From 1a4f98d14f3f1e50c56d3fb5d61003e906992419 Mon Sep 17 00:00:00 2001 From: Matthew C Date: Tue, 3 Sep 2019 22:43:17 -0500 Subject: [PATCH] Cleanup (Implements #116) (#130) PRs #127 #126 and #120 should merge with master to fix jenkins build failing --- .editorconfig | 14 + build.gradle | 184 ++- gradle.properties | 4 +- scripts/update | 2 +- src/main/java/bspkrs/mmv/ClassSrgData.java | 45 +- src/main/java/bspkrs/mmv/CsvData.java | 29 +- src/main/java/bspkrs/mmv/CsvFile.java | 19 +- src/main/java/bspkrs/mmv/ExcData.java | 60 +- src/main/java/bspkrs/mmv/ExcFile.java | 33 +- src/main/java/bspkrs/mmv/FieldSrgData.java | 22 +- src/main/java/bspkrs/mmv/McpBotCommand.java | 5 +- src/main/java/bspkrs/mmv/MemberSrgData.java | 13 +- src/main/java/bspkrs/mmv/MethodSrgData.java | 24 +- src/main/java/bspkrs/mmv/ParamCsvData.java | 23 +- src/main/java/bspkrs/mmv/ParamCsvFile.java | 19 +- .../java/bspkrs/mmv/RemoteZipHandler.java | 85 +- .../bspkrs/mmv/SplittedNaturalComparator.java | 17 +- src/main/java/bspkrs/mmv/SrgFile.java | 73 +- .../java/bspkrs/mmv/StaticMethodsFile.java | 1 + src/main/java/bspkrs/mmv/VersionFetcher.java | 14 +- .../mmv/version/NaturalOrderComparator.java | 5 +- src/main/java/com/matt/forgehax/ForgeHax.java | 48 +- .../com/matt/forgehax/ForgeHaxProperties.java | 30 +- src/main/java/com/matt/forgehax/Globals.java | 5 +- src/main/java/com/matt/forgehax/Helper.java | 177 ++- .../java/com/matt/forgehax/asm/ASMCommon.java | 5 +- .../matt/forgehax/asm/ForgeHaxCoreMod.java | 3 +- .../com/matt/forgehax/asm/ForgeHaxHooks.java | 974 +++++++----- .../forgehax/asm/ForgeHaxTransformer.java | 76 +- .../java/com/matt/forgehax/asm/TypesHook.java | 805 +++++----- .../java/com/matt/forgehax/asm/TypesMc.java | 1288 +++++++-------- .../com/matt/forgehax/asm/TypesSpecial.java | 47 +- .../events/AddCollisionBoxToListEvent.java | 21 +- .../asm/events/AddRenderChunkEvent.java | 5 +- .../events/ApplyClimbableBlockMovement.java | 1 + .../asm/events/ApplyCollisionMotionEvent.java | 3 +- .../events/BlockControllerProcessEvent.java | 1 + .../asm/events/BlockModelRenderEvent.java | 19 +- .../forgehax/asm/events/BlockRenderEvent.java | 7 +- .../forgehax/asm/events/BuildChunkEvent.java | 7 +- .../asm/events/ChunkUploadedEvent.java | 5 +- .../asm/events/ComputeVisibilityEvent.java | 1 + .../asm/events/DeleteGlResourcesEvent.java | 5 +- .../asm/events/DoBlockCollisionsEvent.java | 1 + .../asm/events/DrawBlockBoundingBoxEvent.java | 8 +- .../asm/events/EntityBlockSlipApplyEvent.java | 9 +- .../asm/events/HurtCamEffectEvent.java | 1 + .../asm/events/ItemStoppedUsedEvent.java | 1 + .../events/LeftClickCounterUpdateEvent.java | 1 + .../asm/events/LoadRenderersEvent.java | 5 +- .../LocalPlayerUpdateMovementEvent.java | 7 +- .../matt/forgehax/asm/events/PacketEvent.java | 7 + .../asm/events/PlayerAttackEntityEvent.java | 3 +- .../asm/events/PlayerDamageBlockEvent.java | 3 +- .../asm/events/PlayerSyncItemEvent.java | 1 + .../events/PrePostBlockModelRenderEvent.java | 21 +- .../asm/events/PushOutOfBlocksEvent.java | 4 +- .../asm/events/RenderBlockInLayerEvent.java | 3 +- .../asm/events/RenderBlockLayerEvent.java | 3 + .../forgehax/asm/events/RenderBoatEvent.java | 5 +- .../asm/events/RenderTabNameEvent.java | 5 +- .../asm/events/SchematicaPlaceBlockEvent.java | 4 +- .../asm/events/SetupTerrainEvent.java | 1 + .../asm/events/WaterMovementEvent.java | 1 + .../asm/events/WorldCheckLightForEvent.java | 5 +- .../events/WorldRendererAllocatedEvent.java | 5 +- .../events/WorldRendererDeallocatedEvent.java | 7 +- .../listeners/BlockModelRenderListener.java | 5 +- .../asm/events/listeners/ListenerHook.java | 8 +- .../asm/events/listeners/ListenerObject.java | 5 +- .../asm/events/listeners/Listeners.java | 5 +- .../matt/forgehax/asm/patches/BlockPatch.java | 30 +- .../matt/forgehax/asm/patches/BoatPatch.java | 112 +- .../asm/patches/BufferBuilderPatch.java | 59 +- .../patches/ChunkRenderContainerPatch.java | 15 +- .../patches/ChunkRenderDispatcherPatch.java | 27 +- .../asm/patches/ChunkRenderWorkerPatch.java | 17 +- .../asm/patches/EntityLivingBasePatch.java | 101 +- .../forgehax/asm/patches/EntityPatch.java | 84 +- .../asm/patches/EntityPlayerSPPatch.java | 50 +- .../asm/patches/EntityRendererPatch.java | 13 +- .../forgehax/asm/patches/KeyBindingPatch.java | 17 +- .../forgehax/asm/patches/MinecraftPatch.java | 59 +- .../asm/patches/NetManager$4Patch.java | 21 +- .../forgehax/asm/patches/NetManagerPatch.java | 76 +- .../asm/patches/PlayerControllerMCPatch.java | 13 +- .../asm/patches/PlayerTabOverlayPatch.java | 134 +- .../forgehax/asm/patches/RenderBoatPatch.java | 20 +- .../asm/patches/RenderChunkPatch.java | 72 +- .../asm/patches/RenderGlobalPatch.java | 144 +- .../forgehax/asm/patches/VisGraphPatch.java | 21 +- .../matt/forgehax/asm/patches/WorldPatch.java | 61 +- .../special/SchematicPrinterPatch.java | 16 +- .../asm/reflection/FastReflection.java | 960 +++++------ .../asm/reflection/FastReflectionForge.java | 51 +- .../asm/reflection/FastReflectionSpecial.java | 22 +- .../com/matt/forgehax/asm/test/TestCode.java | 46 - .../matt/forgehax/asm/utils/ASMHelper.java | 134 +- .../forgehax/asm/utils/ASMStackLogger.java | 5 +- .../matt/forgehax/asm/utils/AsmPattern.java | 59 +- .../matt/forgehax/asm/utils/InsnPattern.java | 10 +- .../matt/forgehax/asm/utils/MultiBoolean.java | 9 +- .../forgehax/asm/utils/ReflectionHelper.java | 80 +- .../forgehax/asm/utils/asmtype/ASMClass.java | 9 +- .../asm/utils/asmtype/ASMClassChild.java | 9 +- .../forgehax/asm/utils/asmtype/ASMField.java | 19 +- .../forgehax/asm/utils/asmtype/ASMMethod.java | 64 +- .../forgehax/asm/utils/asmtype/IASMType.java | 23 +- .../utils/asmtype/builders/ASMBuilders.java | 11 +- .../asmtype/builders/ASMClassBuilder.java | 28 +- .../asmtype/builders/ASMFieldBuilder.java | 16 +- .../asmtype/builders/ASMMethodBuilder.java | 24 +- .../asmtype/builders/ParameterBuilder.java | 21 +- .../asm/utils/debug/HookReporter.java | 85 +- .../asm/utils/environment/IStateMapper.java | 15 +- .../asm/utils/environment/RuntimeState.java | 27 +- .../forgehax/asm/utils/environment/State.java | 4 +- .../exception/NoMatchingPatternException.java | 25 - .../asm/utils/fasttype/FastClass.java | 19 +- .../asm/utils/fasttype/FastField.java | 23 +- .../asm/utils/fasttype/FastMethod.java | 19 +- .../forgehax/asm/utils/fasttype/FastType.java | 15 +- .../asm/utils/fasttype/FastTypeBuilder.java | 45 +- .../matt/forgehax/asm/utils/name/IName.java | 11 +- .../forgehax/asm/utils/name/McMultiName.java | 5 +- .../forgehax/asm/utils/name/NameBuilder.java | 12 +- .../forgehax/asm/utils/name/SingleName.java | 5 +- .../asm/utils/remapping/FileDumper.java | 160 +- .../asm/utils/remapping/MCPMappingLoader.java | 61 +- .../remapping/NonObfuscatedStateMapper.java | 11 +- .../remapping/ObfuscatedStateMapper.java | 291 ++-- .../utils/transforming/ClassPatchLoader.java | 30 - .../utils/transforming/ClassTransformer.java | 100 +- .../asm/utils/transforming/Inject.java | 7 +- .../utils/transforming/InjectPriority.java | 4 +- .../utils/transforming/MethodTransformer.java | 60 +- .../transforming/RegisterClassPatch.java | 8 +- .../RegisterMethodTransformer.java | 5 +- .../forgehax/events/ChatMessageEvent.java | 23 +- .../forgehax/events/EntityAddedEvent.java | 1 + .../forgehax/events/EntityRemovedEvent.java | 1 + .../matt/forgehax/events/ForgeHaxEvent.java | 9 +- .../events/LocalPlayerUpdateEvent.java | 1 + .../forgehax/events/PlayerConnectEvent.java | 17 +- .../matt/forgehax/events/Render2DEvent.java | 15 +- .../com/matt/forgehax/events/RenderEvent.java | 21 +- .../forgehax/events/WorldChangeEvent.java | 7 +- .../events/listeners/WorldListener.java | 79 +- .../java/com/matt/forgehax/gui/ClickGui.java | 22 +- .../matt/forgehax/gui/elements/GuiButton.java | 17 +- .../forgehax/gui/elements/GuiElement.java | 26 +- .../matt/forgehax/gui/elements/GuiEnum.java | 4 +- .../forgehax/gui/elements/GuiTextInput.java | 18 +- .../matt/forgehax/gui/elements/GuiToggle.java | 4 +- .../matt/forgehax/gui/windows/GuiWindow.java | 43 +- .../forgehax/gui/windows/GuiWindowMod.java | 138 +- .../gui/windows/GuiWindowSetting.java | 6 +- .../IncompatibleMCVersionException.java | 8 - .../forgehax/mcversion/MCVersionChecker.java | 33 - .../matt/forgehax/mcversion/MCVersions.java | 13 - .../com/matt/forgehax/mods/ActiveModList.java | 154 +- .../java/com/matt/forgehax/mods/Aimbot.java | 394 ++--- .../com/matt/forgehax/mods/AntiAfkMod.java | 414 ++--- .../com/matt/forgehax/mods/AntiBatsMod.java | 55 +- .../matt/forgehax/mods/AntiEffectsMod.java | 19 +- .../com/matt/forgehax/mods/AntiFireMod.java | 32 +- .../com/matt/forgehax/mods/AntiFogMod.java | 5 +- .../forgehax/mods/AntiHeldItemChangeMod.java | 25 +- .../matt/forgehax/mods/AntiHurtCamMod.java | 3 +- .../matt/forgehax/mods/AntiKnockbackMod.java | 267 ++-- .../matt/forgehax/mods/AntiLevitationMod.java | 7 +- .../matt/forgehax/mods/AntiOverlayMod.java | 24 +- .../com/matt/forgehax/mods/AutoArmorMod.java | 10 - .../matt/forgehax/mods/AutoBucketFallMod.java | 126 +- .../matt/forgehax/mods/AutoCrystalMod.java | 177 ++- .../com/matt/forgehax/mods/AutoEatMod.java | 229 +-- .../com/matt/forgehax/mods/AutoElytra.java | 5 +- .../com/matt/forgehax/mods/AutoFishMod.java | 111 +- .../forgehax/mods/AutoHotbarReplenish.java | 304 ++-- .../java/com/matt/forgehax/mods/AutoKey.java | 204 +-- .../java/com/matt/forgehax/mods/AutoLog.java | 64 +- .../java/com/matt/forgehax/mods/AutoMend.java | 63 +- .../java/com/matt/forgehax/mods/AutoMine.java | 51 +- .../com/matt/forgehax/mods/AutoPitch.java | 3 +- .../com/matt/forgehax/mods/AutoPlace.java | 1401 +++++++++-------- .../matt/forgehax/mods/AutoReconnectMod.java | 123 +- .../com/matt/forgehax/mods/AutoReply.java | 51 +- .../matt/forgehax/mods/AutoRespawnMod.java | 33 +- .../com/matt/forgehax/mods/AutoSprintMod.java | 48 +- .../java/com/matt/forgehax/mods/AutoTool.java | 217 +-- .../com/matt/forgehax/mods/AutoTotemMod.java | 45 +- .../com/matt/forgehax/mods/AutoWalkMod.java | 32 +- .../forgehax/mods/BaritoneCompatibility.java | 60 +- .../com/matt/forgehax/mods/BedModeMod.java | 5 +- .../matt/forgehax/mods/BlockHighlightMod.java | 102 +- .../java/com/matt/forgehax/mods/BoatFly.java | 131 +- .../java/com/matt/forgehax/mods/BookBot.java | 529 ++++--- .../java/com/matt/forgehax/mods/ChamsMod.java | 65 +- .../java/com/matt/forgehax/mods/ChatBot.java | 681 ++++---- .../com/matt/forgehax/mods/ChunkLogger.java | 261 +-- .../matt/forgehax/mods/ClientChunkSize.java | 165 +- .../com/matt/forgehax/mods/CompassMod.java | 58 +- .../forgehax/mods/CustomPayloadLogger.java | 45 +- src/main/java/com/matt/forgehax/mods/ESP.java | 410 ++--- .../com/matt/forgehax/mods/ElytraFlight.java | 57 +- .../matt/forgehax/mods/ExtraInventory.java | 389 +++-- .../java/com/matt/forgehax/mods/ExtraTab.java | 9 +- .../java/com/matt/forgehax/mods/FPSLock.java | 102 +- .../com/matt/forgehax/mods/FancyChat.java | 254 +-- .../com/matt/forgehax/mods/FastBreak.java | 6 +- .../com/matt/forgehax/mods/FastPlaceMod.java | 7 +- .../java/com/matt/forgehax/mods/FlyMod.java | 112 +- .../com/matt/forgehax/mods/FreecamMod.java | 128 +- .../com/matt/forgehax/mods/FullBrightMod.java | 11 +- .../java/com/matt/forgehax/mods/GuiMove.java | 20 +- .../com/matt/forgehax/mods/HorseJump.java | 3 +- .../com/matt/forgehax/mods/HorseStats.java | 75 +- .../matt/forgehax/mods/InstantMessage.java | 43 +- .../java/com/matt/forgehax/mods/ItemESP.java | 107 +- .../java/com/matt/forgehax/mods/Jesus.java | 73 +- .../com/matt/forgehax/mods/JoinMessage.java | 272 ++-- .../java/com/matt/forgehax/mods/KillAura.java | 11 +- .../com/matt/forgehax/mods/LogoutSpot.java | 205 +-- .../matt/forgehax/mods/ManualDeleteMod.java | 18 +- .../com/matt/forgehax/mods/MapDownloader.java | 107 +- .../java/com/matt/forgehax/mods/MapMod.java | 189 +-- .../java/com/matt/forgehax/mods/Markers.java | 1203 +++++++------- .../forgehax/mods/MatrixNotifications.java | 294 ++-- .../com/matt/forgehax/mods/NoCaveCulling.java | 5 +- .../com/matt/forgehax/mods/NoFallMod.java | 37 +- .../java/com/matt/forgehax/mods/NoRender.java | 39 +- .../java/com/matt/forgehax/mods/NoRotate.java | 6 +- .../matt/forgehax/mods/NoSkylightUpdates.java | 11 +- .../com/matt/forgehax/mods/NoSlowdown.java | 7 +- .../com/matt/forgehax/mods/NoSoundLagMod.java | 51 +- .../com/matt/forgehax/mods/NoWeather.java | 44 +- .../com/matt/forgehax/mods/NoclipMod.java | 11 +- .../java/com/matt/forgehax/mods/Nuker.java | 314 ++-- .../com/matt/forgehax/mods/PacketLogger.java | 359 +++-- .../matt/forgehax/mods/PayloadSpoofer.java | 27 +- .../com/matt/forgehax/mods/PortalGui.java | 7 +- .../com/matt/forgehax/mods/RiderDesync.java | 221 +-- .../com/matt/forgehax/mods/SafeWalkMod.java | 69 +- .../java/com/matt/forgehax/mods/Scaffold.java | 165 +- .../mods/SchematicaPrinterBypass.java | 19 +- .../com/matt/forgehax/mods/ShulkerViewer.java | 516 +++--- .../com/matt/forgehax/mods/SignTextMod.java | 33 +- .../com/matt/forgehax/mods/SpawnerEspMod.java | 19 +- .../java/com/matt/forgehax/mods/StepMod.java | 127 +- .../matt/forgehax/mods/StopEntityUpdates.java | 11 +- .../com/matt/forgehax/mods/StorageESPMod.java | 79 +- .../java/com/matt/forgehax/mods/TimerMod.java | 109 +- .../java/com/matt/forgehax/mods/Tracers.java | 400 ++--- .../com/matt/forgehax/mods/TrajectoryMod.java | 45 +- .../java/com/matt/forgehax/mods/WaifuESP.java | 115 +- .../java/com/matt/forgehax/mods/XrayMod.java | 62 +- .../com/matt/forgehax/mods/YawLockMod.java | 101 +- .../forgehax/mods/commands/BlocksCommand.java | 97 +- .../forgehax/mods/commands/ClipCommand.java | 154 +- .../forgehax/mods/commands/GuiCommand.java | 33 - .../forgehax/mods/commands/HelpCommand.java | 358 +++-- .../forgehax/mods/commands/MacroCommand.java | 373 ++--- .../forgehax/mods/commands/SayCommand.java | 76 +- .../managers/PositionRotationManager.java | 282 ++-- .../mods/services/BindEventService.java | 29 +- .../mods/services/ChatCommandService.java | 39 +- .../mods/services/ChatIdentifierService.java | 200 +-- .../services/FirstTimeRunningService.java | 10 +- .../forgehax/mods/services/GuiService.java | 13 +- .../mods/services/HotbarSelectionService.java | 74 +- .../LocalPlayerUpdateEventService.java | 9 +- .../mods/services/MainMenuGuiService.java | 92 +- .../services/PacketIgnoreListService.java | 13 +- .../services/PigmenAngerCooldownService.java | 7 +- .../mods/services/RenderEventService.java | 23 +- .../services/ScoreboardListenerService.java | 147 +- .../forgehax/mods/services/SneakService.java | 14 +- .../forgehax/mods/services/SpamService.java | 116 +- .../mods/services/TickRateService.java | 69 +- .../mods/services/WorldEventService.java | 5 +- .../com/matt/forgehax/util/ArrayHelper.java | 5 +- .../com/matt/forgehax/util/BlockHelper.java | 154 +- .../matt/forgehax/util/CaseInsensitive.java | 8 - .../com/matt/forgehax/util/CaseSensitive.java | 10 - .../com/matt/forgehax/util/FileHelper.java | 18 +- .../forgehax/{log => util}/FileManager.java | 61 +- .../com/matt/forgehax/util/ImageUtils.java | 10 +- .../com/matt/forgehax/util/Immutables.java | 41 +- .../com/matt/forgehax/util/MapColors.java | 50 +- .../com/matt/forgehax/util/PacketHelper.java | 22 +- .../com/matt/forgehax/util/SafeConverter.java | 51 +- .../com/matt/forgehax/util/SimpleTimer.java | 16 +- .../com/matt/forgehax/util/Streamables.java | 11 +- .../java/com/matt/forgehax/util/Switch.java | 25 +- .../matt/forgehax/util/TickrateCounter.java | 5 +- .../java/com/matt/forgehax/util/Utils.java | 97 +- .../matt/forgehax/util/blocks/BlockEntry.java | 76 +- .../util/blocks/BlockOptionHelper.java | 92 +- .../BadBlockEntryFormatException.java | 5 +- .../BlockDoesNotExistException.java | 5 +- .../util/blocks/properties/BoundProperty.java | 27 +- .../util/blocks/properties/ColorProperty.java | 25 +- .../blocks/properties/DimensionProperty.java | 22 +- .../blocks/properties/IBlockProperty.java | 5 +- .../blocks/properties/PropertyFactory.java | 17 +- .../util/blocks/properties/TagProperty.java | 10 +- .../blocks/properties/ToggleProperty.java | 25 +- .../util/classloader/AbstractClassLoader.java | 73 +- .../util/classloader/ClassLoaderHelper.java | 291 ++-- .../util/classloader/CustomClassLoaders.java | 10 +- .../com/matt/forgehax/util/color/Color.java | 100 +- .../com/matt/forgehax/util/color/Color4F.java | 22 +- .../matt/forgehax/util/color/ColorBuffer.java | 9 +- .../com/matt/forgehax/util/color/Colors.java | 5 +- .../util/command/BaseCommandBuilder.java | 59 +- .../forgehax/util/command/CallbackType.java | 4 +- .../matt/forgehax/util/command/Command.java | 268 ++-- .../forgehax/util/command/CommandBuilder.java | 5 +- .../util/command/CommandBuilders.java | 25 +- .../forgehax/util/command/CommandGlobal.java | 33 +- .../forgehax/util/command/CommandHelper.java | 25 +- .../forgehax/util/command/CommandStub.java | 103 +- .../forgehax/util/command/ExecuteData.java | 99 +- .../matt/forgehax/util/command/Options.java | 77 +- .../forgehax/util/command/OptionsBuilder.java | 13 +- .../matt/forgehax/util/command/Setting.java | 125 +- .../forgehax/util/command/SettingBuilder.java | 27 +- .../util/command/SettingEnumBuilder.java | 116 +- .../forgehax/util/command/StubBuilder.java | 17 +- .../util/command/callbacks/CallbackData.java | 9 +- .../callbacks/CancelableCallbackData.java | 13 +- .../command/callbacks/OnChangeCallback.java | 11 +- .../exception/CommandBuildException.java | 5 +- .../exception/CommandExecuteException.java | 30 +- .../CommandParentNonNullException.java | 5 +- .../exception/MissingEntryException.java | 5 +- .../util/command/flags/ICommandFlag.java | 8 +- .../command/options/BlockEntryProcessor.java | 77 +- .../util/command/options/OptionBuilders.java | 21 +- .../command/options/OptionProcessors.java | 32 +- .../forgehax/util/command/v2/AbstractCmd.java | 230 --- .../util/command/v2/AbstractCmdBuilder.java | 148 -- .../forgehax/util/command/v2/CmdBuilders.java | 25 - .../forgehax/util/command/v2/CmdHelper.java | 89 -- .../matt/forgehax/util/command/v2/ICmd.java | 216 --- .../util/command/v2/IHelpTextFormatter.java | 6 - .../forgehax/util/command/v2/IParentCmd.java | 18 - .../forgehax/util/command/v2/ParentCmd.java | 175 -- .../util/command/v2/ParentCmdBuilder.java | 15 - .../matt/forgehax/util/command/v2/Parser.java | 160 -- .../util/command/v2/argument/ArgBuilder.java | 106 -- .../util/command/v2/argument/ArgHelper.java | 38 - .../util/command/v2/argument/ArgMap.java | 113 -- .../util/command/v2/argument/BaseArg.java | 109 -- .../util/command/v2/argument/BaseOption.java | 107 -- .../util/command/v2/argument/IArg.java | 42 - .../util/command/v2/argument/IOption.java | 72 - .../command/v2/argument/OptionBuilder.java | 55 - .../util/command/v2/argument/OptionMap.java | 123 -- .../util/command/v2/argument/ValueMap.java | 97 -- .../command/v2/callback/CmdCallbacks.java | 3 - .../command/v2/callback/ICmdCallback.java | 4 - .../v2/converter/AbstractConverter.java | 43 - .../command/v2/converter/BaseConverter.java | 110 -- .../v2/converter/ConverterFactory.java | 13 - .../util/command/v2/converter/Converters.java | 58 - .../v2/converter/DefaultConverters.java | 444 ------ .../util/command/v2/converter/IConverter.java | 179 --- .../command/v2/converter/StringConverter.java | 30 - .../command/v2/converter/ValueConverter.java | 46 - .../command/v2/converter/ValuesConverter.java | 26 - .../exceptions/StringConversionException.java | 19 - .../exceptions/ValueParseException.java | 19 - .../v2/exception/BaseCmdException.java | 21 - .../v2/exception/CmdAmbiguousException.java | 24 - .../command/v2/exception/CmdException.java | 26 - .../command/v2/exception/CmdExceptions.java | 23 - .../CmdMissingArgumentException.java | 17 - .../v2/exception/CmdRuntimeException.java | 51 - .../v2/exception/CmdUnknownException.java | 16 - .../util/command/v2/flag/CmdFlags.java | 57 - .../util/command/v2/flag/DefaultCmdFlags.java | 11 - .../util/command/v2/flag/ICmdFlag.java | 4 - .../v2/serializers/CmdChildrenSerializer.java | 50 - .../v2/serializers/CmdFlagSerializer.java | 52 - .../v2/serializers/ICmdSerializer.java | 6 - .../v2/templates/ConverterBuilder.java | 31 - .../matt/forgehax/util/common/Priority.java | 5 +- .../forgehax/util/common/PriorityEnum.java | 4 +- .../matt/forgehax/util/console/ConsoleIO.java | 12 +- .../forgehax/util/console/ConsoleWriter.java | 9 +- .../com/matt/forgehax/util/draw/Fonts.java | 14 - .../matt/forgehax/util/draw/RenderUtils.java | 85 +- .../forgehax/util/draw/SurfaceBuilder.java | 368 +++-- .../forgehax/util/draw/SurfaceHelper.java | 326 ++-- .../matt/forgehax/util/draw/font}/CFont.java | 129 +- .../matt/forgehax/util/draw/font/Fonts.java | 16 + .../draw/font}/MinecraftFontRenderer.java | 192 +-- .../util/entity/EnchantmentUtils.java | 39 +- .../forgehax/util/entity/EntityUtils.java | 238 +-- .../util/entity/LocalPlayerInventory.java | 208 +-- .../util/entity/LocalPlayerUtils.java | 119 +- .../matt/forgehax/util/entity/PlayerInfo.java | 140 +- .../util/entity/PlayerInfoHelper.java | 131 +- .../forgehax/util/entity/PlayerUtils.java | 5 +- .../util/entity/mobtypes/EndermanMob.java | 5 +- .../util/entity/mobtypes/FriendlyMob.java | 15 +- .../util/entity/mobtypes/HostileMob.java | 5 +- .../util/entity/mobtypes/MobType.java | 15 +- .../util/entity/mobtypes/MobTypeEnum.java | 34 +- .../util/entity/mobtypes/MobTypeRegistry.java | 5 +- .../util/entity/mobtypes/PigZombieMob.java | 5 +- .../util/entity/mobtypes/WolfMob.java | 5 +- .../matt/forgehax/util/entry/ClassEntry.java | 38 +- .../util/entry/CustomMessageEntry.java | 26 +- .../matt/forgehax/util/entry/FacingEntry.java | 19 +- .../forgehax/util/filter/FilterElement.java | 16 - .../forgehax/util/filter/FilterEntry.java | 132 -- .../forgehax/util/filter/FilterFactory.java | 28 - .../com/matt/forgehax/util/gui/GuiHelper.java | 28 - .../com/matt/forgehax/util/gui/IGuiBase.java | 244 --- .../matt/forgehax/util/gui/IGuiButton.java | 22 - .../matt/forgehax/util/gui/IGuiCheckbox.java | 18 - .../com/matt/forgehax/util/gui/IGuiLabel.java | 8 - .../com/matt/forgehax/util/gui/IGuiPanel.java | 28 - .../matt/forgehax/util/gui/IGuiParent.java | 25 - .../matt/forgehax/util/gui/IGuiWindow.java | 24 - .../util/gui/callbacks/CallbackList.java | 28 - .../util/gui/callbacks/GuiCallbacks.java | 40 - .../util/gui/callbacks/IGuiCallbackBase.java | 4 - .../callbacks/IGuiCallbackButtonPressed.java | 6 - .../IGuiCallbackCheckboxStateChanged.java | 6 - .../gui/callbacks/IGuiCallbackChildEvent.java | 10 - .../gui/callbacks/IGuiCallbackClicked.java | 8 - .../util/gui/callbacks/IGuiCallbackFocus.java | 6 - .../IGuiCallbackMouseHoverState.java | 6 - .../gui/callbacks/IGuiCallbackVisibility.java | 6 - .../forgehax/util/gui/events/GuiKeyEvent.java | 68 - .../util/gui/events/GuiMouseEvent.java | 97 -- .../util/gui/events/GuiRenderEvent.java | 50 - .../util/gui/events/GuiUpdateEvent.java | 20 - .../forgehax/util/gui/mc/GuiParentScreen.java | 13 - .../util/gui/mc/MinecraftGuiProxy.java | 217 --- .../util/gui/mcgui/ImmutableGuiBase.java | 155 -- .../matt/forgehax/util/gui/mcgui/MBase.java | 274 ---- .../matt/forgehax/util/gui/mcgui/MButton.java | 120 -- .../forgehax/util/gui/mcgui/MCheckbox.java | 162 -- .../matt/forgehax/util/gui/mcgui/MLabel.java | 60 - .../matt/forgehax/util/gui/mcgui/MPanel.java | 117 -- .../matt/forgehax/util/gui/mcgui/MParent.java | 153 -- .../matt/forgehax/util/gui/mcgui/MWindow.java | 251 --- .../forgehax/util/gui/test/GuiTestMain.java | 73 - .../matt/forgehax/util/key/BindingHelper.java | 41 +- .../com/matt/forgehax/util/key/Bindings.java | 40 +- .../com/matt/forgehax/util/key/IKeyBind.java | 13 +- .../forgehax/util/key/KeyBindingHandler.java | 63 +- .../util/markers/MarkersRenderGlobal.java | 150 +- .../forgehax/util/markers/RenderUploader.java | 77 +- .../util/markers/TessellatorCache.java | 31 +- .../matt/forgehax/util/markers/Uploaders.java | 52 +- .../com/matt/forgehax/util/math/Angle.java | 175 +- .../matt/forgehax/util/math/AngleHelper.java | 49 +- .../com/matt/forgehax/util/math/Plane.java | 5 +- .../matt/forgehax/util/math/VectorUtils.java | 70 +- .../com/matt/forgehax/util/mod/BaseMod.java | 212 ++- .../com/matt/forgehax/util/mod/Category.java | 12 +- .../matt/forgehax/util/mod/CommandMod.java | 25 +- .../matt/forgehax/util/mod/ServiceMod.java | 41 +- .../com/matt/forgehax/util/mod/ToggleMod.java | 92 +- .../forgehax/util/mod/loader/ModManager.java | 104 +- .../forgehax/util/mod/loader/RegisterMod.java | 8 +- .../forgehax/util/projectile/IProjectile.java | 19 +- .../forgehax/util/projectile/Projectile.java | 214 +-- .../util/projectile/SimulationResult.java | 9 +- .../util/serialization/GsonConstant.java | 5 +- .../serialization/ISerializableImmutable.java | 1 + .../util/serialization/ISerializableJson.java | 9 +- .../serialization/ISerializableMutable.java | 1 + .../util/serialization/ISerializer.java | 7 +- .../util/serialization/Serializers.java | 27 +- .../matt/forgehax/util/spam/SpamEntry.java | 129 +- .../matt/forgehax/util/spam/SpamMessage.java | 15 +- .../matt/forgehax/util/spam/SpamTokens.java | 35 +- .../matt/forgehax/util/spam/SpamTrigger.java | 30 +- .../com/matt/forgehax/util/spam/SpamType.java | 14 +- .../com/matt/forgehax/util/task/IProcess.java | 6 +- .../util/task/SimpleManagerContainer.java | 131 +- .../com/matt/forgehax/util/task/Task.java | 91 -- .../matt/forgehax/util/task/TaskChain.java | 54 +- .../matt/forgehax/util/task/TaskManager.java | 31 - .../util/tesselation}/GeometryMasks.java | 29 +- .../tesselation}/GeometryTessellator.java | 199 +-- .../util/typeconverter/TypeConverter.java | 27 +- .../typeconverter/TypeConverterRegistry.java | 46 +- .../util/typeconverter/TypeConverters.java | 15 +- .../util/typeconverter/types/BooleanType.java | 5 +- .../util/typeconverter/types/ByteType.java | 5 +- .../typeconverter/types/CharacterType.java | 5 +- .../util/typeconverter/types/DoubleType.java | 5 +- .../util/typeconverter/types/FloatType.java | 5 +- .../util/typeconverter/types/IntegerType.java | 5 +- .../util/typeconverter/types/LongType.java | 5 +- .../util/typeconverter/types/ShortType.java | 5 +- .../util/typeconverter/types/StringType.java | 5 +- .../minecraft/textures/forgehax/waifu1.png | Bin 1303255 -> 0 bytes src/main/resources/mcmod.info | 2 +- 506 files changed, 17354 insertions(+), 20592 deletions(-) create mode 100644 .editorconfig delete mode 100644 src/main/java/com/matt/forgehax/asm/test/TestCode.java delete mode 100644 src/main/java/com/matt/forgehax/asm/utils/exception/NoMatchingPatternException.java delete mode 100644 src/main/java/com/matt/forgehax/asm/utils/transforming/ClassPatchLoader.java delete mode 100644 src/main/java/com/matt/forgehax/mcversion/IncompatibleMCVersionException.java delete mode 100644 src/main/java/com/matt/forgehax/mcversion/MCVersionChecker.java delete mode 100644 src/main/java/com/matt/forgehax/mcversion/MCVersions.java delete mode 100644 src/main/java/com/matt/forgehax/mods/AutoArmorMod.java delete mode 100644 src/main/java/com/matt/forgehax/mods/commands/GuiCommand.java delete mode 100644 src/main/java/com/matt/forgehax/util/CaseInsensitive.java delete mode 100644 src/main/java/com/matt/forgehax/util/CaseSensitive.java rename src/main/java/com/matt/forgehax/{log => util}/FileManager.java (79%) delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/AbstractCmd.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/AbstractCmdBuilder.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/CmdBuilders.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/CmdHelper.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/ICmd.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/IHelpTextFormatter.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/IParentCmd.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/ParentCmd.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/ParentCmdBuilder.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/Parser.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/ArgBuilder.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/ArgHelper.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/ArgMap.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/BaseArg.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/BaseOption.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/IArg.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/IOption.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/OptionBuilder.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/OptionMap.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/argument/ValueMap.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/callback/CmdCallbacks.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/callback/ICmdCallback.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/AbstractConverter.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/BaseConverter.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/ConverterFactory.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/Converters.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/DefaultConverters.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/IConverter.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/StringConverter.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/ValueConverter.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/ValuesConverter.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/exceptions/StringConversionException.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/converter/exceptions/ValueParseException.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/exception/BaseCmdException.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/exception/CmdAmbiguousException.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/exception/CmdException.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/exception/CmdExceptions.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/exception/CmdMissingArgumentException.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/exception/CmdRuntimeException.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/exception/CmdUnknownException.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/flag/CmdFlags.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/flag/DefaultCmdFlags.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/flag/ICmdFlag.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/serializers/CmdChildrenSerializer.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/serializers/CmdFlagSerializer.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/serializers/ICmdSerializer.java delete mode 100644 src/main/java/com/matt/forgehax/util/command/v2/templates/ConverterBuilder.java delete mode 100644 src/main/java/com/matt/forgehax/util/draw/Fonts.java rename src/main/java/{uk/co/hexeption/thx/ttf => com/matt/forgehax/util/draw/font}/CFont.java (79%) create mode 100644 src/main/java/com/matt/forgehax/util/draw/font/Fonts.java rename src/main/java/{uk/co/hexeption/thx/ttf => com/matt/forgehax/util/draw/font}/MinecraftFontRenderer.java (85%) delete mode 100644 src/main/java/com/matt/forgehax/util/filter/FilterElement.java delete mode 100644 src/main/java/com/matt/forgehax/util/filter/FilterEntry.java delete mode 100644 src/main/java/com/matt/forgehax/util/filter/FilterFactory.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/GuiHelper.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/IGuiBase.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/IGuiButton.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/IGuiCheckbox.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/IGuiLabel.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/IGuiPanel.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/IGuiParent.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/IGuiWindow.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/CallbackList.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/GuiCallbacks.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackBase.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackButtonPressed.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackCheckboxStateChanged.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackChildEvent.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackClicked.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackFocus.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackMouseHoverState.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackVisibility.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/events/GuiKeyEvent.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/events/GuiMouseEvent.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/events/GuiRenderEvent.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/events/GuiUpdateEvent.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mc/GuiParentScreen.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mc/MinecraftGuiProxy.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mcgui/ImmutableGuiBase.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mcgui/MBase.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mcgui/MButton.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mcgui/MCheckbox.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mcgui/MLabel.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mcgui/MPanel.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mcgui/MParent.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/mcgui/MWindow.java delete mode 100644 src/main/java/com/matt/forgehax/util/gui/test/GuiTestMain.java delete mode 100644 src/main/java/com/matt/forgehax/util/task/Task.java delete mode 100644 src/main/java/com/matt/forgehax/util/task/TaskManager.java rename src/main/java/com/{github/lunatrius/core/client/renderer/unique => matt/forgehax/util/tesselation}/GeometryMasks.java (86%) rename src/main/java/com/{github/lunatrius/core/client/renderer/unique => matt/forgehax/util/tesselation}/GeometryTessellator.java (83%) delete mode 100644 src/main/resources/assets/minecraft/textures/forgehax/waifu1.png diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..398b5b743 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +[{*.java,*.gradle,*.properties}] +indent_style = space +indent_size = 2 + +[*.info] +indent_style = tab diff --git a/build.gradle b/build.gradle index 35456a61b..db74a02f2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,23 @@ import org.apache.tools.ant.filters.ReplaceTokens -apply plugin: 'java' - buildscript { - repositories { - jcenter() - maven { url = "http://files.minecraftforge.net/maven" } - maven { url "https://plugins.gradle.org/m2/" } - } - dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' - classpath "com.diffplug.spotless:spotless-plugin-gradle:3.15.0" - } + repositories { + jcenter() + maven { url "http://files.minecraftforge.net/maven" } + maven { url "https://plugins.gradle.org/m2/" } + } + dependencies { + classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' + } } repositories { - mavenCentral() - - maven { url 'https://oss.sonatype.org/content/groups/public/' } + mavenCentral() + maven { url "https://oss.sonatype.org/content/groups/public/" } } +apply plugin: 'java' +apply plugin: 'idea' apply plugin: 'net.minecraftforge.gradle.forge' sourceCompatibility = targetCompatibility = '1.8' @@ -30,111 +28,105 @@ version project.property('forgehax.version') archivesBaseName = "forgehax-" + project.property('forgehax.mc.version') configurations.all { - resolutionStrategy.cacheChangingModulesFor 0, 'seconds' + resolutionStrategy.cacheChangingModulesFor 0, 'seconds' } minecraft { - version = project.property('forgehax.forge.version') - runDir = "run" + version = project.property('forgehax.forge.version') + runDir = "run" - // channel_mapping - mappings = project.property('forgehax.mcp.channel') + '_' + project.property('forgehax.mcp.mapping') + // channel_mapping + mappings = "${project.property('forgehax.mcp.channel')}_${project.property('forgehax.mcp.mapping')}" } dependencies { - testCompile group: 'junit', name: 'junit', version: '4.12' - testCompile group: 'org.mockito', name: 'mockito-core', version: '2.15.0' + testCompile group: 'junit', name: 'junit', version: '4.12' + testCompile group: 'org.mockito', name: 'mockito-core', version: '2.15.0' } jar { - manifest { - attributes ( - 'FMLCorePlugin': 'com.matt.forgehax.asm.ForgeHaxCoreMod', - 'FMLCorePluginContainsFMLMod': 'true' - ) - } - exclude ('assets/minecraft/textures/forgehax/*') + manifest { + attributes( + 'FMLCorePlugin': 'com.matt.forgehax.asm.ForgeHaxCoreMod', + 'FMLCorePluginContainsFMLMod': 'true' + ) + } } -processResources -{ - // this will ensure that this task is redone when the versions change. - inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version - - // replace stuff in mcmod.info, nothing else - from(sourceSets.main.resources.srcDirs) { - include 'mcmod.info' - - // replace version and mcversion - expand 'version':project.version, 'mcversion':project.minecraft.version - } - - // copy everything else, thats not the mcmod.info - from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' - } - - - // TODO: Filter images out properly - //filesNotMatching("**/*.png") { - it.filter ReplaceTokens, tokens: [ - "forgehax.version" : project.property("forgehax.version"), - "forgehax.mc.version" : project.property("forgehax.mc.version"), - "forgehax.forge.version": project.property("forgehax.forge.version"), - "forgehax.mcp.version" : project.property("forgehax.mcp.version"), - "forgehax.mcp.channel" : project.property("forgehax.mcp.channel"), - "forgehax.mcp.mapping" : project.property("forgehax.mcp.mapping") - ] - //} +processResources { + // this will ensure that this task is redone when the versions change. + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + // replace stuff in mcmod.info, nothing else + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + // replace version and mcversion + expand 'version': project.version, 'mcversion': project.minecraft.version + } + + // copy everything else, thats not the mcmod.info + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } + + filesMatching('**/*.properties') { + it.filter ReplaceTokens, tokens: [ + "forgehax.version" : project.property("forgehax.version"), + "forgehax.mc.version" : project.property("forgehax.mc.version"), + "forgehax.forge.version": project.property("forgehax.forge.version"), + "forgehax.mcp.version" : project.property("forgehax.mcp.version"), + "forgehax.mcp.channel" : project.property("forgehax.mcp.channel"), + "forgehax.mcp.mapping" : project.property("forgehax.mcp.mapping") + ] + } } task setGameDir() { - // Check if custom gamedir has been passed, if not use default ones per platform - if(!project.hasProperty("gameDir")) { - if(org.gradle.internal.os.OperatingSystem.current().isWindows()) { - project.ext.gameDir = System.getenv("APPDATA") + "/.minecraft" - } else if(org.gradle.internal.os.OperatingSystem.current().isMacOsX()) { - project.ext.gameDir = System.properties["user.home"] + "/Library/Application Support/minecraft" - } else { - project.ext.gameDir = System.properties["user.home"] + "/.minecraft" - } + // Check if custom gamedir has been passed, if not use default ones per platform + if (!project.hasProperty("gameDir")) { + if (org.gradle.internal.os.OperatingSystem.current().isWindows()) { + project.ext.gameDir = System.getenv("APPDATA") + "/.minecraft" + } else if (org.gradle.internal.os.OperatingSystem.current().isMacOsX()) { + project.ext.gameDir = System.properties["user.home"] + "/Library/Application Support/minecraft" + } else { + project.ext.gameDir = System.properties["user.home"] + "/.minecraft" } + } } task copyJar(type: Copy, dependsOn: [setGameDir]) { - def gameDirectory = "$gameDir/mods/" + minecraft.version - - // find previous jar (if it exists) - def previousJars = fileTree(dir: gameDirectory).matching { - include archivesBaseName + '*' - }.files - - // change file name - if(previousJars) { - // create .backups folder - def backupDir = gameDirectory + '/.backups/' - file(backupDir).mkdirs() - - for(File previousJar : previousJars) { - def n = gameDirectory + '/.backups/' + previousJar.getName() + '.bk' - def f = file(n) - def i = 1 - while(f.exists()) { - f = file(n + '_' + i) - i++ - } - previousJar.renameTo(f) - } + def gameDirectory = "$gameDir/mods/" + minecraft.version + + // find previous jar (if it exists) + def previousJars = fileTree(dir: gameDirectory).matching { + include archivesBaseName + '*' + }.files + + // change file name + if (previousJars) { + // create .backups folder + def backupDir = gameDirectory + '/.backups/' + file(backupDir).mkdirs() + + for (File previousJar : previousJars) { + def n = gameDirectory + '/.backups/' + previousJar.getName() + '.bk' + def f = file(n) + def i = 1 + while (f.exists()) { + f = file(n + '_' + i) + i++ + } + previousJar.renameTo(f) } + } - // copy forgehax jar from libs to forge mod folder - from jar - into "$gameDir/mods/" + minecraft.version + // copy forgehax jar from libs to forge mod folder + from jar + into "$gameDir/mods/" + minecraft.version } -task publishToMavenLocal() {} // dummy - build.finalizedBy copyJar diff --git a/gradle.properties b/gradle.properties index 734fac0c8..6c08a02cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ forgehax.version=2.9.0 forgehax.mc.version=1.12.2 -forgehax.forge.version=1.12.2-14.23.5.2775 +forgehax.forge.version=1.12.2-14.23.5.2846 forgehax.mcp.version=1.12 forgehax.mcp.channel=snapshot -forgehax.mcp.mapping=20171003 \ No newline at end of file +forgehax.mcp.mapping=20171003 diff --git a/scripts/update b/scripts/update index 80292dae2..6d9480c2e 100755 --- a/scripts/update +++ b/scripts/update @@ -26,6 +26,6 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then docker-compose \ -f docker-compose.ci.yml \ run --rm \ - forgehax setupDecompWorkspace --stacktrace + forgehax setupDecompWorkspace --stacktrace --refresh-dependencies fi fi diff --git a/src/main/java/bspkrs/mmv/ClassSrgData.java b/src/main/java/bspkrs/mmv/ClassSrgData.java index 34c9445a3..0df467084 100644 --- a/src/main/java/bspkrs/mmv/ClassSrgData.java +++ b/src/main/java/bspkrs/mmv/ClassSrgData.java @@ -27,61 +27,70 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of */ public class ClassSrgData implements Comparable { + public static enum SortType { PKG, OBF } - + private final String obfName; private final String srgName; private String srgPkgName; private final boolean isClientOnly; - + public static SortType sortType = SortType.PKG; - + public ClassSrgData(String obfName, String srgName, String srgPkgName, boolean isClientOnly) { this.obfName = obfName; this.srgName = srgName; this.srgPkgName = srgPkgName; this.isClientOnly = isClientOnly; } - + public String getObfName() { return this.obfName; } - + public String getSrgName() { return this.srgName; } - + public String getSrgPkgName() { return this.srgPkgName; } - + public ClassSrgData setSrgPkgName(String pkg) { this.srgPkgName = pkg; return this; } - + public boolean isClientOnly() { return isClientOnly; } - + public String getFullyQualifiedSrgName() { return srgPkgName + "/" + srgName; } - + @Override public int compareTo(ClassSrgData o) { - if (sortType == SortType.PKG) - if (o != null) return getFullyQualifiedSrgName().compareTo(o.getFullyQualifiedSrgName()); - else return 1; - else if (o != null) - if (obfName.length() != o.obfName.length()) return obfName.length() - o.obfName.length(); - else return obfName.compareTo(o.obfName); - else return 1; + if (sortType == SortType.PKG) { + if (o != null) { + return getFullyQualifiedSrgName().compareTo(o.getFullyQualifiedSrgName()); + } else { + return 1; + } + } else if (o != null) { + if (obfName.length() != o.obfName.length()) { + return obfName.length() - o.obfName.length(); + } else { + return obfName.compareTo(o.obfName); + } + } else { + return 1; + } } - + public boolean contains(String s) { return srgName.contains(s) || obfName.contains(s) || this.srgPkgName.contains(s); } diff --git a/src/main/java/bspkrs/mmv/CsvData.java b/src/main/java/bspkrs/mmv/CsvData.java index add65972c..9a3456a88 100644 --- a/src/main/java/bspkrs/mmv/CsvData.java +++ b/src/main/java/bspkrs/mmv/CsvData.java @@ -27,6 +27,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of */ public class CsvData implements Comparable { + private final String srgName; private String mcpName; private final int side; @@ -39,13 +40,15 @@ public CsvData(String srgName, String mcpName, int side, String comment) { this.side = side; if (comment.contains(",") - || (!comment.isEmpty() - && comment.charAt(0) == '"' - && comment.charAt(comment.length() - 1) == '"')) { + || (!comment.isEmpty() + && comment.charAt(0) == '"' + && comment.charAt(comment.length() - 1) == '"')) { needsQuoted = true; - if (comment.charAt(0) == '"' && comment.charAt(comment.length() - 1) == '"') + if (comment.charAt(0) == '"' && comment.charAt(comment.length() - 1) == '"') { this.comment = comment.substring(1, comment.length() - 1); - else this.comment = comment; + } else { + this.comment = comment; + } } else { this.comment = comment; needsQuoted = false; @@ -54,12 +57,12 @@ public CsvData(String srgName, String mcpName, int side, String comment) { public String toCsv() { return srgName - + "," - + mcpName - + "," - + side - + "," - + (needsQuoted ? "\"" + comment + "\"" : comment); + + "," + + mcpName + + "," + + side + + "," + + (needsQuoted ? "\"" + comment + "\"" : comment); } public String getSrgName() { @@ -90,7 +93,9 @@ public CsvData setComment(String comment) { @Override public int compareTo(CsvData o) { - if (o != null) return this.srgName.compareTo(o.srgName); + if (o != null) { + return this.srgName.compareTo(o.srgName); + } return 1; } diff --git a/src/main/java/bspkrs/mmv/CsvFile.java b/src/main/java/bspkrs/mmv/CsvFile.java index 0080190f9..c4f91f7a0 100644 --- a/src/main/java/bspkrs/mmv/CsvFile.java +++ b/src/main/java/bspkrs/mmv/CsvFile.java @@ -40,6 +40,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.TreeMap; public class CsvFile { + private final File file; private final Map srgMemberName2CsvData; private boolean isDirty; @@ -63,7 +64,7 @@ public void readFromFile() throws IOException { String side = in.next(); String comment = in.nextLine().substring(1); srgMemberName2CsvData.put( - srgName, new CsvData(srgName, mcpName, Integer.valueOf(side), comment)); + srgName, new CsvData(srgName, mcpName, Integer.valueOf(side), comment)); } } finally { in.close(); @@ -74,11 +75,11 @@ public void writeToFile() throws IOException { if (isDirty) { if (file.exists()) { File fileBak = - new File( - file.getAbsolutePath() - + "_" - + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) - + ".bak"); + new File( + file.getAbsolutePath() + + "_" + + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + + ".bak"); file.renameTo(fileBak); } @@ -86,8 +87,10 @@ public void writeToFile() throws IOException { PrintWriter out = new PrintWriter(new FileWriter(file)); out.println(headerLine); - - for (CsvData data : srgMemberName2CsvData.values()) out.println(data.toCsv()); + + for (CsvData data : srgMemberName2CsvData.values()) { + out.println(data.toCsv()); + } out.close(); diff --git a/src/main/java/bspkrs/mmv/ExcData.java b/src/main/java/bspkrs/mmv/ExcData.java index e5441dbb9..8f81c33c5 100644 --- a/src/main/java/bspkrs/mmv/ExcData.java +++ b/src/main/java/bspkrs/mmv/ExcData.java @@ -32,6 +32,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.regex.Pattern; public class ExcData implements Comparable { + private final String srgOwner; private final String srgName; private final String descriptor; @@ -40,11 +41,11 @@ public class ExcData implements Comparable { private final String[] paramTypes; public ExcData( - String srgOwner, - String srgName, - String descriptor, - String[] exceptions, - String[] parameters) { + String srgOwner, + String srgName, + String descriptor, + String[] exceptions, + String[] parameters) { this.srgOwner = srgOwner; this.srgName = srgName; this.descriptor = descriptor; @@ -54,7 +55,7 @@ public ExcData( } public ExcData( - String srgOwner, String srgName, String descriptor, String[] exceptions, boolean isStatic) { + String srgOwner, String srgName, String descriptor, String[] exceptions, boolean isStatic) { this.srgOwner = srgOwner; this.srgName = srgName; this.descriptor = descriptor; @@ -88,8 +89,15 @@ public String[] getParamTypes() { } public boolean contains(String s) { - if (srgName.contains(s)) return true; - else for (String param : parameters) if (param.contains(s)) return true; + if (srgName.contains(s)) { + return true; + } else { + for (String param : parameters) { + if (param.contains(s)) { + return true; + } + } + } return false; } @@ -128,19 +136,23 @@ public static String[] splitMethodDesc(String desc) { public static String[] genParamNames(String srgId, String[] paramTypes, boolean isStatic) { boolean skip2 = - (paramTypes.length >= 4) - && paramTypes[0].equals("Ljava/lang/String;") - && paramTypes[1].equals('I') - && paramTypes[0].equals(paramTypes[2]) - && paramTypes[1].equals(paramTypes[3]); + (paramTypes.length >= 4) + && paramTypes[0].equals("Ljava/lang/String;") + && paramTypes[1].equals('I') + && paramTypes[0].equals(paramTypes[2]) + && paramTypes[1].equals(paramTypes[3]); String[] ret = new String[paramTypes.length]; int idOffset = isStatic ? 0 : 1; - if (skip2) idOffset += 2; + if (skip2) { + idOffset += 2; + } for (int i = 0; i < paramTypes.length; i++) { ret[i] = "p_" + srgId + "_" + (i + idOffset) + "_"; - if (paramTypes[i].equals("D") || paramTypes[i].equals("J")) idOffset++; + if (paramTypes[i].equals("D") || paramTypes[i].equals("J")) { + idOffset++; + } } return ret; @@ -149,19 +161,21 @@ public static String[] genParamNames(String srgId, String[] paramTypes, boolean public static String getSrgId(String srgName) { Pattern pattern = Pattern.compile("func_(i?[0-9]+)_"); Matcher matcher = pattern.matcher(srgName); - if (matcher.find()) return matcher.group(1); + if (matcher.find()) { + return matcher.group(1); + } return srgName; } @Override public String toString() { return String.format( - " Owner: %s\n SRG Name: %s\n Descriptor: %s\n Exceptions: %s\n Parameters: %s\n Param Types: %s", - srgOwner, - srgName, - descriptor, - Arrays.toString(exceptions), - Arrays.toString(parameters), - Arrays.toString(paramTypes)); + " Owner: %s\n SRG Name: %s\n Descriptor: %s\n Exceptions: %s\n Parameters: %s\n Param Types: %s", + srgOwner, + srgName, + descriptor, + Arrays.toString(exceptions), + Arrays.toString(parameters), + Arrays.toString(paramTypes)); } } diff --git a/src/main/java/bspkrs/mmv/ExcFile.java b/src/main/java/bspkrs/mmv/ExcFile.java index 2d0872393..65dcc569b 100644 --- a/src/main/java/bspkrs/mmv/ExcFile.java +++ b/src/main/java/bspkrs/mmv/ExcFile.java @@ -35,6 +35,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.Scanner; public class ExcFile { + public final Map srgMethodName2ExcData; public final Map srgParamName2ExcData; @@ -59,10 +60,14 @@ public ExcFile(File f) throws IOException { in.useDelimiter("\\."); String srgOwner = in.next(); in.useDelimiter("\\("); - - if (!in.hasNext()) - if (in.hasNextLine()) in.nextLine(); - else break; + + if (!in.hasNext()) { + if (in.hasNextLine()) { + in.nextLine(); + } else { + break; + } + } String srgName = in.next().substring(1); in.useDelimiter("="); @@ -72,20 +77,22 @@ public ExcFile(File f) throws IOException { String params = in.nextLine().substring(1); ExcData toAdd = - new ExcData( - srgOwner, - srgName, - descriptor, - (excs.length() > 0 ? excs.split(",") : new String[0]), - (params.length() > 0 ? params.split(",") : new String[0])); + new ExcData( + srgOwner, + srgName, + descriptor, + (excs.length() > 0 ? excs.split(",") : new String[0]), + (params.length() > 0 ? params.split(",") : new String[0])); ExcData existing = srgMethodName2ExcData.get(srgName); if ((existing == null) - || (existing.getParameters().length < toAdd.getParameters().length)) { + || (existing.getParameters().length < toAdd.getParameters().length)) { srgMethodName2ExcData.put(srgName, toAdd); - - for (String parameter : toAdd.getParameters()) srgParamName2ExcData.put(parameter, toAdd); + + for (String parameter : toAdd.getParameters()) { + srgParamName2ExcData.put(parameter, toAdd); + } } } } finally { diff --git a/src/main/java/bspkrs/mmv/FieldSrgData.java b/src/main/java/bspkrs/mmv/FieldSrgData.java index 734af79a4..20364c533 100644 --- a/src/main/java/bspkrs/mmv/FieldSrgData.java +++ b/src/main/java/bspkrs/mmv/FieldSrgData.java @@ -27,19 +27,23 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of */ public class FieldSrgData extends MemberSrgData implements Comparable { + public FieldSrgData( - String obfOwner, - String obfName, - String srgOwner, - String srgPkg, - String srgName, - boolean isClientOnly) { + String obfOwner, + String obfName, + String srgOwner, + String srgPkg, + String srgName, + boolean isClientOnly) { super(obfOwner, obfName, srgOwner, srgPkg, srgName, isClientOnly); } - + @Override public int compareTo(FieldSrgData o) { - if (o != null) return this.getSrgName().compareTo(o.getSrgName()); - else return 1; + if (o != null) { + return this.getSrgName().compareTo(o.getSrgName()); + } else { + return 1; + } } } diff --git a/src/main/java/bspkrs/mmv/McpBotCommand.java b/src/main/java/bspkrs/mmv/McpBotCommand.java index 3d7ac71fc..0e43815cb 100644 --- a/src/main/java/bspkrs/mmv/McpBotCommand.java +++ b/src/main/java/bspkrs/mmv/McpBotCommand.java @@ -12,6 +12,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of */ public class McpBotCommand { + public enum BotCommand { SF, SM, @@ -55,7 +56,7 @@ public McpBotCommand(BotCommand command, String srgName, String newName) { } public static McpBotCommand getMcpBotCommand( - MemberType type, boolean isForced, String srgName, String newName, String comment) { + MemberType type, boolean isForced, String srgName, String newName, String comment) { return new McpBotCommand(getCommand(type, isForced), srgName, newName, comment); } @@ -70,6 +71,6 @@ public String getNewName() { @Override public String toString() { return String.format( - "!%s %s %s %s", command.toString().toLowerCase(), srgName, newName, comment); + "!%s %s %s %s", command.toString().toLowerCase(), srgName, newName, comment); } } diff --git a/src/main/java/bspkrs/mmv/MemberSrgData.java b/src/main/java/bspkrs/mmv/MemberSrgData.java index f7cc31efd..955b7225c 100644 --- a/src/main/java/bspkrs/mmv/MemberSrgData.java +++ b/src/main/java/bspkrs/mmv/MemberSrgData.java @@ -27,6 +27,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of */ public class MemberSrgData { + private final String obfOwner; private final String obfName; private final String srgOwner; @@ -35,12 +36,12 @@ public class MemberSrgData { private final boolean isClientOnly; public MemberSrgData( - String obfOwner, - String obfName, - String srgOwner, - String srgPkg, - String srgName, - boolean isClientOnly) { + String obfOwner, + String obfName, + String srgOwner, + String srgPkg, + String srgName, + boolean isClientOnly) { this.obfOwner = obfOwner; this.obfName = obfName; this.srgOwner = srgOwner; diff --git a/src/main/java/bspkrs/mmv/MethodSrgData.java b/src/main/java/bspkrs/mmv/MethodSrgData.java index 114a68321..60e82e072 100644 --- a/src/main/java/bspkrs/mmv/MethodSrgData.java +++ b/src/main/java/bspkrs/mmv/MethodSrgData.java @@ -27,18 +27,19 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of */ public class MethodSrgData extends MemberSrgData implements Comparable { + private final String obfDescriptor; private final String srgDescriptor; public MethodSrgData( - String obfOwner, - String obfName, - String obfDescriptor, - String srgOwner, - String srgPkg, - String srgName, - String srgDescriptor, - boolean isClientOnly) { + String obfOwner, + String obfName, + String obfDescriptor, + String srgOwner, + String srgPkg, + String srgName, + String srgDescriptor, + boolean isClientOnly) { super(obfOwner, obfName, srgOwner, srgPkg, srgName, isClientOnly); this.obfDescriptor = obfDescriptor; this.srgDescriptor = srgDescriptor; @@ -54,7 +55,10 @@ public String getSrgDescriptor() { @Override public int compareTo(MethodSrgData o) { - if (o != null) return getSrgName().compareTo(o.getSrgName()); - else return 1; + if (o != null) { + return getSrgName().compareTo(o.getSrgName()); + } else { + return 1; + } } } diff --git a/src/main/java/bspkrs/mmv/ParamCsvData.java b/src/main/java/bspkrs/mmv/ParamCsvData.java index 175cf255a..b3061b752 100644 --- a/src/main/java/bspkrs/mmv/ParamCsvData.java +++ b/src/main/java/bspkrs/mmv/ParamCsvData.java @@ -27,44 +27,47 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of */ public class ParamCsvData implements Comparable { + private final String srgName; private String mcpName; private final int side; - + public ParamCsvData(String srgName, String mcpName, int side) { this.srgName = srgName; this.mcpName = mcpName; this.side = side; } - + public String toCsv() { return srgName + "," + mcpName + "," + side; } - + public String getSrgName() { return srgName; } - + public String getMcpName() { return mcpName; } - + public ParamCsvData setMcpName(String mcpName) { this.mcpName = mcpName; return this; } - + public int getSide() { return side; } - + @Override public int compareTo(ParamCsvData o) { - if (o != null) return srgName.compareTo(o.srgName); - + if (o != null) { + return srgName.compareTo(o.srgName); + } + return 1; } - + public boolean contains(String s) { return mcpName.contains(s); } diff --git a/src/main/java/bspkrs/mmv/ParamCsvFile.java b/src/main/java/bspkrs/mmv/ParamCsvFile.java index f6a9ad196..074d44ad1 100644 --- a/src/main/java/bspkrs/mmv/ParamCsvFile.java +++ b/src/main/java/bspkrs/mmv/ParamCsvFile.java @@ -40,6 +40,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.TreeMap; public class ParamCsvFile { + private final File file; private final Map srgParamName2ParamCsvData; private boolean isDirty; @@ -62,7 +63,7 @@ public void readFromFile() throws IOException { String mcpName = in.next(); String side = in.nextLine().substring(1); srgParamName2ParamCsvData.put( - srgName, new ParamCsvData(srgName, mcpName, Integer.valueOf(side))); + srgName, new ParamCsvData(srgName, mcpName, Integer.valueOf(side))); } } finally { in.close(); @@ -73,11 +74,11 @@ public void writeToFile() throws IOException { if (isDirty) { if (file.exists()) { File fileBak = - new File( - file.getAbsolutePath() - + "_" - + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) - + ".bak"); + new File( + file.getAbsolutePath() + + "_" + + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + + ".bak"); file.renameTo(fileBak); } @@ -85,8 +86,10 @@ public void writeToFile() throws IOException { PrintWriter out = new PrintWriter(new FileWriter(file)); out.println(headerLine); - - for (ParamCsvData data : srgParamName2ParamCsvData.values()) out.println(data.toCsv()); + + for (ParamCsvData data : srgParamName2ParamCsvData.values()) { + out.println(data.toCsv()); + } out.close(); diff --git a/src/main/java/bspkrs/mmv/RemoteZipHandler.java b/src/main/java/bspkrs/mmv/RemoteZipHandler.java index 94dbf1f40..ceb4e8911 100644 --- a/src/main/java/bspkrs/mmv/RemoteZipHandler.java +++ b/src/main/java/bspkrs/mmv/RemoteZipHandler.java @@ -48,6 +48,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.zip.ZipInputStream; public class RemoteZipHandler { + private static final String MMV_VERSION = "1.0.1"; private final URL zipUrl; @@ -57,10 +58,13 @@ public class RemoteZipHandler { private final String zipFileName; public RemoteZipHandler(String urlString, File dir, String digestType) - throws MalformedURLException { + throws MalformedURLException { zipUrl = new URL(urlString); - if (digestType != null) digestUrl = new URL(urlString + "." + digestType.toLowerCase()); - else digestUrl = null; + if (digestType != null) { + digestUrl = new URL(urlString + "." + digestType.toLowerCase()); + } else { + digestUrl = null; + } String[] tokens = urlString.split("/"); zipFileName = tokens[tokens.length - 1]; localDir = dir; @@ -74,14 +78,16 @@ public void checkRemoteZip() throws IOException, NoSuchAlgorithmException, Diges File digestFile = null; if (digestType != null) { // check hash against local hash if exists - remoteHash = loadTextFromURL(digestUrl, new String[] {""})[0]; + remoteHash = loadTextFromURL(digestUrl, new String[]{""})[0]; if (!remoteHash.isEmpty()) { digestFile = new File(localDir, zipFileName + "." + digestType.toLowerCase()); // if local digest exists and hashes match skip getting the zip file if (digestFile.exists()) { - String existingHash = loadTextFromFile(digestFile, new String[] {""})[0]; - if (!existingHash.isEmpty() && remoteHash.equals(existingHash)) fetchZip = false; + String existingHash = loadTextFromFile(digestFile, new String[]{""})[0]; + if (!existingHash.isEmpty() && remoteHash.equals(existingHash)) { + fetchZip = false; + } } } } @@ -89,7 +95,9 @@ public void checkRemoteZip() throws IOException, NoSuchAlgorithmException, Diges if (fetchZip) { // download zip File localZip = new File(localDir, zipFileName); - if (localZip.exists()) localZip.delete(); + if (localZip.exists()) { + localZip.delete(); + } OutputStream output = new FileOutputStream(localZip); try { URLConnection uc = zipUrl.openConnection(); @@ -97,7 +105,9 @@ public void checkRemoteZip() throws IOException, NoSuchAlgorithmException, Diges byte[] buffer = new byte[1024]; // Or whatever int bytesRead; try (InputStream is = uc.getInputStream()) { - while ((bytesRead = is.read(buffer)) > 0) output.write(buffer, 0, bytesRead); + while ((bytesRead = is.read(buffer)) > 0) { + output.write(buffer, 0, bytesRead); + } } } finally { output.close(); @@ -106,18 +116,23 @@ public void checkRemoteZip() throws IOException, NoSuchAlgorithmException, Diges // Check hash of downloaded file to ensure we received it correctly if (digestType != null && !remoteHash.isEmpty()) { String downloadHash = getFileDigest(new FileInputStream(localZip), digestType); - if (!remoteHash.equals(downloadHash)) + if (!remoteHash.equals(downloadHash)) { throw new java.security.DigestException( - "Remote digest does not match digest of downloaded file!"); + "Remote digest does not match digest of downloaded file!"); + } } // extract zip file extractZip(localZip, localDir); - if (localZip.exists()) localZip.delete(); + if (localZip.exists()) { + localZip.delete(); + } // save new hash after successful extract if (digestType != null && !remoteHash.isEmpty()) { - if (digestFile.exists()) digestFile.delete(); + if (digestFile.exists()) { + digestFile.delete(); + } digestFile.createNewFile(); PrintWriter out = new PrintWriter(new FileWriter(digestFile)); out.print(remoteHash); @@ -141,7 +156,9 @@ public static String[] loadTextFromURL(URL url, String[] defaultValue) { } catch (Throwable e) { return defaultValue; } finally { - if (scanner != null) scanner.close(); + if (scanner != null) { + scanner.close(); + } } return arraylist.toArray(new String[arraylist.size()]); } @@ -152,24 +169,30 @@ public static String[] loadTextFromFile(File file, String[] defaultValue) { Scanner scanner = null; try { scanner = new Scanner(file); - while (scanner.hasNextLine()) lines.add(scanner.nextLine()); + while (scanner.hasNextLine()) { + lines.add(scanner.nextLine()); + } } catch (FileNotFoundException e) { return defaultValue; } finally { - if (scanner != null) scanner.close(); + if (scanner != null) { + scanner.close(); + } } return lines.toArray(new String[lines.size()]); } public static String getFileDigest(InputStream is, String digestType) - throws NoSuchAlgorithmException, IOException { + throws NoSuchAlgorithmException, IOException { MessageDigest md = MessageDigest.getInstance(digestType); byte[] dataBytes = new byte[1024]; int nread = 0; - - while ((nread = is.read(dataBytes)) != -1) md.update(dataBytes, 0, nread); + + while ((nread = is.read(dataBytes)) != -1) { + md.update(dataBytes, 0, nread); + } is.close(); @@ -177,14 +200,17 @@ public static String getFileDigest(InputStream is, String digestType) // convert the byte to hex format StringBuffer sb = new StringBuffer(""); - for (int i = 0; i < mdbytes.length; i++) + for (int i = 0; i < mdbytes.length; i++) { sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1)); + } return sb.toString(); } public static void extractZip(File zipFile, File destDir) throws IOException { byte[] buffer = new byte[1024]; - if (!destDir.exists()) destDir.mkdirs(); + if (!destDir.exists()) { + destDir.mkdirs(); + } ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile)); ZipEntry ze = zis.getNextEntry(); @@ -193,15 +219,22 @@ public static void extractZip(File zipFile, File destDir) throws IOException { String fileName = ze.getName(); File newFile = new File(destDir, fileName); if (ze.isDirectory()) { - if (newFile.exists()) deleteDirAndContents(newFile); + if (newFile.exists()) { + deleteDirAndContents(newFile); + } newFile.mkdirs(); } else { - if (newFile.exists()) newFile.delete(); - if (newFile.getParentFile() != null && !newFile.getParentFile().exists()) + if (newFile.exists()) { + newFile.delete(); + } + if (newFile.getParentFile() != null && !newFile.getParentFile().exists()) { newFile.getParentFile().mkdirs(); + } FileOutputStream fos = new FileOutputStream(newFile); int len; - while ((len = zis.read(buffer)) > 0) fos.write(buffer, 0, len); + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } fos.close(); } @@ -218,7 +251,9 @@ public static boolean deleteDirAndContents(File dir) { String[] children = dir.list(); for (int i = 0; i < children.length; i++) { boolean success = deleteDirAndContents(new File(dir, children[i])); - if (!success) return false; + if (!success) { + return false; + } } } return dir.delete(); diff --git a/src/main/java/bspkrs/mmv/SplittedNaturalComparator.java b/src/main/java/bspkrs/mmv/SplittedNaturalComparator.java index d15288285..304231e4c 100644 --- a/src/main/java/bspkrs/mmv/SplittedNaturalComparator.java +++ b/src/main/java/bspkrs/mmv/SplittedNaturalComparator.java @@ -30,23 +30,28 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.Comparator; public class SplittedNaturalComparator implements Comparator { + private final String splitter; - + public SplittedNaturalComparator(String splitter) { this.splitter = splitter; } - + @Override public int compare(Object o1, Object o2) { String[] a = o1.toString().split(splitter); String[] b = o2.toString().split(splitter); - - if (a.length != b.length) return b.length - a.length; - + + if (a.length != b.length) { + return b.length - a.length; + } + NaturalOrderComparator comp = new NaturalOrderComparator(); for (int i = 0; i < a.length; i++) { int comparison = comp.compare(a[i], b[i]); - if (comparison != 0) return comparison; + if (comparison != 0) { + return comparison; + } } return 0; } diff --git a/src/main/java/bspkrs/mmv/SrgFile.java b/src/main/java/bspkrs/mmv/SrgFile.java index f4be72c76..66d2ac7a9 100644 --- a/src/main/java/bspkrs/mmv/SrgFile.java +++ b/src/main/java/bspkrs/mmv/SrgFile.java @@ -39,23 +39,24 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.TreeSet; public class SrgFile { + // All maps should be inter-connected to reference a single set of objects public final Map srgClassName2ClassData = - new TreeMap(); // full/pkg/ClassSrgName -> ClassSrgData + new TreeMap(); // full/pkg/ClassSrgName -> ClassSrgData public final Map> srgPkg2ClassDataSet = - new TreeMap>(); // full/pkg -> Set + new TreeMap>(); // full/pkg -> Set public final Map srgFieldName2FieldData = - new TreeMap(); // field_12345_a -> FieldSrgData + new TreeMap(); // field_12345_a -> FieldSrgData public final Map srgMethodName2MethodData = - new TreeMap(); // func_12345_a -> MethodSrgData + new TreeMap(); // func_12345_a -> MethodSrgData public final Map> class2MethodDataSet = - new TreeMap>(); + new TreeMap>(); public final Map> class2FieldDataSet = - new TreeMap>(); + new TreeMap>(); public final Map srgMethodName2ClassData = - new TreeMap(); // func_12345_a -> ClassSrgData + new TreeMap(); // func_12345_a -> ClassSrgData public final Map srgFieldName2ClassData = - new TreeMap(); // field_12345_a -> ClassSrgData + new TreeMap(); // field_12345_a -> ClassSrgData public static String getLastComponent(String s) { String[] parts = s.split("/"); @@ -75,18 +76,21 @@ public SrgFile(File f, ExcFile excFile, StaticMethodsFile staticMethods) throws String pkgName = deobf.substring(0, deobf.lastIndexOf('/')); ClassSrgData classData = new ClassSrgData(obf, srgName, pkgName, in.hasNext("#C")); - - if (!srgPkg2ClassDataSet.containsKey(pkgName)) + + if (!srgPkg2ClassDataSet.containsKey(pkgName)) { srgPkg2ClassDataSet.put(pkgName, new TreeSet()); + } srgPkg2ClassDataSet.get(pkgName).add(classData); srgClassName2ClassData.put(pkgName + "/" + srgName, classData); - - if (!class2MethodDataSet.containsKey(classData)) + + if (!class2MethodDataSet.containsKey(classData)) { class2MethodDataSet.put(classData, new TreeSet()); - - if (!class2FieldDataSet.containsKey(classData)) + } + + if (!class2FieldDataSet.containsKey(classData)) { class2FieldDataSet.put(classData, new TreeSet()); + } } else if (in.hasNext("FD:")) { // FD: aql/c net/minecraft/block/BlockStoneBrick/field_94408_c #C in.next(); // skip FD: @@ -100,12 +104,12 @@ public SrgFile(File f, ExcFile excFile, StaticMethodsFile staticMethods) throws srgPkg = srgPkg.substring(0, srgPkg.lastIndexOf('/')); FieldSrgData fieldData = - new FieldSrgData(obfOwner, obfName, srgOwner, srgPkg, srgName, in.hasNext("#C")); + new FieldSrgData(obfOwner, obfName, srgOwner, srgPkg, srgName, in.hasNext("#C")); srgFieldName2FieldData.put(srgName, fieldData); class2FieldDataSet - .get(srgClassName2ClassData.get(srgPkg + "/" + srgOwner)) - .add(fieldData); + .get(srgClassName2ClassData.get(srgPkg + "/" + srgOwner)) + .add(fieldData); srgFieldName2ClassData.put(srgName, srgClassName2ClassData.get(srgPkg + "/" + srgOwner)); } else if (in.hasNext("MD:")) { // MD: aor/a (Lmt;)V net/minecraft/block/BlockHay/func_94332_a @@ -123,35 +127,38 @@ public SrgFile(File f, ExcFile excFile, StaticMethodsFile staticMethods) throws String srgDescriptor = in.next(); MethodSrgData methodData = - new MethodSrgData( - obfOwner, - obfName, - obfDescriptor, - srgOwner, - srgPkg, - srgName, - srgDescriptor, - in.hasNext("#C")); + new MethodSrgData( + obfOwner, + obfName, + obfDescriptor, + srgOwner, + srgPkg, + srgName, + srgDescriptor, + in.hasNext("#C")); srgMethodName2MethodData.put(srgName, methodData); class2MethodDataSet - .get(srgClassName2ClassData.get(srgPkg + "/" + srgOwner)) - .add(methodData); + .get(srgClassName2ClassData.get(srgPkg + "/" + srgOwner)) + .add(methodData); srgMethodName2ClassData.put(srgName, srgClassName2ClassData.get(srgPkg + "/" + srgOwner)); // Hack in the missing parameter data ExcData toAdd = - new ExcData( - srgOwner, srgName, srgDescriptor, new String[0], staticMethods.contains(srgName)); + new ExcData( + srgOwner, srgName, srgDescriptor, new String[0], staticMethods.contains(srgName)); ExcData existing = excFile.srgMethodName2ExcData.get(srgName); if ((existing == null) - || (existing.getParameters().length < toAdd.getParameters().length)) { + || (existing.getParameters().length < toAdd.getParameters().length)) { excFile.srgMethodName2ExcData.put(srgName, toAdd); - for (String parameter : toAdd.getParameters()) + for (String parameter : toAdd.getParameters()) { excFile.srgParamName2ExcData.put(parameter, toAdd); + } } - } else in.nextLine(); + } else { + in.nextLine(); + } } } finally { in.close(); diff --git a/src/main/java/bspkrs/mmv/StaticMethodsFile.java b/src/main/java/bspkrs/mmv/StaticMethodsFile.java index ad7a58b85..5991c3880 100644 --- a/src/main/java/bspkrs/mmv/StaticMethodsFile.java +++ b/src/main/java/bspkrs/mmv/StaticMethodsFile.java @@ -35,6 +35,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.Scanner; public class StaticMethodsFile { + private final File file; public List staticMethods; diff --git a/src/main/java/bspkrs/mmv/VersionFetcher.java b/src/main/java/bspkrs/mmv/VersionFetcher.java index 4689fe1fd..c41b59724 100644 --- a/src/main/java/bspkrs/mmv/VersionFetcher.java +++ b/src/main/java/bspkrs/mmv/VersionFetcher.java @@ -38,6 +38,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.Map; public class VersionFetcher { + private final String jsonUrl = "http://export.mcpbot.bspk.rs/versions.json"; private List versions; @@ -52,12 +53,17 @@ public List getVersions(boolean force) throws IOException { Map json = new Gson().fromJson(br, Map.class); versions = new ArrayList(); - for (String mcVer : json.keySet()) - for (String channel : ((Map[]>) json.get(mcVer)).keySet()) - for (Double ver : ((Map>) json.get(mcVer)).get(channel)) + for (String mcVer : json.keySet()) { + for (String channel : ((Map[]>) json.get(mcVer)).keySet()) { + for (Double ver : ((Map>) json.get(mcVer)).get(channel)) { versions.add(mcVer + "_" + channel + "_" + String.format("%.0f", ver)); + } + } + } Collections.sort(versions, Collections.reverseOrder(new SplittedNaturalComparator("_"))); return versions; - } else return versions; + } else { + return versions; + } } } diff --git a/src/main/java/bspkrs/mmv/version/NaturalOrderComparator.java b/src/main/java/bspkrs/mmv/version/NaturalOrderComparator.java index 5a25135a3..31281b10c 100644 --- a/src/main/java/bspkrs/mmv/version/NaturalOrderComparator.java +++ b/src/main/java/bspkrs/mmv/version/NaturalOrderComparator.java @@ -39,6 +39,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of import java.util.Comparator; public class NaturalOrderComparator implements Comparator { + int compareRight(String a, String b) { int bias = 0; int ia = 0; @@ -63,7 +64,9 @@ int compareRight(String a, String b) { bias = -1; } } else if (ca > cb) { - if (bias == 0) bias = +1; + if (bias == 0) { + bias = +1; + } } else if (ca == 0 && cb == 0) { return bias; } diff --git a/src/main/java/com/matt/forgehax/ForgeHax.java b/src/main/java/com/matt/forgehax/ForgeHax.java index 72ad7d5d5..b3cf76d3d 100644 --- a/src/main/java/com/matt/forgehax/ForgeHax.java +++ b/src/main/java/com/matt/forgehax/ForgeHax.java @@ -7,12 +7,14 @@ import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.relauncher.Side; @Mod(modid = ForgeHax.MOD_ID, clientSideOnly = true) public class ForgeHax { + public static final String MOD_ID = "forgehax"; public static final String MOD_VERSION = ForgeHaxProperties.getVersion(); - + static { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // NOTE: if you ever change the package name make sure this @@ -21,43 +23,29 @@ public class ForgeHax { getModManager().searchPackage("com.matt.forgehax.mods.*"); getModManager().searchPluginDirectory(getFileManager().getBaseResolve("plugins")); } - + public static String getWelcomeMessage() { - StringBuilder builder = new StringBuilder(); - builder.append("Running ForgeHax v"); - builder.append(MOD_VERSION); - builder.append("\n"); - builder.append("Type .help in chat for command instructions"); - return builder.toString(); + return String + .format("Running ForgeHax v%s\n Type .help in chat for command instructions", MOD_VERSION); } - + @Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { - switch (event.getSide()) { - case CLIENT: - { - // ---- initialize mods ----// - getModManager().loadAll(); - } - default: - break; + if (event.getSide() == Side.CLIENT) { + // ---- initialize mods ----// + getModManager().loadAll(); } } - + @Mod.EventHandler public void init(FMLInitializationEvent event) { - switch (event.getSide()) { - case CLIENT: - { - // add shutdown hook to serialize all binds - Runtime.getRuntime() - .addShutdownHook(new Thread(() -> getModManager().forEach(BaseMod::unload))); - // registerAll mod events - getModManager().forEach(BaseMod::load); - break; - } - default: - break; + if (event.getSide() == Side.CLIENT) { + // add shutdown hook to serialize all binds + Runtime.getRuntime() + .addShutdownHook(new Thread(() -> getModManager().forEach(BaseMod::unload))); + + // registerAll mod events + getModManager().forEach(BaseMod::load); } } } diff --git a/src/main/java/com/matt/forgehax/ForgeHaxProperties.java b/src/main/java/com/matt/forgehax/ForgeHaxProperties.java index cc51065d5..8390cac34 100644 --- a/src/main/java/com/matt/forgehax/ForgeHaxProperties.java +++ b/src/main/java/com/matt/forgehax/ForgeHaxProperties.java @@ -4,53 +4,59 @@ import java.io.InputStream; import java.util.Properties; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class ForgeHaxProperties { + private static final Properties CONFIG_PROPERTIES = new Properties(); - + static { InputStream input = null; try { input = ForgeHaxProperties.class.getClassLoader().getResourceAsStream("config.properties"); CONFIG_PROPERTIES.load(input); } catch (Throwable t) { + ; } finally { - if (input != null) + if (input != null) { try { input.close(); - } catch (Throwable t) {; + } catch (Throwable t) { + ; } + } } } - + public static Properties getConfigProperties() { return CONFIG_PROPERTIES; } - + public static String getVersion() { return Strings.nullToEmpty(getConfigProperties().getProperty("forgehax.version")); } - + public static String getMcVersion() { return Strings.nullToEmpty(getConfigProperties().getProperty("forgehax.mc.version")); } - + public static String getForgeVersion() { return Strings.nullToEmpty(getConfigProperties().getProperty("forgehax.forge.version")); } - + public static String getMcpVersion() { return Strings.nullToEmpty(getConfigProperties().getProperty("forgehax.mcp.version")); } - + public static String getMcpChannel() { return Strings.nullToEmpty(getConfigProperties().getProperty("forgehax.mcp.channel")); } - + public static String getMcpMapping() { return Strings.nullToEmpty(getConfigProperties().getProperty("forgehax.mcp.mapping")); } - + public static String getMcpMappingUrl() { return String.format("%s_%s_%s", getMcpVersion(), getMcpChannel(), getMcpMapping()); } diff --git a/src/main/java/com/matt/forgehax/Globals.java b/src/main/java/com/matt/forgehax/Globals.java index 0c772012a..86c4e093a 100644 --- a/src/main/java/com/matt/forgehax/Globals.java +++ b/src/main/java/com/matt/forgehax/Globals.java @@ -7,8 +7,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** 2 lazy to import static */ +/** + * 2 lazy to import static + */ public interface Globals { + Logger LOGGER = LogManager.getLogger("ForgeHax"); Minecraft MC = FMLClientHandler.instance().getClient(); Command GLOBAL_COMMAND = CommandGlobal.getInstance(); diff --git a/src/main/java/com/matt/forgehax/Helper.java b/src/main/java/com/matt/forgehax/Helper.java index 20a2c6543..ba5b16a9c 100644 --- a/src/main/java/com/matt/forgehax/Helper.java +++ b/src/main/java/com/matt/forgehax/Helper.java @@ -2,8 +2,8 @@ import com.google.common.base.Strings; import com.google.common.base.Throwables; -import com.matt.forgehax.log.FileManager; import com.matt.forgehax.mods.services.MainMenuGuiService.CommandInputGui; +import com.matt.forgehax.util.FileManager; import com.matt.forgehax.util.command.CommandGlobal; import com.matt.forgehax.util.mod.loader.ModManager; import java.util.Optional; @@ -24,72 +24,78 @@ import net.minecraftforge.fml.client.FMLClientHandler; import org.apache.logging.log4j.Logger; -/** Created on 4/25/2017 by fr1kin */ +/** + * Created on 4/25/2017 by fr1kin + */ public class Helper implements Globals { + public static CommandGlobal getGlobalCommand() { return CommandGlobal.getInstance(); } - + public static Minecraft getMinecraft() { return MC; } - + public static ModManager getModManager() { return ModManager.getInstance(); } - + public static FileManager getFileManager() { return FileManager.getInstance(); } - + public static Logger getLog() { return LOGGER; } - + public static EntityPlayerSP getLocalPlayer() { return MC.player; } - + @Nullable public static Entity getRidingEntity() { - if (getLocalPlayer() != null) return getLocalPlayer().getRidingEntity(); - else return null; + if (getLocalPlayer() != null) { + return getLocalPlayer().getRidingEntity(); + } else { + return null; + } } - + public static Optional getOptionalRidingEntity() { return Optional.ofNullable(getRidingEntity()); } - + // Returns the riding entity if present, otherwise the local player @Nullable public static Entity getRidingOrPlayer() { return getRidingEntity() != null ? getRidingEntity() : getLocalPlayer(); } - + @Nullable public static WorldClient getWorld() { return MC.world; } - + public static World getWorld(Entity entity) { return entity.getEntityWorld(); } - + public static World getWorld(TileEntity tileEntity) { return tileEntity.getWorld(); } - + @Nullable public static NetworkManager getNetworkManager() { return FMLClientHandler.instance().getClientToServerNetworkManager(); } - + public static PlayerControllerMP getPlayerController() { return MC.playerController; } - + public static void printMessageNaked( - String startWith, String message, Style firstStyle, Style secondStyle) { + String startWith, String message, Style firstStyle, Style secondStyle) { if (!Strings.isNullOrEmpty(message)) { if (message.contains("\n")) { Scanner scanner = new Scanner(message); @@ -105,12 +111,13 @@ public static void printMessageNaked( } } else { TextComponentString string = - new TextComponentString(startWith + message.replaceAll("\r", "")); + new TextComponentString(startWith + message.replaceAll("\r", "")); string.setStyle(firstStyle); outputMessage(string.getFormattedText()); } } } + // private function that is ultimately used to output the message private static void outputMessage(String text) { if (getLocalPlayer() != null) { @@ -119,98 +126,112 @@ private static void outputMessage(String text) { ((CommandInputGui) MC.currentScreen).print(text); } } - + public static void printMessageNaked(String append, String message, Style style) { printMessageNaked(append, message, style, style); } - + public static void printMessageNaked(String append, String message) { printMessageNaked( - append, - message, - new Style().setColor(TextFormatting.WHITE), - new Style().setColor(TextFormatting.GRAY)); + append, + message, + new Style().setColor(TextFormatting.WHITE), + new Style().setColor(TextFormatting.GRAY)); } - + public static void printMessageNaked(String message) { printMessageNaked("", message); } - + // Will append '[FH] ' in front public static void printMessage(String message) { - if (!Strings.isNullOrEmpty(message)) printMessageNaked("[FH] " + message); + if (!Strings.isNullOrEmpty(message)) { + printMessageNaked("[FH] " + message); + } } - + public static void printMessage(String format, Object... args) { printMessage(String.format(format, args)); } - - private static ITextComponent getFormattedText( - String text, TextFormatting color, boolean bold, boolean italic) { + + private static ITextComponent getFormattedText(String text, TextFormatting color, + boolean bold, boolean italic) { return new TextComponentString(text.replaceAll("\r", "")) - .setStyle(new Style().setColor(color).setBold(bold).setItalic(italic)); + .setStyle(new Style() + .setColor(color) + .setBold(bold) + .setItalic(italic) + ); } - + public static void printInform(String format, Object... args) { outputMessage( - getFormattedText("[ForgeHax]", TextFormatting.GREEN, true, false) - .appendSibling( - getFormattedText( - " " + String.format(format, args).trim(), TextFormatting.GRAY, false, false)) - .getFormattedText()); - } - + getFormattedText("[ForgeHax]", TextFormatting.GREEN, true, false) + .appendSibling( + getFormattedText(" " + String.format(format, args).trim(), + TextFormatting.GRAY, false, false) + ).getFormattedText() + ); + } + public static void printWarning(String format, Object... args) { outputMessage( - getFormattedText("[ForgeHax]", TextFormatting.YELLOW, true, false) - .appendSibling( - getFormattedText( - " " + String.format(format, args).trim(), TextFormatting.GRAY, false, false)) - .getFormattedText()); - } - + getFormattedText("[ForgeHax]", TextFormatting.YELLOW, true, false) + .appendSibling( + getFormattedText(" " + String.format(format, args).trim(), + TextFormatting.GRAY, false, false) + ).getFormattedText() + ); + } + public static void printError(String format, Object... args) { outputMessage( - getFormattedText("[ForgeHax]", TextFormatting.RED, true, false) - .appendSibling( - getFormattedText( - " " + String.format(format, args).trim(), TextFormatting.GRAY, false, false)) - .getFormattedText()); - } - + getFormattedText("[ForgeHax]", TextFormatting.RED, true, false) + .appendSibling( + getFormattedText(" " + String.format(format, args).trim(), + TextFormatting.GRAY, false, false) + ).getFormattedText() + ); + } + public static void printStackTrace(Throwable t) { getLog().error(Throwables.getStackTraceAsString(t)); } - + public static void handleThrowable(Throwable t) { - getLog() - .error( - String.format( - "[%s] %s", t.getClass().getSimpleName(), Strings.nullToEmpty(t.getMessage()))); - if (t.getCause() != null) handleThrowable(t.getCause()); + getLog().error(String.format("[%s] %s", + t.getClass().getSimpleName(), + Strings.nullToEmpty(t.getMessage()))); + + if (t.getCause() != null) { + handleThrowable(t.getCause()); + } printStackTrace(t); } - + public static void reloadChunks() { // credits to 0x22 - if (getWorld() != null && getLocalPlayer() != null) + if (getWorld() != null && getLocalPlayer() != null) { MC.addScheduledTask( - () -> { - int x = (int) getLocalPlayer().posX; - int y = (int) getLocalPlayer().posY; - int z = (int) getLocalPlayer().posZ; - - int distance = MC.gameSettings.renderDistanceChunks * 16; - - MC.renderGlobal.markBlockRangeForRenderUpdate( - x - distance, y - distance, z - distance, x + distance, y + distance, z + distance); - }); + () -> { + int x = (int) getLocalPlayer().posX; + int y = (int) getLocalPlayer().posY; + int z = (int) getLocalPlayer().posZ; + + int distance = MC.gameSettings.renderDistanceChunks * 16; + + MC.renderGlobal.markBlockRangeForRenderUpdate( + x - distance, y - distance, z - distance, x + distance, y + distance, z + distance); + }); + } } - + public static void reloadChunksHard() { MC.addScheduledTask( - () -> { - if (getWorld() != null && getLocalPlayer() != null) MC.renderGlobal.loadRenderers(); - }); + () -> { + if (getWorld() != null && getLocalPlayer() != null) { + MC.renderGlobal.loadRenderers(); + } + }); } } diff --git a/src/main/java/com/matt/forgehax/asm/ASMCommon.java b/src/main/java/com/matt/forgehax/asm/ASMCommon.java index 929feaddb..c90c824eb 100644 --- a/src/main/java/com/matt/forgehax/asm/ASMCommon.java +++ b/src/main/java/com/matt/forgehax/asm/ASMCommon.java @@ -5,8 +5,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** Created on 5/2/2017 by fr1kin */ +/** + * Created on 5/2/2017 by fr1kin + */ public interface ASMCommon { + Logger LOGGER = LogManager.getLogger("ForgeHaxASM"); IStateMapper MAPPER = RuntimeState.getMapper(); } diff --git a/src/main/java/com/matt/forgehax/asm/ForgeHaxCoreMod.java b/src/main/java/com/matt/forgehax/asm/ForgeHaxCoreMod.java index 3e09490ab..a4f772d89 100644 --- a/src/main/java/com/matt/forgehax/asm/ForgeHaxCoreMod.java +++ b/src/main/java/com/matt/forgehax/asm/ForgeHaxCoreMod.java @@ -6,9 +6,10 @@ import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; public class ForgeHaxCoreMod implements IFMLLoadingPlugin, ASMCommon { + @Override public String[] getASMTransformerClass() { - return new String[] {ForgeHaxTransformer.class.getName()}; + return new String[]{ForgeHaxTransformer.class.getName()}; } @Override diff --git a/src/main/java/com/matt/forgehax/asm/ForgeHaxHooks.java b/src/main/java/com/matt/forgehax/asm/ForgeHaxHooks.java index 539cd3f77..fbb793973 100644 --- a/src/main/java/com/matt/forgehax/asm/ForgeHaxHooks.java +++ b/src/main/java/com/matt/forgehax/asm/ForgeHaxHooks.java @@ -3,8 +3,38 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.matt.forgehax.asm.TypesMc.Methods; -import com.matt.forgehax.asm.events.*; +import com.matt.forgehax.asm.events.AddCollisionBoxToListEvent; +import com.matt.forgehax.asm.events.AddRenderChunkEvent; +import com.matt.forgehax.asm.events.ApplyClimbableBlockMovement; +import com.matt.forgehax.asm.events.ApplyCollisionMotionEvent; +import com.matt.forgehax.asm.events.BlockControllerProcessEvent; +import com.matt.forgehax.asm.events.BlockRenderEvent; +import com.matt.forgehax.asm.events.BuildChunkEvent; +import com.matt.forgehax.asm.events.ChunkUploadedEvent; +import com.matt.forgehax.asm.events.ComputeVisibilityEvent; +import com.matt.forgehax.asm.events.DeleteGlResourcesEvent; +import com.matt.forgehax.asm.events.DoBlockCollisionsEvent; +import com.matt.forgehax.asm.events.DrawBlockBoundingBoxEvent; +import com.matt.forgehax.asm.events.EntityBlockSlipApplyEvent; import com.matt.forgehax.asm.events.EntityBlockSlipApplyEvent.Stage; +import com.matt.forgehax.asm.events.HurtCamEffectEvent; +import com.matt.forgehax.asm.events.ItemStoppedUsedEvent; +import com.matt.forgehax.asm.events.LeftClickCounterUpdateEvent; +import com.matt.forgehax.asm.events.LoadRenderersEvent; +import com.matt.forgehax.asm.events.LocalPlayerUpdateMovementEvent; +import com.matt.forgehax.asm.events.PacketEvent; +import com.matt.forgehax.asm.events.PlayerAttackEntityEvent; +import com.matt.forgehax.asm.events.PlayerDamageBlockEvent; +import com.matt.forgehax.asm.events.PlayerSyncItemEvent; +import com.matt.forgehax.asm.events.PushOutOfBlocksEvent; +import com.matt.forgehax.asm.events.RenderBlockInLayerEvent; +import com.matt.forgehax.asm.events.RenderBlockLayerEvent; +import com.matt.forgehax.asm.events.RenderBoatEvent; +import com.matt.forgehax.asm.events.SchematicaPlaceBlockEvent; +import com.matt.forgehax.asm.events.SetupTerrainEvent; +import com.matt.forgehax.asm.events.WaterMovementEvent; +import com.matt.forgehax.asm.events.WorldCheckLightForEvent; +import com.matt.forgehax.asm.events.WorldRendererDeallocatedEvent; import com.matt.forgehax.asm.events.listeners.BlockModelRenderListener; import com.matt.forgehax.asm.events.listeners.Listeners; import com.matt.forgehax.asm.utils.MultiBoolean; @@ -20,7 +50,11 @@ import net.minecraft.client.multiplayer.PlayerControllerMP; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.ViewFrustum; -import net.minecraft.client.renderer.chunk.*; +import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator; +import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; +import net.minecraft.client.renderer.chunk.RenderChunk; +import net.minecraft.client.renderer.chunk.SetVisibility; +import net.minecraft.client.renderer.chunk.VisGraph; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.item.EntityBoat; @@ -39,193 +73,227 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class ForgeHaxHooks implements ASMCommon { + private static final List ALL_REPORTERS = Lists.newArrayList(); - + public static List getReporters() { return Collections.unmodifiableList(ALL_REPORTERS); } - + private static HookReporter.Builder newHookReporter() { return HookReporter.Builder.of() - .parentClass(ForgeHaxHooks.class) - .finalizeBy(ALL_REPORTERS::add); + .parentClass(ForgeHaxHooks.class) + .finalizeBy(ALL_REPORTERS::add); } - - /** static fields */ + + /** + * static fields + */ public static boolean isSafeWalkActivated = false; - + public static boolean isNoSlowDownActivated = false; - + public static boolean isNoBoatGravityActivated = false; public static boolean isNoClampingActivated = false; public static boolean isBoatSetYawActivated = false; public static boolean isNotRowingBoatActivated = false; - + public static boolean doIncreaseTabListSize = false; - + /** static hooks */ - - /** Convenient functions for firing events */ + + /** + * Convenient functions for firing events + */ public static void fireEvent_v(Event event) { MinecraftForge.EVENT_BUS.post(event); } - + public static boolean fireEvent_b(Event event) { return MinecraftForge.EVENT_BUS.post(event); } - - /** onDrawBoundingBox */ + + /** + * onDrawBoundingBox + */ public static void onDrawBoundingBoxPost() { MinecraftForge.EVENT_BUS.post(new DrawBlockBoundingBoxEvent.Post()); } - - /** onPushOutOfBlocks */ + + /** + * onPushOutOfBlocks + */ public static final HookReporter HOOK_onPushOutOfBlocks = - newHookReporter() - .hook("onPushOutOfBlocks") - .dependsOn(TypesMc.Methods.EntityPlayerSP_pushOutOfBlocks) - .forgeEvent(PushOutOfBlocksEvent.class) - .build(); - + newHookReporter() + .hook("onPushOutOfBlocks") + .dependsOn(TypesMc.Methods.EntityPlayerSP_pushOutOfBlocks) + .forgeEvent(PushOutOfBlocksEvent.class) + .build(); + public static boolean onPushOutOfBlocks() { return HOOK_onPushOutOfBlocks.reportHook() - && MinecraftForge.EVENT_BUS.post(new PushOutOfBlocksEvent()); + && MinecraftForge.EVENT_BUS.post(new PushOutOfBlocksEvent()); } - - /** onRenderBoat */ + + /** + * onRenderBoat + */ public static final HookReporter HOOK_onRenderBoat = - newHookReporter() - .hook("onRenderBoat") - .dependsOn(TypesMc.Methods.RenderBoat_doRender) - .forgeEvent(RenderBoatEvent.class) - .build(); - + newHookReporter() + .hook("onRenderBoat") + .dependsOn(TypesMc.Methods.RenderBoat_doRender) + .forgeEvent(RenderBoatEvent.class) + .build(); + public static float onRenderBoat(EntityBoat boat, float entityYaw) { if (HOOK_onRenderBoat.reportHook()) { RenderBoatEvent event = new RenderBoatEvent(boat, entityYaw); MinecraftForge.EVENT_BUS.post(event); return event.getYaw(); - } else return entityYaw; + } else { + return entityYaw; + } } - - /** onSchematicaPlaceBlock */ + + /** + * onSchematicaPlaceBlock + */ public static final HookReporter HOOK_onSchematicaPlaceBlock = - newHookReporter() - .hook("onSchematicaPlaceBlock") - .dependsOn(TypesSpecial.Methods.SchematicPrinter_placeBlock) - .forgeEvent(SchematicaPlaceBlockEvent.class) - .build(); - + newHookReporter() + .hook("onSchematicaPlaceBlock") + .dependsOn(TypesSpecial.Methods.SchematicPrinter_placeBlock) + .forgeEvent(SchematicaPlaceBlockEvent.class) + .build(); + public static void onSchematicaPlaceBlock(ItemStack itemIn, BlockPos posIn, Vec3d vecIn) { - if (HOOK_onSchematicaPlaceBlock.reportHook()) + if (HOOK_onSchematicaPlaceBlock.reportHook()) { MinecraftForge.EVENT_BUS.post(new SchematicaPlaceBlockEvent(itemIn, posIn, vecIn)); + } } - - /** onHurtcamEffect */ + + /** + * onHurtcamEffect + */ public static final HookReporter HOOK_onHurtcamEffect = - newHookReporter() - .hook("onHurtcamEffect") - .dependsOn(TypesMc.Methods.EntityRenderer_hurtCameraEffect) - .forgeEvent(HurtCamEffectEvent.class) - .build(); - + newHookReporter() + .hook("onHurtcamEffect") + .dependsOn(TypesMc.Methods.EntityRenderer_hurtCameraEffect) + .forgeEvent(HurtCamEffectEvent.class) + .build(); + public static boolean onHurtcamEffect(float partialTicks) { return HOOK_onHurtcamEffect.reportHook() - && MinecraftForge.EVENT_BUS.post(new HurtCamEffectEvent(partialTicks)); + && MinecraftForge.EVENT_BUS.post(new HurtCamEffectEvent(partialTicks)); } - - /** onSendingPacket */ + + /** + * onSendingPacket + */ public static final HookReporter HOOK_onSendingPacket = - newHookReporter() - .hook("onSendingPacket") - .dependsOn(TypesMc.Methods.NetworkManager_dispatchPacket) - .dependsOn(TypesMc.Methods.NetworkManager$4_run) - .forgeEvent(PacketEvent.Outgoing.Pre.class) - .build(); - + newHookReporter() + .hook("onSendingPacket") + .dependsOn(TypesMc.Methods.NetworkManager_dispatchPacket) + .dependsOn(TypesMc.Methods.NetworkManager$4_run) + .forgeEvent(PacketEvent.Outgoing.Pre.class) + .build(); + public static boolean onSendingPacket(Packet packet) { return HOOK_onSendingPacket.reportHook() - && MinecraftForge.EVENT_BUS.post(new PacketEvent.Outgoing.Pre(packet)); + && MinecraftForge.EVENT_BUS.post(new PacketEvent.Outgoing.Pre(packet)); } - - /** onSentPacket */ + + /** + * onSentPacket + */ public static final HookReporter HOOK_onSentPacket = - newHookReporter() - .hook("onSentPacket") - .dependsOn(TypesMc.Methods.NetworkManager_dispatchPacket) - .dependsOn(TypesMc.Methods.NetworkManager$4_run) - .forgeEvent(PacketEvent.Outgoing.Post.class) - .build(); - + newHookReporter() + .hook("onSentPacket") + .dependsOn(TypesMc.Methods.NetworkManager_dispatchPacket) + .dependsOn(TypesMc.Methods.NetworkManager$4_run) + .forgeEvent(PacketEvent.Outgoing.Post.class) + .build(); + public static void onSentPacket(Packet packet) { - if (HOOK_onSentPacket.reportHook()) + if (HOOK_onSentPacket.reportHook()) { MinecraftForge.EVENT_BUS.post(new PacketEvent.Outgoing.Post(packet)); + } } - - /** onPreReceived */ + + /** + * onPreReceived + */ public static final HookReporter HOOK_onPreReceived = - newHookReporter() - .hook("onPreReceived") - .dependsOn(TypesMc.Methods.NetworkManager_channelRead0) - .forgeEvent(PacketEvent.Incoming.Pre.class) - .build(); - + newHookReporter() + .hook("onPreReceived") + .dependsOn(TypesMc.Methods.NetworkManager_channelRead0) + .forgeEvent(PacketEvent.Incoming.Pre.class) + .build(); + public static boolean onPreReceived(Packet packet) { return HOOK_onPreReceived.reportHook() - && MinecraftForge.EVENT_BUS.post(new PacketEvent.Incoming.Pre(packet)); + && MinecraftForge.EVENT_BUS.post(new PacketEvent.Incoming.Pre(packet)); } - - /** onPostReceived */ + + /** + * onPostReceived + */ public static final HookReporter HOOK_onPostReceived = - newHookReporter() - .hook("onPostReceived") - .dependsOn(TypesMc.Methods.NetworkManager_channelRead0) - .forgeEvent(PacketEvent.Incoming.Post.class) - .build(); - + newHookReporter() + .hook("onPostReceived") + .dependsOn(TypesMc.Methods.NetworkManager_channelRead0) + .forgeEvent(PacketEvent.Incoming.Post.class) + .build(); + public static void onPostReceived(Packet packet) { - if (HOOK_onPostReceived.reportHook()) + if (HOOK_onPostReceived.reportHook()) { MinecraftForge.EVENT_BUS.post(new PacketEvent.Incoming.Post(packet)); + } } - - /** onWaterMovement */ + + /** + * onWaterMovement + */ public static final HookReporter HOOK_onWaterMovement = - newHookReporter() - .hook("onWaterMovement") - .dependsOn(TypesMc.Methods.World_handleMaterialAcceleration) - .forgeEvent(WaterMovementEvent.class) - .build(); - + newHookReporter() + .hook("onWaterMovement") + .dependsOn(TypesMc.Methods.World_handleMaterialAcceleration) + .forgeEvent(WaterMovementEvent.class) + .build(); + public static boolean onWaterMovement(Entity entity, Vec3d moveDir) { return HOOK_onWaterMovement.reportHook() - && MinecraftForge.EVENT_BUS.post(new WaterMovementEvent(entity, moveDir)); + && MinecraftForge.EVENT_BUS.post(new WaterMovementEvent(entity, moveDir)); } - - /** onApplyCollisionMotion */ + + /** + * onApplyCollisionMotion + */ public static final HookReporter HOOK_onApplyCollisionMotion = - newHookReporter() - .hook("onApplyCollisionMotion") - .dependsOn(TypesMc.Methods.Entity_applyEntityCollision) - .forgeEvent(ApplyCollisionMotionEvent.class) - .build(); - + newHookReporter() + .hook("onApplyCollisionMotion") + .dependsOn(TypesMc.Methods.Entity_applyEntityCollision) + .forgeEvent(ApplyCollisionMotionEvent.class) + .build(); + public static boolean onApplyCollisionMotion( - Entity entity, Entity collidedWithEntity, double x, double z) { + Entity entity, Entity collidedWithEntity, double x, double z) { return HOOK_onApplyCollisionMotion.reportHook() - && MinecraftForge.EVENT_BUS.post( - new ApplyCollisionMotionEvent(entity, collidedWithEntity, x, 0.D, z)); + && MinecraftForge.EVENT_BUS.post( + new ApplyCollisionMotionEvent(entity, collidedWithEntity, x, 0.D, z)); } - - /** onPutColorMultiplier */ + + /** + * onPutColorMultiplier + */ public static final HookReporter HOOK_onPutColorMultiplier = - newHookReporter() - .hook("onPutColorMultiplier") - .dependsOn(TypesMc.Methods.BufferBuilder_putColorMultiplier) - .build(); - + newHookReporter() + .hook("onPutColorMultiplier") + .dependsOn(TypesMc.Methods.BufferBuilder_putColorMultiplier) + .build(); + public static boolean SHOULD_UPDATE_ALPHA = false; public static float COLOR_MULTIPLIER_ALPHA = 150.f / 255.f; - + public static int onPutColorMultiplier(float r, float g, float b, int buffer, boolean[] flag) { flag[0] = SHOULD_UPDATE_ALPHA; if (HOOK_onPutColorMultiplier.reportHook() && SHOULD_UPDATE_ALPHA) { @@ -245,433 +313,517 @@ public static int onPutColorMultiplier(float r, float g, float b, int buffer, bo } return buffer; } - - /** onPreRenderBlockLayer */ + + /** + * onPreRenderBlockLayer + */ public static final HookReporter HOOK_onPreRenderBlockLayer = - newHookReporter() - .hook("onPreRenderBlockLayer") - .dependsOn(TypesMc.Methods.RenderGlobal_renderBlockLayer) - .forgeEvent(RenderBlockLayerEvent.Pre.class) - .build(); - + newHookReporter() + .hook("onPreRenderBlockLayer") + .dependsOn(TypesMc.Methods.RenderGlobal_renderBlockLayer) + .forgeEvent(RenderBlockLayerEvent.Pre.class) + .build(); + public static boolean onPreRenderBlockLayer(BlockRenderLayer layer, double partialTicks) { return HOOK_onPreRenderBlockLayer.reportHook() - && MinecraftForge.EVENT_BUS.post(new RenderBlockLayerEvent.Pre(layer, partialTicks)); + && MinecraftForge.EVENT_BUS.post(new RenderBlockLayerEvent.Pre(layer, partialTicks)); } - - /** onPostRenderBlockLayer */ + + /** + * onPostRenderBlockLayer + */ public static final HookReporter HOOK_onPostRenderBlockLayer = - newHookReporter() - .hook("onPostRenderBlockLayer") - .dependsOn(TypesMc.Methods.RenderGlobal_renderBlockLayer) - .forgeEvent(RenderBlockLayerEvent.Post.class) - .build(); - + newHookReporter() + .hook("onPostRenderBlockLayer") + .dependsOn(TypesMc.Methods.RenderGlobal_renderBlockLayer) + .forgeEvent(RenderBlockLayerEvent.Post.class) + .build(); + public static void onPostRenderBlockLayer(BlockRenderLayer layer, double partialTicks) { - if (HOOK_onPostRenderBlockLayer.reportHook()) + if (HOOK_onPostRenderBlockLayer.reportHook()) { MinecraftForge.EVENT_BUS.post(new RenderBlockLayerEvent.Post(layer, partialTicks)); + } } - - /** onSetupTerrain */ + + /** + * onSetupTerrain + */ public static final HookReporter HOOK_onSetupTerrain = - newHookReporter() - .hook("onSetupTerrain") - .dependsOn(TypesMc.Methods.RenderGlobal_setupTerrain) - .forgeEvent(SetupTerrainEvent.class) - .build(); - + newHookReporter() + .hook("onSetupTerrain") + .dependsOn(TypesMc.Methods.RenderGlobal_setupTerrain) + .forgeEvent(SetupTerrainEvent.class) + .build(); + public static boolean onSetupTerrain(Entity renderEntity, boolean playerSpectator) { if (HOOK_onSetupTerrain.reportHook()) { SetupTerrainEvent event = new SetupTerrainEvent(renderEntity, playerSpectator); MinecraftForge.EVENT_BUS.post(event); return event.isCulling(); - } else return playerSpectator; + } else { + return playerSpectator; + } } - - /** onComputeVisibility */ + + /** + * onComputeVisibility + */ public static final HookReporter HOOK_onComputeVisibility = - newHookReporter() - .hook("onComputeVisibility") - // no hook exists anymore - .forgeEvent(ComputeVisibilityEvent.class) - .build(); - + newHookReporter() + .hook("onComputeVisibility") + // no hook exists anymore + .forgeEvent(ComputeVisibilityEvent.class) + .build(); + @Deprecated public static void onComputeVisibility(VisGraph visGraph, SetVisibility setVisibility) { - if (HOOK_onComputeVisibility.reportHook()) + if (HOOK_onComputeVisibility.reportHook()) { MinecraftForge.EVENT_BUS.post(new ComputeVisibilityEvent(visGraph, setVisibility)); + } } - - /** onDoBlockCollisions */ + + /** + * onDoBlockCollisions + */ public static final HookReporter HOOK_onDoBlockCollisions = - newHookReporter() - .hook("onDoBlockCollisions") - // no hook exists anymore - .forgeEvent(DoBlockCollisionsEvent.class) - .build(); - + newHookReporter() + .hook("onDoBlockCollisions") + // no hook exists anymore + .forgeEvent(DoBlockCollisionsEvent.class) + .build(); + @Deprecated public static boolean onDoBlockCollisions(Entity entity, BlockPos pos, IBlockState state) { return HOOK_onDoBlockCollisions.reportHook() - && MinecraftForge.EVENT_BUS.post(new DoBlockCollisionsEvent(entity, pos, state)); + && MinecraftForge.EVENT_BUS.post(new DoBlockCollisionsEvent(entity, pos, state)); } - - /** isBlockFiltered */ + + /** + * isBlockFiltered + */ public static final HookReporter HOOK_isBlockFiltered = - newHookReporter() - .hook("isBlockFiltered") - .dependsOn(TypesMc.Methods.Entity_doBlockCollisions) - .build(); - + newHookReporter() + .hook("isBlockFiltered") + .dependsOn(TypesMc.Methods.Entity_doBlockCollisions) + .build(); + public static final Set> LIST_BLOCK_FILTER = Sets.newHashSet(); - + public static boolean isBlockFiltered(Entity entity, IBlockState state) { return HOOK_isBlockFiltered.reportHook() - && entity instanceof EntityPlayer - && LIST_BLOCK_FILTER.contains(state.getBlock().getClass()); + && entity instanceof EntityPlayer + && LIST_BLOCK_FILTER.contains(state.getBlock().getClass()); } - - /** onApplyClimbableBlockMovement */ + + /** + * onApplyClimbableBlockMovement + */ public static final HookReporter HOOK_onApplyClimbableBlockMovement = - newHookReporter() - .hook("onApplyClimbableBlockMovement") - // no hook exists - .forgeEvent(ApplyClimbableBlockMovement.class) - .build(); - + newHookReporter() + .hook("onApplyClimbableBlockMovement") + // no hook exists + .forgeEvent(ApplyClimbableBlockMovement.class) + .build(); + @Deprecated public static boolean onApplyClimbableBlockMovement(EntityLivingBase livingBase) { return HOOK_onApplyClimbableBlockMovement.reportHook() - && MinecraftForge.EVENT_BUS.post(new ApplyClimbableBlockMovement(livingBase)); + && MinecraftForge.EVENT_BUS.post(new ApplyClimbableBlockMovement(livingBase)); } - - /** onRenderBlockInLayer */ + + /** + * onRenderBlockInLayer + */ public static final HookReporter HOOK_onRenderBlockInLayer = - newHookReporter() - .hook("onRenderBlockInLayer") - .dependsOn(TypesMc.Methods.Block_canRenderInLayer) - .forgeEvent(RenderBlockInLayerEvent.class) - .build(); - + newHookReporter() + .hook("onRenderBlockInLayer") + .dependsOn(TypesMc.Methods.Block_canRenderInLayer) + .forgeEvent(RenderBlockInLayerEvent.class) + .build(); + public static BlockRenderLayer onRenderBlockInLayer( - Block block, IBlockState state, BlockRenderLayer layer, BlockRenderLayer compareToLayer) { + Block block, IBlockState state, BlockRenderLayer layer, BlockRenderLayer compareToLayer) { if (HOOK_onRenderBlockInLayer.reportHook()) { RenderBlockInLayerEvent event = - new RenderBlockInLayerEvent(block, state, layer, compareToLayer); + new RenderBlockInLayerEvent(block, state, layer, compareToLayer); MinecraftForge.EVENT_BUS.post(event); return event.getLayer(); - } else return layer; + } else { + return layer; + } } - - /** onBlockRender */ + + /** + * onBlockRender + */ public static final HookReporter HOOK_onBlockRender = - newHookReporter() - .hook("onBlockRender") - // no hook exists - .forgeEvent(BlockRenderEvent.class) - .build(); - + newHookReporter() + .hook("onBlockRender") + // no hook exists + .forgeEvent(BlockRenderEvent.class) + .build(); + @Deprecated public static void onBlockRender( - BlockPos pos, IBlockState state, IBlockAccess access, BufferBuilder buffer) { - if (HOOK_onBlockRender.reportHook()) + BlockPos pos, IBlockState state, IBlockAccess access, BufferBuilder buffer) { + if (HOOK_onBlockRender.reportHook()) { MinecraftForge.EVENT_BUS.post(new BlockRenderEvent(pos, state, access, buffer)); + } } - - /** onAddCollisionBoxToList */ + + /** + * onAddCollisionBoxToList + */ public static final HookReporter HOOK_onAddCollisionBoxToList = - newHookReporter() - .hook("onAddCollisionBoxToList") - .dependsOn(TypesMc.Methods.Block_addCollisionBoxToList) - .forgeEvent(AddCollisionBoxToListEvent.class) - .build(); - + newHookReporter() + .hook("onAddCollisionBoxToList") + .dependsOn(TypesMc.Methods.Block_addCollisionBoxToList) + .forgeEvent(AddCollisionBoxToListEvent.class) + .build(); + public static boolean onAddCollisionBoxToList( - Block block, - IBlockState state, - World worldIn, - BlockPos pos, - AxisAlignedBB entityBox, - List collidingBoxes, - Entity entityIn, - boolean bool) { + Block block, + IBlockState state, + World worldIn, + BlockPos pos, + AxisAlignedBB entityBox, + List collidingBoxes, + Entity entityIn, + boolean bool) { return HOOK_onAddCollisionBoxToList.reportHook() - && MinecraftForge.EVENT_BUS.post( - new AddCollisionBoxToListEvent( - block, state, worldIn, pos, entityBox, collidingBoxes, entityIn, bool)); - } - - /** onBlockRenderInLoop */ + && MinecraftForge.EVENT_BUS.post( + new AddCollisionBoxToListEvent( + block, state, worldIn, pos, entityBox, collidingBoxes, entityIn, bool)); + } + + /** + * onBlockRenderInLoop + */ public static final HookReporter HOOK_onBlockRenderInLoop = - newHookReporter() - .hook("onBlockRenderInLoop") - .dependsOn(TypesMc.Methods.RenderChunk_rebuildChunk) - .listenerEvent(BlockModelRenderListener.class) - .build(); - + newHookReporter() + .hook("onBlockRenderInLoop") + .dependsOn(TypesMc.Methods.RenderChunk_rebuildChunk) + .listenerEvent(BlockModelRenderListener.class) + .build(); + public static void onBlockRenderInLoop( - RenderChunk renderChunk, Block block, IBlockState state, BlockPos pos) { + RenderChunk renderChunk, Block block, IBlockState state, BlockPos pos) { // faster hook - if (HOOK_onBlockRenderInLoop.reportHook()) - for (BlockModelRenderListener listener : Listeners.BLOCK_MODEL_RENDER_LISTENER.getAll()) + if (HOOK_onBlockRenderInLoop.reportHook()) { + for (BlockModelRenderListener listener : Listeners.BLOCK_MODEL_RENDER_LISTENER.getAll()) { listener.onBlockRenderInLoop(renderChunk, block, state, pos); + } + } } - - /** onPreBuildChunk */ + + /** + * onPreBuildChunk + */ public static final HookReporter HOOK_onPreBuildChunk = - newHookReporter() - .hook("onPreBuildChunk") - .dependsOn(TypesMc.Methods.RenderChunk_rebuildChunk) - .forgeEvent(BuildChunkEvent.Pre.class) - .build(); - + newHookReporter() + .hook("onPreBuildChunk") + .dependsOn(TypesMc.Methods.RenderChunk_rebuildChunk) + .forgeEvent(BuildChunkEvent.Pre.class) + .build(); + public static void onPreBuildChunk(RenderChunk renderChunk) { - if (HOOK_onPreBuildChunk.reportHook()) + if (HOOK_onPreBuildChunk.reportHook()) { MinecraftForge.EVENT_BUS.post(new BuildChunkEvent.Pre(renderChunk)); + } } - - /** onPostBuildChunk */ + + /** + * onPostBuildChunk + */ public static final HookReporter HOOK_onPostBuildChunk = - newHookReporter() - .hook("onPostBuildChunk") - .dependsOn(TypesMc.Methods.RenderChunk_rebuildChunk) - .forgeEvent(BuildChunkEvent.Post.class) - .build(); - + newHookReporter() + .hook("onPostBuildChunk") + .dependsOn(TypesMc.Methods.RenderChunk_rebuildChunk) + .forgeEvent(BuildChunkEvent.Post.class) + .build(); + public static void onPostBuildChunk(RenderChunk renderChunk) { // i couldn't place a post block render hook within the if label so I have to do this - if (HOOK_onPostBuildChunk.reportHook()) + if (HOOK_onPostBuildChunk.reportHook()) { MinecraftForge.EVENT_BUS.post(new BuildChunkEvent.Post(renderChunk)); + } } - - /** onDeleteGlResources */ + + /** + * onDeleteGlResources + */ public static final HookReporter HOOK_onDeleteGlResources = - newHookReporter() - .hook("onDeleteGlResources") - .dependsOn(TypesMc.Methods.RenderChunk_deleteGlResources) - .forgeEvent(DeleteGlResourcesEvent.class) - .build(); - + newHookReporter() + .hook("onDeleteGlResources") + .dependsOn(TypesMc.Methods.RenderChunk_deleteGlResources) + .forgeEvent(DeleteGlResourcesEvent.class) + .build(); + public static void onDeleteGlResources(RenderChunk renderChunk) { - if (HOOK_onDeleteGlResources.reportHook()) + if (HOOK_onDeleteGlResources.reportHook()) { MinecraftForge.EVENT_BUS.post(new DeleteGlResourcesEvent(renderChunk)); + } } - - /** onAddRenderChunk */ + + /** + * onAddRenderChunk + */ public static final HookReporter HOOK_onAddRenderChunk = - newHookReporter() - .hook("onAddRenderChunk") - .dependsOn(TypesMc.Methods.ChunkRenderContainer_addRenderChunk) - .forgeEvent(AddRenderChunkEvent.class) - .build(); - + newHookReporter() + .hook("onAddRenderChunk") + .dependsOn(TypesMc.Methods.ChunkRenderContainer_addRenderChunk) + .forgeEvent(AddRenderChunkEvent.class) + .build(); + public static void onAddRenderChunk(RenderChunk renderChunk, BlockRenderLayer layer) { - if (HOOK_onAddRenderChunk.reportHook()) + if (HOOK_onAddRenderChunk.reportHook()) { MinecraftForge.EVENT_BUS.post(new AddRenderChunkEvent(renderChunk, layer)); + } } - - /** onChunkUploaded */ + + /** + * onChunkUploaded + */ public static final HookReporter HOOK_onChunkUploaded = - newHookReporter() - .hook("onChunkUploaded") - .dependsOn(TypesMc.Methods.ChunkRenderDispatcher_uploadChunk) - .forgeEvent(ChunkUploadedEvent.class) - .build(); - + newHookReporter() + .hook("onChunkUploaded") + .dependsOn(TypesMc.Methods.ChunkRenderDispatcher_uploadChunk) + .forgeEvent(ChunkUploadedEvent.class) + .build(); + public static void onChunkUploaded(RenderChunk chunk, BufferBuilder buffer) { - if (HOOK_onChunkUploaded.reportHook()) + if (HOOK_onChunkUploaded.reportHook()) { MinecraftForge.EVENT_BUS.post(new ChunkUploadedEvent(chunk, buffer)); + } } - - /** onLoadRenderers */ + + /** + * onLoadRenderers + */ public static final HookReporter HOOK_onLoadRenderers = - newHookReporter() - .hook("onLoadRenderers") - .dependsOn(TypesMc.Methods.RenderGlobal_loadRenderers) - .forgeEvent(LoadRenderersEvent.class) - .build(); - + newHookReporter() + .hook("onLoadRenderers") + .dependsOn(TypesMc.Methods.RenderGlobal_loadRenderers) + .forgeEvent(LoadRenderersEvent.class) + .build(); + public static void onLoadRenderers( - ViewFrustum viewFrustum, ChunkRenderDispatcher renderDispatcher) { - if (HOOK_onLoadRenderers.reportHook()) + ViewFrustum viewFrustum, ChunkRenderDispatcher renderDispatcher) { + if (HOOK_onLoadRenderers.reportHook()) { MinecraftForge.EVENT_BUS.post(new LoadRenderersEvent(viewFrustum, renderDispatcher)); + } } - - /** onWorldRendererDeallocated */ + + /** + * onWorldRendererDeallocated + */ public static final HookReporter HOOK_onWorldRendererDeallocated = - newHookReporter() - .hook("onWorldRendererDeallocated") - .dependsOn(TypesMc.Methods.ChunkRenderWorker_freeRenderBuilder) - .forgeEvent(WorldRendererDeallocatedEvent.class) - .build(); - + newHookReporter() + .hook("onWorldRendererDeallocated") + .dependsOn(TypesMc.Methods.ChunkRenderWorker_freeRenderBuilder) + .forgeEvent(WorldRendererDeallocatedEvent.class) + .build(); + public static void onWorldRendererDeallocated(ChunkCompileTaskGenerator generator) { - if (HOOK_onWorldRendererDeallocated.reportHook()) + if (HOOK_onWorldRendererDeallocated.reportHook()) { MinecraftForge.EVENT_BUS.post( - new WorldRendererDeallocatedEvent(generator, generator.getRenderChunk())); + new WorldRendererDeallocatedEvent(generator, generator.getRenderChunk())); + } } - - /** shouldDisableCaveCulling */ + + /** + * shouldDisableCaveCulling + */ public static final HookReporter HOOK_shouldDisableCaveCulling = - newHookReporter() - .hook("shouldDisableCaveCulling") - .dependsOn(TypesMc.Methods.RenderGlobal_setupTerrain) - .dependsOn(TypesMc.Methods.VisGraph_setOpaqueCube) - .dependsOn(TypesMc.Methods.VisGraph_computeVisibility) - .build(); - + newHookReporter() + .hook("shouldDisableCaveCulling") + .dependsOn(TypesMc.Methods.RenderGlobal_setupTerrain) + .dependsOn(TypesMc.Methods.VisGraph_setOpaqueCube) + .dependsOn(TypesMc.Methods.VisGraph_computeVisibility) + .build(); + public static final MultiBoolean SHOULD_DISABLE_CAVE_CULLING = new MultiBoolean(); - + public static boolean shouldDisableCaveCulling() { return HOOK_shouldDisableCaveCulling.reportHook() && SHOULD_DISABLE_CAVE_CULLING.isEnabled(); } - - /** onUpdateWalkingPlayerPre */ + + /** + * onUpdateWalkingPlayerPre + */ public static final HookReporter HOOK_onUpdateWalkingPlayerPre = - newHookReporter() - .hook("onUpdateWalkingPlayerPre") - .dependsOn(TypesMc.Methods.EntityPlayerSP_onUpdateWalkingPlayer) - .forgeEvent(LocalPlayerUpdateMovementEvent.Pre.class) - .build(); - + newHookReporter() + .hook("onUpdateWalkingPlayerPre") + .dependsOn(TypesMc.Methods.EntityPlayerSP_onUpdateWalkingPlayer) + .forgeEvent(LocalPlayerUpdateMovementEvent.Pre.class) + .build(); + public static boolean onUpdateWalkingPlayerPre(EntityPlayerSP localPlayer) { return HOOK_onUpdateWalkingPlayerPre.reportHook() - && MinecraftForge.EVENT_BUS.post(new LocalPlayerUpdateMovementEvent.Pre(localPlayer)); + && MinecraftForge.EVENT_BUS.post(new LocalPlayerUpdateMovementEvent.Pre(localPlayer)); } - - /** onUpdateWalkingPlayerPost */ + + /** + * onUpdateWalkingPlayerPost + */ public static final HookReporter HOOK_onUpdateWalkingPlayerPost = - newHookReporter() - .hook("onUpdateWalkingPlayerPost") - .dependsOn(TypesMc.Methods.EntityPlayerSP_onUpdateWalkingPlayer) - .forgeEvent(LocalPlayerUpdateMovementEvent.Post.class) - .build(); - + newHookReporter() + .hook("onUpdateWalkingPlayerPost") + .dependsOn(TypesMc.Methods.EntityPlayerSP_onUpdateWalkingPlayer) + .forgeEvent(LocalPlayerUpdateMovementEvent.Post.class) + .build(); + public static void onUpdateWalkingPlayerPost(EntityPlayerSP localPlayer) { - if (HOOK_onUpdateWalkingPlayerPost.reportHook()) + if (HOOK_onUpdateWalkingPlayerPost.reportHook()) { MinecraftForge.EVENT_BUS.post(new LocalPlayerUpdateMovementEvent.Post(localPlayer)); + } } - - /** onWorldCheckLightFor */ + + /** + * onWorldCheckLightFor + */ public static final HookReporter HOOK_onWorldCheckLightFor = - newHookReporter() - .hook("onWorldCheckLightFor") - .dependsOn(TypesMc.Methods.World_checkLightFor) - .forgeEvent(WorldCheckLightForEvent.class) - .build(); - + newHookReporter() + .hook("onWorldCheckLightFor") + .dependsOn(TypesMc.Methods.World_checkLightFor) + .forgeEvent(WorldCheckLightForEvent.class) + .build(); + public static boolean onWorldCheckLightFor(EnumSkyBlock enumSkyBlock, BlockPos pos) { return HOOK_onWorldCheckLightFor.reportHook() - && MinecraftForge.EVENT_BUS.post(new WorldCheckLightForEvent(enumSkyBlock, pos)); + && MinecraftForge.EVENT_BUS.post(new WorldCheckLightForEvent(enumSkyBlock, pos)); } - - /** onLeftClickCounterSet */ + + /** + * onLeftClickCounterSet + */ public static final HookReporter HOOK_onLeftClickCounterSet = - newHookReporter() - .hook("onLeftClickCounterSet") - .dependsOn(TypesMc.Methods.Minecraft_runTick) - .dependsOn(TypesMc.Methods.Minecraft_setIngameFocus) - .forgeEvent(LeftClickCounterUpdateEvent.class) - .build(); - + newHookReporter() + .hook("onLeftClickCounterSet") + .dependsOn(TypesMc.Methods.Minecraft_runTick) + .dependsOn(TypesMc.Methods.Minecraft_setIngameFocus) + .forgeEvent(LeftClickCounterUpdateEvent.class) + .build(); + public static int onLeftClickCounterSet(int value, Minecraft minecraft) { if (HOOK_onLeftClickCounterSet.reportHook()) { LeftClickCounterUpdateEvent event = new LeftClickCounterUpdateEvent(minecraft, value); return MinecraftForge.EVENT_BUS.post(event) ? event.getCurrentValue() : event.getValue(); - } else return value; + } else { + return value; + } } - - /** onSendClickBlockToController */ + + /** + * onSendClickBlockToController + */ public static final HookReporter HOOK_onSendClickBlockToController = - newHookReporter() - .hook("onSendClickBlockToController") - .dependsOn(TypesMc.Methods.Minecraft_runTick) - .forgeEvent(BlockControllerProcessEvent.class) - .build(); - + newHookReporter() + .hook("onSendClickBlockToController") + .dependsOn(TypesMc.Methods.Minecraft_runTick) + .forgeEvent(BlockControllerProcessEvent.class) + .build(); + public static boolean onSendClickBlockToController(Minecraft minecraft, boolean clicked) { if (HOOK_onSendClickBlockToController.reportHook()) { BlockControllerProcessEvent event = new BlockControllerProcessEvent(minecraft, clicked); MinecraftForge.EVENT_BUS.post(event); return event.isLeftClicked(); - } else return clicked; + } else { + return clicked; + } } - - /** onPlayerItemSync */ + + /** + * onPlayerItemSync + */ public static final HookReporter HOOK_onPlayerItemSync = - newHookReporter() - .hook("onPlayerItemSync") - .dependsOn(Methods.PlayerControllerMC_syncCurrentPlayItem) - .forgeEvent(PlayerSyncItemEvent.class) - .build(); - + newHookReporter() + .hook("onPlayerItemSync") + .dependsOn(Methods.PlayerControllerMC_syncCurrentPlayItem) + .forgeEvent(PlayerSyncItemEvent.class) + .build(); + public static void onPlayerItemSync(PlayerControllerMP playerControllerMP) { - if (HOOK_onPlayerItemSync.reportHook()) + if (HOOK_onPlayerItemSync.reportHook()) { MinecraftForge.EVENT_BUS.post(new PlayerSyncItemEvent(playerControllerMP)); + } } - - /** onPlayerBreakingBlock */ + + /** + * onPlayerBreakingBlock + */ public static final HookReporter HOOK_onPlayerBreakingBlock = - newHookReporter() - .hook("onPlayerBreakingBlock") - .dependsOn(Methods.PlayerControllerMC_onPlayerDamageBlock) - .forgeEvent(PlayerDamageBlockEvent.class) - .build(); - + newHookReporter() + .hook("onPlayerBreakingBlock") + .dependsOn(Methods.PlayerControllerMC_onPlayerDamageBlock) + .forgeEvent(PlayerDamageBlockEvent.class) + .build(); + public static void onPlayerBreakingBlock( - PlayerControllerMP playerControllerMP, BlockPos pos, EnumFacing facing) { - if (HOOK_onPlayerBreakingBlock.reportHook()) + PlayerControllerMP playerControllerMP, BlockPos pos, EnumFacing facing) { + if (HOOK_onPlayerBreakingBlock.reportHook()) { MinecraftForge.EVENT_BUS.post(new PlayerDamageBlockEvent(playerControllerMP, pos, facing)); + } } - - /** onPlayerAttackEntity */ + + /** + * onPlayerAttackEntity + */ public static final HookReporter HOOK_onPlayerAttackEntity = - newHookReporter() - .hook("onPlayerAttackEntity") - .dependsOn(Methods.PlayerControllerMC_attackEntity) - .forgeEvent(PlayerAttackEntityEvent.class) - .build(); - + newHookReporter() + .hook("onPlayerAttackEntity") + .dependsOn(Methods.PlayerControllerMC_attackEntity) + .forgeEvent(PlayerAttackEntityEvent.class) + .build(); + public static void onPlayerAttackEntity( - PlayerControllerMP playerControllerMP, EntityPlayer attacker, Entity victim) { - if (HOOK_onPlayerAttackEntity.reportHook()) + PlayerControllerMP playerControllerMP, EntityPlayer attacker, Entity victim) { + if (HOOK_onPlayerAttackEntity.reportHook()) { MinecraftForge.EVENT_BUS.post( - new PlayerAttackEntityEvent(playerControllerMP, attacker, victim)); + new PlayerAttackEntityEvent(playerControllerMP, attacker, victim)); + } } - - /** onPlayerStopUse */ + + /** + * onPlayerStopUse + */ public static final HookReporter HOOK_onPlayerStopUse = - newHookReporter() - .hook("onPlayerStopUse") - .dependsOn(Methods.PlayerControllerMC_onStoppedUsingItem) - .forgeEvent(ItemStoppedUsedEvent.class) - .build(); - + newHookReporter() + .hook("onPlayerStopUse") + .dependsOn(Methods.PlayerControllerMC_onStoppedUsingItem) + .forgeEvent(ItemStoppedUsedEvent.class) + .build(); + public static boolean onPlayerStopUse( - PlayerControllerMP playerControllerMP, EntityPlayer player) { + PlayerControllerMP playerControllerMP, EntityPlayer player) { return HOOK_onPlayerStopUse.reportHook() - && MinecraftForge.EVENT_BUS.post(new ItemStoppedUsedEvent(playerControllerMP, player)); + && MinecraftForge.EVENT_BUS.post(new ItemStoppedUsedEvent(playerControllerMP, player)); } - - /** onPlayerStopUse */ + + /** + * onPlayerStopUse + */ public static final HookReporter HOOK_onEntityBlockSlipApply = - newHookReporter() - .hook("onEntityBlockSlipApply") - .dependsOn(Methods.PlayerControllerMC_onStoppedUsingItem) - .forgeEvent(EntityBlockSlipApplyEvent.class) - .build(); - + newHookReporter() + .hook("onEntityBlockSlipApply") + .dependsOn(Methods.PlayerControllerMC_onStoppedUsingItem) + .forgeEvent(EntityBlockSlipApplyEvent.class) + .build(); + public static float onEntityBlockSlipApply( - float defaultSlipperiness, - EntityLivingBase entityLivingBase, - IBlockState blockStateUnder, - int stage) { + float defaultSlipperiness, + EntityLivingBase entityLivingBase, + IBlockState blockStateUnder, + int stage) { if (HOOK_onEntityBlockSlipApply.reportHook()) { EntityBlockSlipApplyEvent event = - new EntityBlockSlipApplyEvent( - Stage.values()[stage], entityLivingBase, blockStateUnder, defaultSlipperiness); + new EntityBlockSlipApplyEvent( + Stage.values()[stage], entityLivingBase, blockStateUnder, defaultSlipperiness); MinecraftForge.EVENT_BUS.post(event); return event.getSlipperiness(); - } else return defaultSlipperiness; + } else { + return defaultSlipperiness; + } } } diff --git a/src/main/java/com/matt/forgehax/asm/ForgeHaxTransformer.java b/src/main/java/com/matt/forgehax/asm/ForgeHaxTransformer.java index 7238607b3..9d2730c70 100644 --- a/src/main/java/com/matt/forgehax/asm/ForgeHaxTransformer.java +++ b/src/main/java/com/matt/forgehax/asm/ForgeHaxTransformer.java @@ -1,8 +1,28 @@ package com.matt.forgehax.asm; import com.matt.forgehax.asm.TypesMc.Classes; -import com.matt.forgehax.asm.patches.*; -import com.matt.forgehax.asm.patches.special.*; +import com.matt.forgehax.asm.patches.BlockPatch; +import com.matt.forgehax.asm.patches.BoatPatch; +import com.matt.forgehax.asm.patches.BufferBuilderPatch; +import com.matt.forgehax.asm.patches.ChunkRenderContainerPatch; +import com.matt.forgehax.asm.patches.ChunkRenderDispatcherPatch; +import com.matt.forgehax.asm.patches.ChunkRenderWorkerPatch; +import com.matt.forgehax.asm.patches.EntityLivingBasePatch; +import com.matt.forgehax.asm.patches.EntityPatch; +import com.matt.forgehax.asm.patches.EntityPlayerSPPatch; +import com.matt.forgehax.asm.patches.EntityRendererPatch; +import com.matt.forgehax.asm.patches.KeyBindingPatch; +import com.matt.forgehax.asm.patches.MinecraftPatch; +import com.matt.forgehax.asm.patches.NetManager$4Patch; +import com.matt.forgehax.asm.patches.NetManagerPatch; +import com.matt.forgehax.asm.patches.PlayerControllerMCPatch; +import com.matt.forgehax.asm.patches.PlayerTabOverlayPatch; +import com.matt.forgehax.asm.patches.RenderBoatPatch; +import com.matt.forgehax.asm.patches.RenderChunkPatch; +import com.matt.forgehax.asm.patches.RenderGlobalPatch; +import com.matt.forgehax.asm.patches.VisGraphPatch; +import com.matt.forgehax.asm.patches.WorldPatch; +import com.matt.forgehax.asm.patches.special.SchematicPrinterPatch; import com.matt.forgehax.asm.utils.ASMStackLogger; import com.matt.forgehax.asm.utils.transforming.ClassTransformer; import java.lang.reflect.Field; @@ -19,6 +39,7 @@ @IFMLLoadingPlugin.SortingIndex(1001) public class ForgeHaxTransformer implements IClassTransformer, ASMCommon { + private HashMap transformingClasses = new HashMap<>(); private int transformingLevel = 0; @@ -58,11 +79,11 @@ public ForgeHaxTransformer() { } catch (MixinMissingException e) { LOGGER.info("Mixin not detected running, skipped adding transformer exclusions"); } catch (NullPointerException - | ClassNotFoundException - | NoSuchFieldException - | IllegalAccessException - | NoSuchMethodException - | InvocationTargetException e) { + | ClassNotFoundException + | NoSuchFieldException + | IllegalAccessException + | NoSuchMethodException + | InvocationTargetException e) { LOGGER.info("Failed to add ForgeHax transformer exclusion into Mixin environment"); ASMStackLogger.printStackTrace(e); } @@ -74,8 +95,9 @@ private void registerTransformer(ClassTransformer transformer) { @Override public byte[] transform(String name, String realName, byte[] bytes) { - if (transformingLevel > 0) + if (transformingLevel > 0) { LOGGER.warn("Reentrant class loaded {} at level {}", realName, transformingLevel); + } ++transformingLevel; if (transformingClasses.containsKey(realName)) { @@ -90,7 +112,7 @@ public byte[] transform(String name, String realName, byte[] bytes) { transformer.transform(classNode); ClassWriter classWriter = - new NoClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + new NoClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); classNode.accept(classWriter); @@ -100,11 +122,11 @@ public byte[] transform(String name, String realName, byte[] bytes) { bytes = classWriter.toByteArray(); } catch (Exception e) { LOGGER.error( - e.getClass().getSimpleName() - + " thrown from transforming class " - + realName - + ": " - + e.getMessage()); + e.getClass().getSimpleName() + + " thrown from transforming class " + + realName + + ": " + + e.getMessage()); ASMStackLogger.printStackTrace(e); } } @@ -114,12 +136,13 @@ public byte[] transform(String name, String realName, byte[] bytes) { } /** - * This will prevent Mixin from feeding our transformer meta class data which it may later discard + * This will prevent Mixin from feeding our transformer meta class data which it may later + * discard */ private static int addExcludedTransformersToMixin(String... excludedTransformers) - throws MixinMissingException, NullPointerException, ClassNotFoundException, - NoSuchFieldException, IllegalAccessException, NoSuchMethodException, - InvocationTargetException { + throws MixinMissingException, NullPointerException, ClassNotFoundException, + NoSuchFieldException, IllegalAccessException, NoSuchMethodException, + InvocationTargetException { // get the MixinEnvironment class Class class_MixinEnvironment; try { @@ -131,12 +154,12 @@ private static int addExcludedTransformersToMixin(String... excludedTransformers int count = 0; Method method_addTransformerExclusion = - class_MixinEnvironment.getDeclaredMethod("addTransformerExclusion", String.class); + class_MixinEnvironment.getDeclaredMethod("addTransformerExclusion", String.class); method_addTransformerExclusion.setAccessible(true); // get the environment phase subclass Class class_MixinEnvironment$Phase = - Class.forName("org.spongepowered.asm.mixin.MixinEnvironment$Phase"); + Class.forName("org.spongepowered.asm.mixin.MixinEnvironment$Phase"); // get the phases field Field field_phases = class_MixinEnvironment$Phase.getDeclaredField("phases"); @@ -171,17 +194,22 @@ private static int addExcludedTransformersToMixin(String... excludedTransformers } private class NoClassLoadingClassWriter extends ClassWriter { + NoClassLoadingClassWriter(int flags) { super(flags); } @Override protected String getCommonSuperClass(String type1, String type2) { - if (type1.matches(Classes.GuiMainMenu.getRuntimeInternalName())) + if (type1.matches(Classes.GuiMainMenu.getRuntimeInternalName())) { return Classes.GuiScreen.getRuntimeInternalName(); // stupid edge case - else return "java/lang/Object"; // credits to popbob + } else { + return "java/lang/Object"; // credits to popbob + } } } - - private static class MixinMissingException extends Exception {} + + private static class MixinMissingException extends Exception { + + } } diff --git a/src/main/java/com/matt/forgehax/asm/TypesHook.java b/src/main/java/com/matt/forgehax/asm/TypesHook.java index 2dec9adc3..60e0688dc 100644 --- a/src/main/java/com/matt/forgehax/asm/TypesHook.java +++ b/src/main/java/com/matt/forgehax/asm/TypesHook.java @@ -1,6 +1,5 @@ package com.matt.forgehax.asm; -import com.matt.forgehax.asm.TypesMc.Classes; import com.matt.forgehax.asm.utils.asmtype.ASMClass; import com.matt.forgehax.asm.utils.asmtype.ASMField; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -8,458 +7,464 @@ import java.util.List; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public interface TypesHook { + interface Classes { + ASMClass ForgeHaxHooks = - ASMBuilders.newClassBuilder().setClassName("com/matt/forgehax/asm/ForgeHaxHooks").build(); + ASMBuilders.newClassBuilder().setClassName("com/matt/forgehax/asm/ForgeHaxHooks").build(); } - + interface Fields { + ASMField ForgeHaxHooks_isSafeWalkActivated = - Classes.ForgeHaxHooks.childField() - .setName("isSafeWalkActivated") - .setType(boolean.class) - .build(); - + Classes.ForgeHaxHooks.childField() + .setName("isSafeWalkActivated") + .setType(boolean.class) + .build(); + ASMField ForgeHaxHooks_isNoSlowDownActivated = - Classes.ForgeHaxHooks.childField() - .setName("isNoSlowDownActivated") - .setType(boolean.class) - .build(); - + Classes.ForgeHaxHooks.childField() + .setName("isNoSlowDownActivated") + .setType(boolean.class) + .build(); + ASMField ForgeHaxHooks_isNoBoatGravityActivated = - Classes.ForgeHaxHooks.childField() - .setName("isNoBoatGravityActivated") - .setType(boolean.class) - .build(); - + Classes.ForgeHaxHooks.childField() + .setName("isNoBoatGravityActivated") + .setType(boolean.class) + .build(); + ASMField ForgeHaxHooks_isNoClampingActivated = - Classes.ForgeHaxHooks.childField() - .setName("isNoClampingActivated") - .setType(boolean.class) - .build(); - + Classes.ForgeHaxHooks.childField() + .setName("isNoClampingActivated") + .setType(boolean.class) + .build(); + ASMField ForgeHaxHooks_isBoatSetYawActivated = - Classes.ForgeHaxHooks.childField() - .setName("isBoatSetYawActivated") - .setType(boolean.class) - .build(); - + Classes.ForgeHaxHooks.childField() + .setName("isBoatSetYawActivated") + .setType(boolean.class) + .build(); + ASMField ForgeHaxHooks_isNotRowingBoatActivated = - Classes.ForgeHaxHooks.childField() - .setName("isNotRowingBoatActivated") - .setType(boolean.class) - .build(); - + Classes.ForgeHaxHooks.childField() + .setName("isNotRowingBoatActivated") + .setType(boolean.class) + .build(); + ASMField ForgeHaxHooks_doIncreaseTabListSize = - Classes.ForgeHaxHooks.childField() - .setName("doIncreaseTabListSize") - .setType(boolean.class) - .build(); + Classes.ForgeHaxHooks.childField() + .setName("doIncreaseTabListSize") + .setType(boolean.class) + .build(); } - + interface Methods { + ASMMethod ForgeHaxHooks_onHurtcamEffect = - Classes.ForgeHaxHooks.childMethod() - .setName("onHurtcamEffect") - .setReturnType(boolean.class) - .beginParameters() - .add(float.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onHurtcamEffect") + .setReturnType(boolean.class) + .beginParameters() + .add(float.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onSendingPacket = - Classes.ForgeHaxHooks.childMethod() - .setName("onSendingPacket") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.Packet) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onSendingPacket") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.Packet) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onSentPacket = - Classes.ForgeHaxHooks.childMethod() - .setName("onSentPacket") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.Packet) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onSentPacket") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.Packet) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPreReceived = - Classes.ForgeHaxHooks.childMethod() - .setName("onPreReceived") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.Packet) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPreReceived") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.Packet) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPostReceived = - Classes.ForgeHaxHooks.childMethod() - .setName("onPostReceived") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.Packet) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPostReceived") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.Packet) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onWaterMovement = - Classes.ForgeHaxHooks.childMethod() - .setName("onWaterMovement") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.Entity) - .add(TypesMc.Classes.Vec3d) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onWaterMovement") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.Entity) + .add(TypesMc.Classes.Vec3d) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onApplyCollisionMotion = - Classes.ForgeHaxHooks.childMethod() - .setName("onApplyCollisionMotion") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.Entity) - .add(TypesMc.Classes.Entity) - .add(double.class) - .add(double.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onApplyCollisionMotion") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.Entity) + .add(TypesMc.Classes.Entity) + .add(double.class) + .add(double.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPutColorMultiplier = - Classes.ForgeHaxHooks.childMethod() - .setName("onPutColorMultiplier") - .setReturnType(int.class) - .beginParameters() - .add(float.class) - .add(float.class) - .add(float.class) - .add(int.class) - .add(boolean[].class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPutColorMultiplier") + .setReturnType(int.class) + .beginParameters() + .add(float.class) + .add(float.class) + .add(float.class) + .add(int.class) + .add(boolean[].class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPreRenderBlockLayer = - Classes.ForgeHaxHooks.childMethod() - .setName("onPreRenderBlockLayer") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.BlockRenderLayer) - .add(double.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPreRenderBlockLayer") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.BlockRenderLayer) + .add(double.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPostRenderBlockLayer = - Classes.ForgeHaxHooks.childMethod() - .setName("onPostRenderBlockLayer") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.BlockRenderLayer) - .add(double.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPostRenderBlockLayer") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.BlockRenderLayer) + .add(double.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onRenderBlockInLayer = - Classes.ForgeHaxHooks.childMethod() - .setName("onRenderBlockInLayer") - .setReturnType(TypesMc.Classes.BlockRenderLayer) - .beginParameters() - .add(TypesMc.Classes.Block) - .add(TypesMc.Classes.IBlockState) - .add(TypesMc.Classes.BlockRenderLayer) - .add(TypesMc.Classes.BlockRenderLayer) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onRenderBlockInLayer") + .setReturnType(TypesMc.Classes.BlockRenderLayer) + .beginParameters() + .add(TypesMc.Classes.Block) + .add(TypesMc.Classes.IBlockState) + .add(TypesMc.Classes.BlockRenderLayer) + .add(TypesMc.Classes.BlockRenderLayer) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onSetupTerrain = - Classes.ForgeHaxHooks.childMethod() - .setName("onSetupTerrain") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.Entity) - .add(boolean.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onSetupTerrain") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.Entity) + .add(boolean.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_isBlockFiltered = - Classes.ForgeHaxHooks.childMethod() - .setName("isBlockFiltered") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.Entity) - .add(TypesMc.Classes.IBlockState) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("isBlockFiltered") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.Entity) + .add(TypesMc.Classes.IBlockState) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onAddCollisionBoxToList = - Classes.ForgeHaxHooks.childMethod() - .setName("onAddCollisionBoxToList") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.Block) - .add(TypesMc.Classes.IBlockState) - .add(TypesMc.Classes.World) - .add(TypesMc.Classes.BlockPos) - .add(TypesMc.Classes.AxisAlignedBB) - .add(List.class) - .add(TypesMc.Classes.Entity) - .add(boolean.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onAddCollisionBoxToList") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.Block) + .add(TypesMc.Classes.IBlockState) + .add(TypesMc.Classes.World) + .add(TypesMc.Classes.BlockPos) + .add(TypesMc.Classes.AxisAlignedBB) + .add(List.class) + .add(TypesMc.Classes.Entity) + .add(boolean.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onBlockRenderInLoop = - Classes.ForgeHaxHooks.childMethod() - .setName("onBlockRenderInLoop") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.RenderChunk) - .add(TypesMc.Classes.Block) - .add(TypesMc.Classes.IBlockState) - .add(TypesMc.Classes.BlockPos) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onBlockRenderInLoop") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.RenderChunk) + .add(TypesMc.Classes.Block) + .add(TypesMc.Classes.IBlockState) + .add(TypesMc.Classes.BlockPos) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPreBuildChunk = - Classes.ForgeHaxHooks.childMethod() - .setName("onPreBuildChunk") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.RenderChunk) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPreBuildChunk") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.RenderChunk) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPostBuildChunk = - Classes.ForgeHaxHooks.childMethod() - .setName("onPostBuildChunk") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.RenderChunk) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPostBuildChunk") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.RenderChunk) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onDeleteGlResources = - Classes.ForgeHaxHooks.childMethod() - .setName("onDeleteGlResources") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.RenderChunk) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onDeleteGlResources") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.RenderChunk) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onChunkUploaded = - Classes.ForgeHaxHooks.childMethod() - .setName("onChunkUploaded") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.RenderChunk) - .add(TypesMc.Classes.BufferBuilder) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onChunkUploaded") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.RenderChunk) + .add(TypesMc.Classes.BufferBuilder) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onAddRenderChunk = - Classes.ForgeHaxHooks.childMethod() - .setName("onAddRenderChunk") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.RenderChunk) - .add(TypesMc.Classes.BlockRenderLayer) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onAddRenderChunk") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.RenderChunk) + .add(TypesMc.Classes.BlockRenderLayer) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onLoadRenderers = - Classes.ForgeHaxHooks.childMethod() - .setName("onLoadRenderers") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.ViewFrustum) - .add(TypesMc.Classes.ChunkRenderDispatcher) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onLoadRenderers") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.ViewFrustum) + .add(TypesMc.Classes.ChunkRenderDispatcher) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onWorldRendererDeallocated = - Classes.ForgeHaxHooks.childMethod() - .setName("onWorldRendererDeallocated") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.ChunkCompileTaskGenerator) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onWorldRendererDeallocated") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.ChunkCompileTaskGenerator) + .finish() + .build(); + ASMMethod ForgeHaxHooks_shouldDisableCaveCulling = - Classes.ForgeHaxHooks.childMethod() - .setName("shouldDisableCaveCulling") - .setReturnType(boolean.class) - .emptyParameters() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("shouldDisableCaveCulling") + .setReturnType(boolean.class) + .emptyParameters() + .build(); + ASMMethod ForgeHaxHooks_onJournyMapSetStratumColor = - Classes.ForgeHaxHooks.childMethod() - .setName("onJournyMapSetStratumColor") - .setReturnType(boolean.class) - .beginParameters() - .add(Object.class) - .add(Object.class) - .add(int.class) - .add(Integer.class) - .add(boolean.class) - .add(boolean.class) - .add(boolean.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onJournyMapSetStratumColor") + .setReturnType(boolean.class) + .beginParameters() + .add(Object.class) + .add(Object.class) + .add(int.class) + .add(Integer.class) + .add(boolean.class) + .add(boolean.class) + .add(boolean.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onUpdateWalkingPlayerPre = - Classes.ForgeHaxHooks.childMethod() - .setName("onUpdateWalkingPlayerPre") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.EntityPlayerSP) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onUpdateWalkingPlayerPre") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.EntityPlayerSP) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onUpdateWalkingPlayerPost = - Classes.ForgeHaxHooks.childMethod() - .setName("onUpdateWalkingPlayerPost") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.EntityPlayerSP) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onUpdateWalkingPlayerPost") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.EntityPlayerSP) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPushOutOfBlocks = - Classes.ForgeHaxHooks.childMethod() - .setName("onPushOutOfBlocks") - .setReturnType(boolean.class) - .emptyParameters() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPushOutOfBlocks") + .setReturnType(boolean.class) + .emptyParameters() + .build(); + ASMMethod ForgeHaxHooks_onRenderBoat = - Classes.ForgeHaxHooks.childMethod() - .setName("onRenderBoat") - .setReturnType(float.class) - .beginParameters() - .add(TypesMc.Classes.EntityBoat) - .add(float.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onRenderBoat") + .setReturnType(float.class) + .beginParameters() + .add(TypesMc.Classes.EntityBoat) + .add(float.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onSchematicaPlaceBlock = - Classes.ForgeHaxHooks.childMethod() - .setName("onSchematicaPlaceBlock") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.ItemStack) - .add(TypesMc.Classes.BlockPos) - .add(TypesMc.Classes.Vec3d) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onSchematicaPlaceBlock") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.ItemStack) + .add(TypesMc.Classes.BlockPos) + .add(TypesMc.Classes.Vec3d) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onWorldCheckLightFor = - Classes.ForgeHaxHooks.childMethod() - .setName("onWorldCheckLightFor") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.EnumSkyBlock) - .add(TypesMc.Classes.BlockPos) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onWorldCheckLightFor") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.EnumSkyBlock) + .add(TypesMc.Classes.BlockPos) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onLeftClickCounterSet = - Classes.ForgeHaxHooks.childMethod() - .setName("onLeftClickCounterSet") - .setReturnType(int.class) - .beginParameters() - .add(int.class) - .add(TypesMc.Classes.Minecraft) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onLeftClickCounterSet") + .setReturnType(int.class) + .beginParameters() + .add(int.class) + .add(TypesMc.Classes.Minecraft) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onSendClickBlockToController = - Classes.ForgeHaxHooks.childMethod() - .setName("onSendClickBlockToController") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.Minecraft) - .add(boolean.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onSendClickBlockToController") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.Minecraft) + .add(boolean.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPlayerItemSync = - Classes.ForgeHaxHooks.childMethod() - .setName("onPlayerItemSync") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.PlayerControllerMP) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPlayerItemSync") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.PlayerControllerMP) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPlayerBreakingBlock = - Classes.ForgeHaxHooks.childMethod() - .setName("onPlayerBreakingBlock") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.PlayerControllerMP) - .add(TypesMc.Classes.BlockPos) - .add(TypesMc.Classes.EnumFacing) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPlayerBreakingBlock") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.PlayerControllerMP) + .add(TypesMc.Classes.BlockPos) + .add(TypesMc.Classes.EnumFacing) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPlayerAttackEntity = - Classes.ForgeHaxHooks.childMethod() - .setName("onPlayerAttackEntity") - .setReturnType(void.class) - .beginParameters() - .add(TypesMc.Classes.PlayerControllerMP) - .add(TypesMc.Classes.EntityPlayer) - .add(TypesMc.Classes.Entity) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPlayerAttackEntity") + .setReturnType(void.class) + .beginParameters() + .add(TypesMc.Classes.PlayerControllerMP) + .add(TypesMc.Classes.EntityPlayer) + .add(TypesMc.Classes.Entity) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onPlayerStopUse = - Classes.ForgeHaxHooks.childMethod() - .setName("onPlayerStopUse") - .setReturnType(boolean.class) - .beginParameters() - .add(TypesMc.Classes.PlayerControllerMP) - .add(TypesMc.Classes.EntityPlayer) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onPlayerStopUse") + .setReturnType(boolean.class) + .beginParameters() + .add(TypesMc.Classes.PlayerControllerMP) + .add(TypesMc.Classes.EntityPlayer) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onEntityBlockSlipApply = - Classes.ForgeHaxHooks.childMethod() - .setName("onEntityBlockSlipApply") - .setReturnType(float.class) - .beginParameters() - .add(float.class) - .add(TypesMc.Classes.EntityLivingBase) - .add(TypesMc.Classes.IBlockState) - .add(int.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("onEntityBlockSlipApply") + .setReturnType(float.class) + .beginParameters() + .add(float.class) + .add(TypesMc.Classes.EntityLivingBase) + .add(TypesMc.Classes.IBlockState) + .add(int.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_fireEvent_v = - Classes.ForgeHaxHooks.childMethod() - .setName("fireEvent_v") - .setReturnType(void.class) // return nothing - .beginParameters() - .add(Event.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("fireEvent_v") + .setReturnType(void.class) // return nothing + .beginParameters() + .add(Event.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_fireEvent_b = - Classes.ForgeHaxHooks.childMethod() - .setName("fireEvent_b") - .setReturnType(boolean.class) // return true if canceled - .beginParameters() - .add(Event.class) - .finish() - .build(); - + Classes.ForgeHaxHooks.childMethod() + .setName("fireEvent_b") + .setReturnType(boolean.class) // return true if canceled + .beginParameters() + .add(Event.class) + .finish() + .build(); + ASMMethod ForgeHaxHooks_onDrawBoundingBox_Post = - Classes.ForgeHaxHooks.childMethod() - .setName("onDrawBoundingBoxPost") - .setReturnType(void.class) - .emptyParameters() - .build(); + Classes.ForgeHaxHooks.childMethod() + .setName("onDrawBoundingBoxPost") + .setReturnType(void.class) + .emptyParameters() + .build(); } } diff --git a/src/main/java/com/matt/forgehax/asm/TypesMc.java b/src/main/java/com/matt/forgehax/asm/TypesMc.java index 57c2334fb..ed682eb9f 100644 --- a/src/main/java/com/matt/forgehax/asm/TypesMc.java +++ b/src/main/java/com/matt/forgehax/asm/TypesMc.java @@ -9,745 +9,751 @@ import io.netty.util.concurrent.GenericFutureListener; import java.util.List; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public interface TypesMc { + interface Classes { + ASMClass Packet = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/network/Packet") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/network/Packet") + .autoAssign() + .build(); + ASMClass AxisAlignedBB = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/util/math/AxisAlignedBB") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/util/math/AxisAlignedBB") + .autoAssign() + .build(); + ASMClass Material = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/block/material/Material") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/block/material/Material") + .autoAssign() + .build(); + ASMClass Entity = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/entity/Entity") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/entity/Entity") + .autoAssign() + .build(); + ASMClass EntityLivingBase = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/entity/EntityLivingBase") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/entity/EntityLivingBase") + .autoAssign() + .build(); + ASMClass Vec3d = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/util/math/Vec3d") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/util/math/Vec3d") + .autoAssign() + .build(); + ASMClass BlockRenderLayer = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/util/BlockRenderLayer") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/util/BlockRenderLayer") + .autoAssign() + .build(); + ASMClass IBlockState = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/block/state/IBlockState") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/block/state/IBlockState") + .autoAssign() + .build(); + ASMClass BlockPos = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/util/math/BlockPos") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/util/math/BlockPos") + .autoAssign() + .build(); + ASMClass Block = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/block/Block") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/block/Block") + .autoAssign() + .build(); + ASMClass ICamera = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/culling/ICamera") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/culling/ICamera") + .autoAssign() + .build(); + ASMClass VisGraph = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/chunk/VisGraph") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/chunk/VisGraph") + .autoAssign() + .build(); + ASMClass SetVisibility = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/chunk/SetVisibility") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/chunk/SetVisibility") + .autoAssign() + .build(); + ASMClass Minecraft = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/Minecraft") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/Minecraft") + .autoAssign() + .build(); + ASMClass NetworkManager$4 = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/network/NetworkManager$4") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/network/NetworkManager$4") + .autoAssign() + .build(); + ASMClass IBlockAccess = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/world/IBlockAccess") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/world/IBlockAccess") + .autoAssign() + .build(); + ASMClass BufferBuilder = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/BufferBuilder") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/BufferBuilder") + .autoAssign() + .build(); + ASMClass MoverType = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/entity/MoverType") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/entity/MoverType") + .autoAssign() + .build(); + ASMClass WorldProvider = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/world/WorldProvider") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/world/WorldProvider") + .autoAssign() + .build(); + ASMClass World = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/world/World") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/world/World") + .autoAssign() + .build(); + ASMClass IBakedModel = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/block/model/IBakedModel") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/block/model/IBakedModel") + .autoAssign() + .build(); + ASMClass CompiledChunk = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/chunk/CompiledChunk") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/chunk/CompiledChunk") + .autoAssign() + .build(); + ASMClass RenderChunk = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/chunk/RenderChunk") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/chunk/RenderChunk") + .autoAssign() + .build(); + ASMClass ChunkCompileTaskGenerator = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/chunk/ChunkCompileTaskGenerator") + .autoAssign() + .build(); + ASMClass ChunkCache = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/world/ChunkCache") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/world/ChunkCache") + .autoAssign() + .build(); + ASMClass ViewFrustum = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/ViewFrustum") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/ViewFrustum") + .autoAssign() + .build(); + ASMClass ChunkRenderDispatcher = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/chunk/ChunkRenderDispatcher") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/chunk/ChunkRenderDispatcher") + .autoAssign() + .build(); + ASMClass RenderGlobal = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/RenderGlobal") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/RenderGlobal") + .autoAssign() + .build(); + ASMClass ChunkRenderContainer = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/ChunkRenderContainer") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/ChunkRenderContainer") + .autoAssign() + .build(); + ASMClass ChunkRenderWorker = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/chunk/ChunkRenderWorker") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/chunk/ChunkRenderWorker") + .autoAssign() + .build(); + ASMClass EntityPlayer = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/entity/player/EntityPlayer") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/entity/player/EntityPlayer") + .autoAssign() + .build(); + ASMClass EntityPlayerSP = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/entity/EntityPlayerSP") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/entity/EntityPlayerSP") + .autoAssign() + .build(); + ASMClass EntityBoat = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/entity/item/EntityBoat") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/entity/item/EntityBoat") + .autoAssign() + .build(); + ASMClass EntityRenderer = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/EntityRenderer") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/EntityRenderer") + .autoAssign() + .build(); + ASMClass RenderBoat = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/renderer/entity/RenderBoat") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/renderer/entity/RenderBoat") + .autoAssign() + .build(); + ASMClass NetworkManager = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/network/NetworkManager") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/network/NetworkManager") + .autoAssign() + .build(); + ASMClass GuiScreen = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/gui/GuiScreen") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/gui/GuiScreen") + .autoAssign() + .build(); + ASMClass GuiMainMenu = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/gui/GuiMainMenu") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/gui/GuiMainMenu") + .autoAssign() + .build(); + ASMClass GuiPlayerTabOverlay = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/gui/GuiPlayerTabOverlay") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/gui/GuiPlayerTabOverlay") + .autoAssign() + .build(); + ASMClass Scoreboard = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/scoreboard/Scoreboard") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/scoreboard/Scoreboard") + .autoAssign() + .build(); + ASMClass ScoreObjective = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/scoreboard/ScoreObjective") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/scoreboard/ScoreObjective") + .autoAssign() + .build(); + ASMClass KeyBinding = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/settings/KeyBinding") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/settings/KeyBinding") + .autoAssign() + .build(); + ASMClass WorldClient = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/multiplayer/WorldClient") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/multiplayer/WorldClient") + .autoAssign() + .build(); + ASMClass ItemStack = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/item/ItemStack") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/item/ItemStack") + .autoAssign() + .build(); + ASMClass EnumFacing = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/util/EnumFacing") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/util/EnumFacing") + .autoAssign() + .build(); + ASMClass EnumHand = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/util/EnumHand") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/util/EnumHand") + .autoAssign() + .build(); + ASMClass EnumSkyBlock = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/world/EnumSkyBlock") - .autoAssign() - .build(); - + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/world/EnumSkyBlock") + .autoAssign() + .build(); + ASMClass PlayerControllerMP = - ASMBuilders.newClassBuilder() - .setClassName("net/minecraft/client/multiplayer/PlayerControllerMP") - .autoAssign() - .build(); + ASMBuilders.newClassBuilder() + .setClassName("net/minecraft/client/multiplayer/PlayerControllerMP") + .autoAssign() + .build(); } - + interface Fields { + ASMField NetworkManager$4_val$inPacket = - Classes.NetworkManager$4.childField() - .setName("val$inPacket") - .setType(Classes.Packet) - .build(); - + Classes.NetworkManager$4.childField() + .setName("val$inPacket") + .setType(Classes.Packet) + .build(); + ASMField RenderGlobal_viewFrustum = - Classes.RenderGlobal.childField() - .setName("viewFrustum") - .setType(Classes.ViewFrustum) - .autoAssign() - .build(); + Classes.RenderGlobal.childField() + .setName("viewFrustum") + .setType(Classes.ViewFrustum) + .autoAssign() + .build(); ASMField RenderGlobal_renderDispatcher = - Classes.RenderGlobal.childField() - .setName("renderDispatcher") - .setType(Classes.ChunkRenderDispatcher) - .autoAssign() - .build(); + Classes.RenderGlobal.childField() + .setName("renderDispatcher") + .setType(Classes.ChunkRenderDispatcher) + .autoAssign() + .build(); } - + interface Methods { + ASMMethod Block_canRenderInLayer = - Classes.Block.childMethod() - .setName("canRenderInLayer") - .setReturnType(boolean.class) - .beginParameters() - .add(Classes.IBlockState) - .add(Classes.BlockRenderLayer) - .finish() - .autoAssign() - .build(); + Classes.Block.childMethod() + .setName("canRenderInLayer") + .setReturnType(boolean.class) + .beginParameters() + .add(Classes.IBlockState) + .add(Classes.BlockRenderLayer) + .finish() + .autoAssign() + .build(); ASMMethod Block_addCollisionBoxToList = - Classes.Block.childMethod() - .setName("addCollisionBoxToList") - .setReturnType(void.class) - .beginParameters() - .add(Classes.IBlockState) - .add(Classes.World) - .add(Classes.BlockPos) - .add(Classes.AxisAlignedBB) - .add(List.class) - .add(Classes.Entity) - .add(boolean.class) - .finish() - .autoAssign() - .build(); - + Classes.Block.childMethod() + .setName("addCollisionBoxToList") + .setReturnType(void.class) + .beginParameters() + .add(Classes.IBlockState) + .add(Classes.World) + .add(Classes.BlockPos) + .add(Classes.AxisAlignedBB) + .add(List.class) + .add(Classes.Entity) + .add(boolean.class) + .finish() + .autoAssign() + .build(); + ASMMethod ChunkRenderContainer_addRenderChunk = - Classes.ChunkRenderContainer.childMethod() - .setName("addRenderChunk") - .setReturnType(void.class) - .beginParameters() - .add(Classes.RenderChunk) - .add(Classes.BlockRenderLayer) - .finish() - .autoAssign() - .build(); - + Classes.ChunkRenderContainer.childMethod() + .setName("addRenderChunk") + .setReturnType(void.class) + .beginParameters() + .add(Classes.RenderChunk) + .add(Classes.BlockRenderLayer) + .finish() + .autoAssign() + .build(); + ASMMethod ChunkRenderDispatcher_uploadChunk = - Classes.ChunkRenderDispatcher.childMethod() - .setName("uploadChunk") - .setReturnType(ListenableFuture.class) - .beginParameters() - .add(Classes.BlockRenderLayer) - .add(Classes.BufferBuilder) - .add(Classes.RenderChunk) - .add(Classes.CompiledChunk) - .add(double.class) - .finish() - .autoAssign() - .build(); - + Classes.ChunkRenderDispatcher.childMethod() + .setName("uploadChunk") + .setReturnType(ListenableFuture.class) + .beginParameters() + .add(Classes.BlockRenderLayer) + .add(Classes.BufferBuilder) + .add(Classes.RenderChunk) + .add(Classes.CompiledChunk) + .add(double.class) + .finish() + .autoAssign() + .build(); + ASMMethod ChunkRenderWorker_freeRenderBuilder = - Classes.ChunkRenderWorker.childMethod() - .setName("freeRenderBuilder") - .setReturnType(void.class) - .beginParameters() - .add(Classes.ChunkCompileTaskGenerator) - .finish() - .autoAssign() - .build(); - + Classes.ChunkRenderWorker.childMethod() + .setName("freeRenderBuilder") + .setReturnType(void.class) + .beginParameters() + .add(Classes.ChunkCompileTaskGenerator) + .finish() + .autoAssign() + .build(); + ASMMethod Entity_applyEntityCollision = - Classes.Entity.childMethod() - .setName("applyEntityCollision") - .setReturnType(void.class) - .beginParameters() - .add(Classes.Entity) - .finish() - .autoAssign() - .build(); + Classes.Entity.childMethod() + .setName("applyEntityCollision") + .setReturnType(void.class) + .beginParameters() + .add(Classes.Entity) + .finish() + .autoAssign() + .build(); ASMMethod Entity_move = - Classes.Entity.childMethod() - .setName("move") - .setReturnType(void.class) - .beginParameters() - .add(Classes.MoverType) - .add(double.class) - .add(double.class) - .add(double.class) - .finish() - .autoAssign() - .build(); + Classes.Entity.childMethod() + .setName("move") + .setReturnType(void.class) + .beginParameters() + .add(Classes.MoverType) + .add(double.class) + .add(double.class) + .add(double.class) + .finish() + .autoAssign() + .build(); ASMMethod Entity_doBlockCollisions = - Classes.Entity.childMethod() - .setName("doBlockCollisions") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); - + Classes.Entity.childMethod() + .setName("doBlockCollisions") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); + ASMMethod EntityPlayerSP_onLivingUpdate = - Classes.EntityPlayerSP.childMethod() - .setName("onLivingUpdate") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); + Classes.EntityPlayerSP.childMethod() + .setName("onLivingUpdate") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); ASMMethod EntityPlayerSP_onUpdate = - Classes.EntityPlayerSP.childMethod() - .setName("onUpdate") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); + Classes.EntityPlayerSP.childMethod() + .setName("onUpdate") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); ASMMethod EntityPlayerSP_onUpdateWalkingPlayer = - Classes.EntityPlayerSP.childMethod() - .setName("onUpdateWalkingPlayer") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); + Classes.EntityPlayerSP.childMethod() + .setName("onUpdateWalkingPlayer") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); ASMMethod EntityPlayerSP_pushOutOfBlocks = - Classes.EntityPlayerSP.childMethod() - .setName("pushOutOfBlocks") - .setReturnType(boolean.class) - .beginParameters() - .add(double.class) - .add(double.class) - .add(double.class) - .finish() - .autoAssign() - .build(); - + Classes.EntityPlayerSP.childMethod() + .setName("pushOutOfBlocks") + .setReturnType(boolean.class) + .beginParameters() + .add(double.class) + .add(double.class) + .add(double.class) + .finish() + .autoAssign() + .build(); + ASMMethod EntityPlayerSP_isRowingBoat = - Classes.EntityPlayerSP.childMethod() - .setName("isRowingBoat") - .setReturnType(boolean.class) - .emptyParameters() - .autoAssign() - .build(); - + Classes.EntityPlayerSP.childMethod() + .setName("isRowingBoat") + .setReturnType(boolean.class) + .emptyParameters() + .autoAssign() + .build(); + ASMMethod EntityLivingBase_travel = - Classes.EntityLivingBase.childMethod() - .setName("travel") - .setReturnType(void.class) - .beginParameters() - .add(float.class) - .add(float.class) - .add(float.class) - .finish() - .autoAssign() - .build(); - + Classes.EntityLivingBase.childMethod() + .setName("travel") + .setReturnType(void.class) + .beginParameters() + .add(float.class) + .add(float.class) + .add(float.class) + .finish() + .autoAssign() + .build(); + ASMMethod EntityRenderer_hurtCameraEffect = - Classes.EntityRenderer.childMethod() - .setName("hurtCameraEffect") - .setReturnType(void.class) - .beginParameters() - .add(float.class) - .finish() - .autoAssign() - .build(); - + Classes.EntityRenderer.childMethod() + .setName("hurtCameraEffect") + .setReturnType(void.class) + .beginParameters() + .add(float.class) + .finish() + .autoAssign() + .build(); + ASMMethod Minecraft_setIngameFocus = - Classes.Minecraft.childMethod() - .setName("setIngameFocus") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); + Classes.Minecraft.childMethod() + .setName("setIngameFocus") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); ASMMethod Minecraft_runTick = - Classes.Minecraft.childMethod() - .setName("runTick") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); + Classes.Minecraft.childMethod() + .setName("runTick") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); ASMMethod Minecraft_sendClickBlockToController = - Classes.Minecraft.childMethod() - .setName("sendClickBlockToController") - .setReturnType(void.class) - .beginParameters() - .add(boolean.class) - .finish() - .autoAssign() - .build(); - + Classes.Minecraft.childMethod() + .setName("sendClickBlockToController") + .setReturnType(void.class) + .beginParameters() + .add(boolean.class) + .finish() + .autoAssign() + .build(); + ASMMethod NetworkManager$4_run = - Classes.NetworkManager$4.childMethod() - .setName("run") - .setReturnType(void.class) - .emptyParameters() - .build(); // does not have an obfuscated or an srg name - + Classes.NetworkManager$4.childMethod() + .setName("run") + .setReturnType(void.class) + .emptyParameters() + .build(); // does not have an obfuscated or an srg name + ASMMethod NetworkManager_dispatchPacket = - Classes.NetworkManager.childMethod() - .setName("dispatchPacket") - .setReturnType(void.class) - .beginParameters() - .add(Classes.Packet) - .add(GenericFutureListener[].class) - .finish() - .autoAssign() - .build(); + Classes.NetworkManager.childMethod() + .setName("dispatchPacket") + .setReturnType(void.class) + .beginParameters() + .add(Classes.Packet) + .add(GenericFutureListener[].class) + .finish() + .autoAssign() + .build(); ASMMethod NetworkManager_channelRead0 = - Classes.NetworkManager.childMethod() - .setName("channelRead0") - .setObfuscatedName("a") // manually set because this isn't a vanilla method - .setReturnType(void.class) - .beginParameters() - .add(ChannelHandlerContext.class) - .add(Classes.Packet) - .finish() - // .autoAssign() - .build(); - + Classes.NetworkManager.childMethod() + .setName("channelRead0") + .setObfuscatedName("a") // manually set because this isn't a vanilla method + .setReturnType(void.class) + .beginParameters() + .add(ChannelHandlerContext.class) + .add(Classes.Packet) + .finish() + // .autoAssign() + .build(); + ASMMethod RenderChunk_rebuildChunk = - Classes.RenderChunk.childMethod() - .setName("rebuildChunk") - .setReturnType(void.class) - .beginParameters() - .add(float.class) - .add(float.class) - .add(float.class) - .add(Classes.ChunkCompileTaskGenerator) - .finish() - .autoAssign() - .build(); + Classes.RenderChunk.childMethod() + .setName("rebuildChunk") + .setReturnType(void.class) + .beginParameters() + .add(float.class) + .add(float.class) + .add(float.class) + .add(Classes.ChunkCompileTaskGenerator) + .finish() + .autoAssign() + .build(); ASMMethod RenderChunk_deleteGlResources = - Classes.RenderChunk.childMethod() - .setName("deleteGlResources") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); - + Classes.RenderChunk.childMethod() + .setName("deleteGlResources") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); + ASMMethod RenderGlobal_loadRenderers = - Classes.RenderGlobal.childMethod() - .setName("loadRenderers") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); + Classes.RenderGlobal.childMethod() + .setName("loadRenderers") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); ASMMethod RenderGlobal_renderBlockLayer = - Classes.RenderGlobal.childMethod() - .setName("renderBlockLayer") - .setReturnType(int.class) - .beginParameters() - .add(Classes.BlockRenderLayer) - .add(double.class) - .add(int.class) - .add(Classes.Entity) - .finish() - .autoAssign() - .build(); + Classes.RenderGlobal.childMethod() + .setName("renderBlockLayer") + .setReturnType(int.class) + .beginParameters() + .add(Classes.BlockRenderLayer) + .add(double.class) + .add(int.class) + .add(Classes.Entity) + .finish() + .autoAssign() + .build(); ASMMethod RenderGlobal_setupTerrain = - Classes.RenderGlobal.childMethod() - .setName("setupTerrain") - .setReturnType(void.class) - .beginParameters() - .add(Classes.Entity) - .add(double.class) - .add(Classes.ICamera) - .add(int.class) - .add(boolean.class) - .finish() - .autoAssign() - .build(); + Classes.RenderGlobal.childMethod() + .setName("setupTerrain") + .setReturnType(void.class) + .beginParameters() + .add(Classes.Entity) + .add(double.class) + .add(Classes.ICamera) + .add(int.class) + .add(boolean.class) + .finish() + .autoAssign() + .build(); ASMMethod RenderGlobal_drawBoundingBox = - Classes.RenderGlobal.childMethod() - .setName("drawBoundingBox") - .setReturnType(void.class) - .beginParameters() - .add(double.class) - .add(double.class) - .add(double.class) - .add(double.class) - .add(double.class) - .add(double.class) - .add(float.class) - .add(float.class) - .add(float.class) - .add(float.class) - .finish() - .autoAssign() - .build(); - + Classes.RenderGlobal.childMethod() + .setName("drawBoundingBox") + .setReturnType(void.class) + .beginParameters() + .add(double.class) + .add(double.class) + .add(double.class) + .add(double.class) + .add(double.class) + .add(double.class) + .add(float.class) + .add(float.class) + .add(float.class) + .add(float.class) + .finish() + .autoAssign() + .build(); + ASMMethod BufferBuilder_putColorMultiplier = - Classes.BufferBuilder.childMethod() - .setName("putColorMultiplier") - .setReturnType(void.class) - .beginParameters() - .add(float.class) - .add(float.class) - .add(float.class) - .add(int.class) - .finish() - .autoAssign() - .build(); - + Classes.BufferBuilder.childMethod() + .setName("putColorMultiplier") + .setReturnType(void.class) + .beginParameters() + .add(float.class) + .add(float.class) + .add(float.class) + .add(int.class) + .finish() + .autoAssign() + .build(); + ASMMethod VisGraph_setOpaqueCube = - Classes.VisGraph.childMethod() - .setName("setOpaqueCube") - .setReturnType(void.class) - .beginParameters() - .add(Classes.BlockPos) - .finish() - .autoAssign() - .build(); + Classes.VisGraph.childMethod() + .setName("setOpaqueCube") + .setReturnType(void.class) + .beginParameters() + .add(Classes.BlockPos) + .finish() + .autoAssign() + .build(); ASMMethod VisGraph_computeVisibility = - Classes.VisGraph.childMethod() - .setName("computeVisibility") - .setReturnType(Classes.SetVisibility) - .emptyParameters() - .autoAssign() - .build(); - + Classes.VisGraph.childMethod() + .setName("computeVisibility") + .setReturnType(Classes.SetVisibility) + .emptyParameters() + .autoAssign() + .build(); + ASMMethod World_handleMaterialAcceleration = - Classes.World.childMethod() - .setName("handleMaterialAcceleration") - .setReturnType(boolean.class) - .beginParameters() - .add(Classes.AxisAlignedBB) - .add(Classes.Material) - .add(Classes.Entity) - .finish() - .autoAssign() - .build(); + Classes.World.childMethod() + .setName("handleMaterialAcceleration") + .setReturnType(boolean.class) + .beginParameters() + .add(Classes.AxisAlignedBB) + .add(Classes.Material) + .add(Classes.Entity) + .finish() + .autoAssign() + .build(); ASMMethod World_checkLightFor = - Classes.World.childMethod() - .setName("checkLightFor") - .setReturnType(boolean.class) - .beginParameters() - .add(Classes.EnumSkyBlock) - .add(Classes.BlockPos) - .finish() - .autoAssign() - .build(); - + Classes.World.childMethod() + .setName("checkLightFor") + .setReturnType(boolean.class) + .beginParameters() + .add(Classes.EnumSkyBlock) + .add(Classes.BlockPos) + .finish() + .autoAssign() + .build(); + ASMMethod EntityBoat_updateMotion = - Classes.EntityBoat.childMethod() - .setName("updateMotion") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); - + Classes.EntityBoat.childMethod() + .setName("updateMotion") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); + ASMMethod EntityBoat_controlBoat = - Classes.EntityBoat.childMethod() - .setName("controlBoat") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); - + Classes.EntityBoat.childMethod() + .setName("controlBoat") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); + ASMMethod EntityBoat_applyYawToEntity = - Classes.EntityBoat.childMethod() - .setName("applyYawToEntity") - .setReturnType(void.class) - .beginParameters() - .add(Classes.Entity) - .finish() - .autoAssign() - .build(); - + Classes.EntityBoat.childMethod() + .setName("applyYawToEntity") + .setReturnType(void.class) + .beginParameters() + .add(Classes.Entity) + .finish() + .autoAssign() + .build(); + ASMMethod RenderBoat_doRender = - Classes.RenderBoat.childMethod() - .setName("doRender") - .setReturnType(void.class) - .beginParameters() - .add(Classes.EntityBoat) - .add(double.class) - .add(double.class) - .add(double.class) - .add(float.class) - .add(float.class) - .finish() - .autoAssign() - .build(); - + Classes.RenderBoat.childMethod() + .setName("doRender") + .setReturnType(void.class) + .beginParameters() + .add(Classes.EntityBoat) + .add(double.class) + .add(double.class) + .add(double.class) + .add(float.class) + .add(float.class) + .finish() + .autoAssign() + .build(); + ASMMethod PlayerTabOverlay_renderPlayerList = - Classes.GuiPlayerTabOverlay.childMethod() - .setName("renderPlayerlist") - .setReturnType(void.class) - .beginParameters() - .add(int.class) - .add(Classes.Scoreboard) - .add(Classes.ScoreObjective) - .finish() - .autoAssign() - .build(); - + Classes.GuiPlayerTabOverlay.childMethod() + .setName("renderPlayerlist") + .setReturnType(void.class) + .beginParameters() + .add(int.class) + .add(Classes.Scoreboard) + .add(Classes.ScoreObjective) + .finish() + .autoAssign() + .build(); + ASMMethod KeyBinding_isKeyDown = - Classes.KeyBinding.childMethod() - .setName("isKeyDown") - .setReturnType(boolean.class) - .emptyParameters() - .autoAssign() - .build(); - + Classes.KeyBinding.childMethod() + .setName("isKeyDown") + .setReturnType(boolean.class) + .emptyParameters() + .autoAssign() + .build(); + ASMMethod PlayerControllerMC_syncCurrentPlayItem = - Classes.PlayerControllerMP.childMethod() - .setName("syncCurrentPlayItem") - .setReturnType(void.class) - .emptyParameters() - .autoAssign() - .build(); + Classes.PlayerControllerMP.childMethod() + .setName("syncCurrentPlayItem") + .setReturnType(void.class) + .emptyParameters() + .autoAssign() + .build(); ASMMethod PlayerControllerMC_attackEntity = - Classes.PlayerControllerMP.childMethod() - .setName("attackEntity") - .setReturnType(void.class) - .beginParameters() - .add(Classes.EntityPlayer) - .add(Classes.Entity) - .finish() - .autoAssign() - .build(); + Classes.PlayerControllerMP.childMethod() + .setName("attackEntity") + .setReturnType(void.class) + .beginParameters() + .add(Classes.EntityPlayer) + .add(Classes.Entity) + .finish() + .autoAssign() + .build(); ASMMethod PlayerControllerMC_onPlayerDamageBlock = - Classes.PlayerControllerMP.childMethod() - .setName("onPlayerDamageBlock") - .setReturnType(boolean.class) - .beginParameters() - .add(Classes.BlockPos) - .add(Classes.EnumFacing) - .finish() - .autoAssign() - .build(); + Classes.PlayerControllerMP.childMethod() + .setName("onPlayerDamageBlock") + .setReturnType(boolean.class) + .beginParameters() + .add(Classes.BlockPos) + .add(Classes.EnumFacing) + .finish() + .autoAssign() + .build(); ASMMethod PlayerControllerMC_onStoppedUsingItem = - Classes.PlayerControllerMP.childMethod() - .setName("onStoppedUsingItem") - .setReturnType(void.class) - .beginParameters() - .add(Classes.EntityPlayer) - .finish() - .autoAssign() - .build(); + Classes.PlayerControllerMP.childMethod() + .setName("onStoppedUsingItem") + .setReturnType(void.class) + .beginParameters() + .add(Classes.EntityPlayer) + .finish() + .autoAssign() + .build(); } } diff --git a/src/main/java/com/matt/forgehax/asm/TypesSpecial.java b/src/main/java/com/matt/forgehax/asm/TypesSpecial.java index cb21870e8..e10513621 100644 --- a/src/main/java/com/matt/forgehax/asm/TypesSpecial.java +++ b/src/main/java/com/matt/forgehax/asm/TypesSpecial.java @@ -4,32 +4,39 @@ import com.matt.forgehax.asm.utils.asmtype.ASMMethod; import com.matt.forgehax.asm.utils.asmtype.builders.ASMBuilders; -/** Created on 5/29/2017 by fr1kin */ +/** + * Created on 5/29/2017 by fr1kin + */ public interface TypesSpecial { + interface Classes { + ASMClass SchematicPrinter = - ASMBuilders.newClassBuilder() - .setClassName("com/github/lunatrius/schematica/client/printer/SchematicPrinter") - .build(); + ASMBuilders.newClassBuilder() + .setClassName("com/github/lunatrius/schematica/client/printer/SchematicPrinter") + .build(); + } + + interface Fields { + } - - interface Fields {} interface Methods { + ASMMethod SchematicPrinter_placeBlock = - Classes.SchematicPrinter.childMethod() - .setName("placeBlock") - .setReturnType(boolean.class) - .beginParameters() - .unobfuscated() - .add(TypesMc.Classes.WorldClient) - .add(TypesMc.Classes.EntityPlayerSP) - .add(TypesMc.Classes.ItemStack) - .add(TypesMc.Classes.BlockPos) - .add(TypesMc.Classes.EnumFacing) - .add(TypesMc.Classes.Vec3d) - .add(TypesMc.Classes.EnumHand) - .finish() - .build(); + Classes.SchematicPrinter.childMethod() + .setName("placeBlock") + .setReturnType(boolean.class) + .beginParameters() + .unobfuscated() + .add(TypesMc.Classes.WorldClient) + .add(TypesMc.Classes.EntityPlayerSP) + .add(TypesMc.Classes.ItemStack) + .add(TypesMc.Classes.BlockPos) + .add(TypesMc.Classes.EnumFacing) + .add(TypesMc.Classes.Vec3d) + .add(TypesMc.Classes.EnumHand) + .finish() + .build(); } } diff --git a/src/main/java/com/matt/forgehax/asm/events/AddCollisionBoxToListEvent.java b/src/main/java/com/matt/forgehax/asm/events/AddCollisionBoxToListEvent.java index c44a9583c..0acea9461 100644 --- a/src/main/java/com/matt/forgehax/asm/events/AddCollisionBoxToListEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/AddCollisionBoxToListEvent.java @@ -10,9 +10,12 @@ import net.minecraftforge.fml.common.eventhandler.Cancelable; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 4/9/2017 by fr1kin */ +/** + * Created on 4/9/2017 by fr1kin + */ @Cancelable public class AddCollisionBoxToListEvent extends Event { + private final Block block; private final IBlockState state; private final World world; @@ -23,14 +26,14 @@ public class AddCollisionBoxToListEvent extends Event { private final boolean bool; public AddCollisionBoxToListEvent( - Block block, - IBlockState state, - World worldIn, - BlockPos pos, - AxisAlignedBB entityBox, - List collidingBoxes, - Entity entityIn, - boolean bool) { + Block block, + IBlockState state, + World worldIn, + BlockPos pos, + AxisAlignedBB entityBox, + List collidingBoxes, + Entity entityIn, + boolean bool) { this.block = block; this.state = state; this.world = worldIn; diff --git a/src/main/java/com/matt/forgehax/asm/events/AddRenderChunkEvent.java b/src/main/java/com/matt/forgehax/asm/events/AddRenderChunkEvent.java index ba7ba2612..124ee3012 100644 --- a/src/main/java/com/matt/forgehax/asm/events/AddRenderChunkEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/AddRenderChunkEvent.java @@ -4,8 +4,11 @@ import net.minecraft.util.BlockRenderLayer; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/9/2017 by fr1kin */ +/** + * Created on 5/9/2017 by fr1kin + */ public class AddRenderChunkEvent extends Event { + private final RenderChunk renderChunk; private final BlockRenderLayer blockRenderLayer; diff --git a/src/main/java/com/matt/forgehax/asm/events/ApplyClimbableBlockMovement.java b/src/main/java/com/matt/forgehax/asm/events/ApplyClimbableBlockMovement.java index 29d006d66..f1c642e29 100644 --- a/src/main/java/com/matt/forgehax/asm/events/ApplyClimbableBlockMovement.java +++ b/src/main/java/com/matt/forgehax/asm/events/ApplyClimbableBlockMovement.java @@ -6,6 +6,7 @@ @Cancelable public class ApplyClimbableBlockMovement extends LivingEvent { + public ApplyClimbableBlockMovement(EntityLivingBase entity) { super(entity); } diff --git a/src/main/java/com/matt/forgehax/asm/events/ApplyCollisionMotionEvent.java b/src/main/java/com/matt/forgehax/asm/events/ApplyCollisionMotionEvent.java index 7e8a5054e..076911215 100644 --- a/src/main/java/com/matt/forgehax/asm/events/ApplyCollisionMotionEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/ApplyCollisionMotionEvent.java @@ -6,6 +6,7 @@ @Cancelable public class ApplyCollisionMotionEvent extends Event { + private Entity entity; private Entity collidedWithEntity; @@ -14,7 +15,7 @@ public class ApplyCollisionMotionEvent extends Event { private double motionZ; public ApplyCollisionMotionEvent( - Entity entity, Entity collidedWithEntity, double mX, double mY, double mZ) { + Entity entity, Entity collidedWithEntity, double mX, double mY, double mZ) { this.entity = entity; this.collidedWithEntity = collidedWithEntity; motionX = mX; diff --git a/src/main/java/com/matt/forgehax/asm/events/BlockControllerProcessEvent.java b/src/main/java/com/matt/forgehax/asm/events/BlockControllerProcessEvent.java index fc56d5ee2..0b7af487f 100644 --- a/src/main/java/com/matt/forgehax/asm/events/BlockControllerProcessEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/BlockControllerProcessEvent.java @@ -4,6 +4,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class BlockControllerProcessEvent extends Event { + private final Minecraft minecraft; private boolean leftClicked; diff --git a/src/main/java/com/matt/forgehax/asm/events/BlockModelRenderEvent.java b/src/main/java/com/matt/forgehax/asm/events/BlockModelRenderEvent.java index 03587f3a6..375860ac8 100644 --- a/src/main/java/com/matt/forgehax/asm/events/BlockModelRenderEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/BlockModelRenderEvent.java @@ -7,8 +7,11 @@ import net.minecraft.world.IBlockAccess; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/5/2017 by fr1kin */ +/** + * Created on 5/5/2017 by fr1kin + */ public class BlockModelRenderEvent extends Event { + private final IBlockAccess blockAccess; private final IBakedModel bakedModel; private final IBlockState blockState; @@ -18,13 +21,13 @@ public class BlockModelRenderEvent extends Event { private final long rand; public BlockModelRenderEvent( - IBlockAccess worldIn, - IBakedModel modelIn, - IBlockState stateIn, - BlockPos posIn, - BufferBuilder buffer, - boolean checkSides, - long rand) { + IBlockAccess worldIn, + IBakedModel modelIn, + IBlockState stateIn, + BlockPos posIn, + BufferBuilder buffer, + boolean checkSides, + long rand) { this.blockAccess = worldIn; this.bakedModel = modelIn; this.blockState = stateIn; diff --git a/src/main/java/com/matt/forgehax/asm/events/BlockRenderEvent.java b/src/main/java/com/matt/forgehax/asm/events/BlockRenderEvent.java index 7d7540e91..f31b016d9 100644 --- a/src/main/java/com/matt/forgehax/asm/events/BlockRenderEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/BlockRenderEvent.java @@ -6,15 +6,18 @@ import net.minecraft.world.IBlockAccess; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 11/10/2016 by fr1kin */ +/** + * Created on 11/10/2016 by fr1kin + */ public class BlockRenderEvent extends Event { + private final BlockPos pos; private final IBlockState state; private final IBlockAccess access; private final BufferBuilder buffer; public BlockRenderEvent( - BlockPos pos, IBlockState state, IBlockAccess access, BufferBuilder buffer) { + BlockPos pos, IBlockState state, IBlockAccess access, BufferBuilder buffer) { this.pos = pos; this.state = state; this.access = access; diff --git a/src/main/java/com/matt/forgehax/asm/events/BuildChunkEvent.java b/src/main/java/com/matt/forgehax/asm/events/BuildChunkEvent.java index f9aefec5b..f7ada8d2d 100644 --- a/src/main/java/com/matt/forgehax/asm/events/BuildChunkEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/BuildChunkEvent.java @@ -3,8 +3,11 @@ import net.minecraft.client.renderer.chunk.RenderChunk; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/8/2017 by fr1kin */ +/** + * Created on 5/8/2017 by fr1kin + */ public class BuildChunkEvent extends Event { + private final RenderChunk renderChunk; public BuildChunkEvent(RenderChunk renderChunk) { @@ -16,12 +19,14 @@ public RenderChunk getRenderChunk() { } public static class Pre extends BuildChunkEvent { + public Pre(RenderChunk renderChunk) { super(renderChunk); } } public static class Post extends BuildChunkEvent { + public Post(RenderChunk renderChunk) { super(renderChunk); } diff --git a/src/main/java/com/matt/forgehax/asm/events/ChunkUploadedEvent.java b/src/main/java/com/matt/forgehax/asm/events/ChunkUploadedEvent.java index 3339bdb96..14aa881ad 100644 --- a/src/main/java/com/matt/forgehax/asm/events/ChunkUploadedEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/ChunkUploadedEvent.java @@ -4,8 +4,11 @@ import net.minecraft.client.renderer.chunk.RenderChunk; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/7/2017 by fr1kin */ +/** + * Created on 5/7/2017 by fr1kin + */ public class ChunkUploadedEvent extends Event { + private final RenderChunk renderChunk; private final BufferBuilder buffer; diff --git a/src/main/java/com/matt/forgehax/asm/events/ComputeVisibilityEvent.java b/src/main/java/com/matt/forgehax/asm/events/ComputeVisibilityEvent.java index 40c6f6c36..6533ba338 100644 --- a/src/main/java/com/matt/forgehax/asm/events/ComputeVisibilityEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/ComputeVisibilityEvent.java @@ -5,6 +5,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class ComputeVisibilityEvent extends Event { + private final VisGraph visGraph; private final SetVisibility setVisibility; diff --git a/src/main/java/com/matt/forgehax/asm/events/DeleteGlResourcesEvent.java b/src/main/java/com/matt/forgehax/asm/events/DeleteGlResourcesEvent.java index b73bf54b8..45c503140 100644 --- a/src/main/java/com/matt/forgehax/asm/events/DeleteGlResourcesEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/DeleteGlResourcesEvent.java @@ -3,8 +3,11 @@ import net.minecraft.client.renderer.chunk.RenderChunk; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/8/2017 by fr1kin */ +/** + * Created on 5/8/2017 by fr1kin + */ public class DeleteGlResourcesEvent extends Event { + private final RenderChunk renderChunk; public DeleteGlResourcesEvent(RenderChunk renderChunk) { diff --git a/src/main/java/com/matt/forgehax/asm/events/DoBlockCollisionsEvent.java b/src/main/java/com/matt/forgehax/asm/events/DoBlockCollisionsEvent.java index 29cf90671..997526d12 100644 --- a/src/main/java/com/matt/forgehax/asm/events/DoBlockCollisionsEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/DoBlockCollisionsEvent.java @@ -8,6 +8,7 @@ @Cancelable public class DoBlockCollisionsEvent extends EntityEvent { + private final BlockPos pos; private final IBlockState state; diff --git a/src/main/java/com/matt/forgehax/asm/events/DrawBlockBoundingBoxEvent.java b/src/main/java/com/matt/forgehax/asm/events/DrawBlockBoundingBoxEvent.java index 02cc414e4..50eb3d464 100644 --- a/src/main/java/com/matt/forgehax/asm/events/DrawBlockBoundingBoxEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/DrawBlockBoundingBoxEvent.java @@ -3,6 +3,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class DrawBlockBoundingBoxEvent extends Event { + public float red; public float green; public float blue; @@ -16,10 +17,13 @@ public DrawBlockBoundingBoxEvent(float r, float g, float b, float a) { } public static class Pre extends DrawBlockBoundingBoxEvent { + public Pre(float r, float g, float b, float a) { super(r, g, b, a); } } - - public static class Post extends Event {} + + public static class Post extends Event { + + } } diff --git a/src/main/java/com/matt/forgehax/asm/events/EntityBlockSlipApplyEvent.java b/src/main/java/com/matt/forgehax/asm/events/EntityBlockSlipApplyEvent.java index ad40455af..b4fc784a8 100644 --- a/src/main/java/com/matt/forgehax/asm/events/EntityBlockSlipApplyEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/EntityBlockSlipApplyEvent.java @@ -5,6 +5,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class EntityBlockSlipApplyEvent extends Event { + public enum Stage { FIRST, SECOND, @@ -18,10 +19,10 @@ public enum Stage { private float slipperiness; public EntityBlockSlipApplyEvent( - Stage stage, - EntityLivingBase entityLivingBase, - IBlockState blockStateUnder, - float defaultSlipperiness) { + Stage stage, + EntityLivingBase entityLivingBase, + IBlockState blockStateUnder, + float defaultSlipperiness) { this.stage = stage; this.entityLivingBase = entityLivingBase; this.blockStateUnder = blockStateUnder; diff --git a/src/main/java/com/matt/forgehax/asm/events/HurtCamEffectEvent.java b/src/main/java/com/matt/forgehax/asm/events/HurtCamEffectEvent.java index 20a7038e7..1921eb0bf 100644 --- a/src/main/java/com/matt/forgehax/asm/events/HurtCamEffectEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/HurtCamEffectEvent.java @@ -5,6 +5,7 @@ @Cancelable public class HurtCamEffectEvent extends Event { + private final float partialTicks; public HurtCamEffectEvent(float pt) { diff --git a/src/main/java/com/matt/forgehax/asm/events/ItemStoppedUsedEvent.java b/src/main/java/com/matt/forgehax/asm/events/ItemStoppedUsedEvent.java index 446310e86..02d40a3c3 100644 --- a/src/main/java/com/matt/forgehax/asm/events/ItemStoppedUsedEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/ItemStoppedUsedEvent.java @@ -7,6 +7,7 @@ @Cancelable public class ItemStoppedUsedEvent extends Event { + private final PlayerControllerMP playerController; private final EntityPlayer player; diff --git a/src/main/java/com/matt/forgehax/asm/events/LeftClickCounterUpdateEvent.java b/src/main/java/com/matt/forgehax/asm/events/LeftClickCounterUpdateEvent.java index 4e68b3a32..ca41e7f28 100644 --- a/src/main/java/com/matt/forgehax/asm/events/LeftClickCounterUpdateEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/LeftClickCounterUpdateEvent.java @@ -7,6 +7,7 @@ @Cancelable public class LeftClickCounterUpdateEvent extends Event { + private final Minecraft minecraft; private int value; diff --git a/src/main/java/com/matt/forgehax/asm/events/LoadRenderersEvent.java b/src/main/java/com/matt/forgehax/asm/events/LoadRenderersEvent.java index 9b818ea25..0a081c37a 100644 --- a/src/main/java/com/matt/forgehax/asm/events/LoadRenderersEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/LoadRenderersEvent.java @@ -4,8 +4,11 @@ import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/10/2017 by fr1kin */ +/** + * Created on 5/10/2017 by fr1kin + */ public class LoadRenderersEvent extends Event { + private final ViewFrustum viewFrustum; private final ChunkRenderDispatcher renderDispatcher; diff --git a/src/main/java/com/matt/forgehax/asm/events/LocalPlayerUpdateMovementEvent.java b/src/main/java/com/matt/forgehax/asm/events/LocalPlayerUpdateMovementEvent.java index d4b4c2c01..8779fb68b 100644 --- a/src/main/java/com/matt/forgehax/asm/events/LocalPlayerUpdateMovementEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/LocalPlayerUpdateMovementEvent.java @@ -4,8 +4,11 @@ import net.minecraftforge.fml.common.eventhandler.Cancelable; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 6/15/2017 by fr1kin */ +/** + * Created on 6/15/2017 by fr1kin + */ public class LocalPlayerUpdateMovementEvent extends Event { + private final EntityPlayerSP localPlayer; private LocalPlayerUpdateMovementEvent(EntityPlayerSP localPlayer) { @@ -18,12 +21,14 @@ public EntityPlayerSP getLocalPlayer() { @Cancelable public static class Pre extends LocalPlayerUpdateMovementEvent { + public Pre(EntityPlayerSP localPlayer) { super(localPlayer); } } public static class Post extends LocalPlayerUpdateMovementEvent { + public Post(EntityPlayerSP localPlayer) { super(localPlayer); } diff --git a/src/main/java/com/matt/forgehax/asm/events/PacketEvent.java b/src/main/java/com/matt/forgehax/asm/events/PacketEvent.java index 604c64cc3..61a260220 100644 --- a/src/main/java/com/matt/forgehax/asm/events/PacketEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/PacketEvent.java @@ -5,6 +5,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class PacketEvent extends Event { + private final Packet packet; public PacketEvent(Packet packetIn) { @@ -16,18 +17,21 @@ public > T getPacket() { } public static class Outgoing extends PacketEvent { + public Outgoing(Packet packetIn) { super(packetIn); } @Cancelable public static class Pre extends Outgoing { + public Pre(Packet packetIn) { super(packetIn); } } public static class Post extends Outgoing { + public Post(Packet packetIn) { super(packetIn); } @@ -35,18 +39,21 @@ public Post(Packet packetIn) { } public static class Incoming extends PacketEvent { + public Incoming(Packet packetIn) { super(packetIn); } @Cancelable public static class Pre extends Incoming { + public Pre(Packet packetIn) { super(packetIn); } } public static class Post extends Incoming { + public Post(Packet packetIn) { super(packetIn); } diff --git a/src/main/java/com/matt/forgehax/asm/events/PlayerAttackEntityEvent.java b/src/main/java/com/matt/forgehax/asm/events/PlayerAttackEntityEvent.java index b022e0c35..1d0efe441 100644 --- a/src/main/java/com/matt/forgehax/asm/events/PlayerAttackEntityEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/PlayerAttackEntityEvent.java @@ -6,12 +6,13 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class PlayerAttackEntityEvent extends Event { + private final PlayerControllerMP playerController; private final EntityPlayer attacker; private final Entity victim; public PlayerAttackEntityEvent( - PlayerControllerMP playerController, EntityPlayer attacker, Entity victim) { + PlayerControllerMP playerController, EntityPlayer attacker, Entity victim) { this.playerController = playerController; this.attacker = attacker; this.victim = victim; diff --git a/src/main/java/com/matt/forgehax/asm/events/PlayerDamageBlockEvent.java b/src/main/java/com/matt/forgehax/asm/events/PlayerDamageBlockEvent.java index 3e45e9ccd..442399899 100644 --- a/src/main/java/com/matt/forgehax/asm/events/PlayerDamageBlockEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/PlayerDamageBlockEvent.java @@ -6,12 +6,13 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class PlayerDamageBlockEvent extends Event { + private final PlayerControllerMP playerController; private final BlockPos pos; private final EnumFacing side; public PlayerDamageBlockEvent( - PlayerControllerMP playerController, BlockPos pos, EnumFacing side) { + PlayerControllerMP playerController, BlockPos pos, EnumFacing side) { this.playerController = playerController; this.pos = pos; this.side = side; diff --git a/src/main/java/com/matt/forgehax/asm/events/PlayerSyncItemEvent.java b/src/main/java/com/matt/forgehax/asm/events/PlayerSyncItemEvent.java index f336fd296..74de58e24 100644 --- a/src/main/java/com/matt/forgehax/asm/events/PlayerSyncItemEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/PlayerSyncItemEvent.java @@ -4,6 +4,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class PlayerSyncItemEvent extends Event { + private final PlayerControllerMP playerController; public PlayerSyncItemEvent(PlayerControllerMP playerController) { diff --git a/src/main/java/com/matt/forgehax/asm/events/PrePostBlockModelRenderEvent.java b/src/main/java/com/matt/forgehax/asm/events/PrePostBlockModelRenderEvent.java index 5c725feed..cc4712975 100644 --- a/src/main/java/com/matt/forgehax/asm/events/PrePostBlockModelRenderEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/PrePostBlockModelRenderEvent.java @@ -6,8 +6,11 @@ import net.minecraft.util.math.Vec3d; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/5/2017 by fr1kin */ +/** + * Created on 5/5/2017 by fr1kin + */ public class PrePostBlockModelRenderEvent extends Event { + public enum State { PRE, POST, @@ -21,7 +24,7 @@ public enum State { private final State state; public PrePostBlockModelRenderEvent( - RenderChunk renderChunk, BufferBuilder BufferBuilder, State state, Vec3d pos) { + RenderChunk renderChunk, BufferBuilder BufferBuilder, State state, Vec3d pos) { this.renderChunk = renderChunk; this.buffer = BufferBuilder; this.state = state; @@ -29,17 +32,17 @@ public PrePostBlockModelRenderEvent( } public PrePostBlockModelRenderEvent( - RenderChunk renderChunk, BufferBuilder BufferBuilder, State state, BlockPos pos) { + RenderChunk renderChunk, BufferBuilder BufferBuilder, State state, BlockPos pos) { this(renderChunk, BufferBuilder, state, new Vec3d(pos.getX(), pos.getY(), pos.getZ())); } public PrePostBlockModelRenderEvent( - RenderChunk renderChunk, - BufferBuilder BufferBuilder, - State state, - float x, - float y, - float z) { + RenderChunk renderChunk, + BufferBuilder BufferBuilder, + State state, + float x, + float y, + float z) { this(renderChunk, BufferBuilder, state, new Vec3d(x, y, z)); } diff --git a/src/main/java/com/matt/forgehax/asm/events/PushOutOfBlocksEvent.java b/src/main/java/com/matt/forgehax/asm/events/PushOutOfBlocksEvent.java index 11d336128..2bc151cc9 100644 --- a/src/main/java/com/matt/forgehax/asm/events/PushOutOfBlocksEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/PushOutOfBlocksEvent.java @@ -9,4 +9,6 @@ *

Called every time the player updates cancel to stop getting pushed out of blocks */ @Cancelable -public class PushOutOfBlocksEvent extends Event {} +public class PushOutOfBlocksEvent extends Event { + +} diff --git a/src/main/java/com/matt/forgehax/asm/events/RenderBlockInLayerEvent.java b/src/main/java/com/matt/forgehax/asm/events/RenderBlockInLayerEvent.java index 1509433a3..3e8e75d13 100644 --- a/src/main/java/com/matt/forgehax/asm/events/RenderBlockInLayerEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/RenderBlockInLayerEvent.java @@ -6,13 +6,14 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class RenderBlockInLayerEvent extends Event { + private final Block block; private final IBlockState state; private final BlockRenderLayer compareToLayer; private BlockRenderLayer layer; public RenderBlockInLayerEvent( - Block block, IBlockState state, BlockRenderLayer layer, BlockRenderLayer compareToLayer) { + Block block, IBlockState state, BlockRenderLayer layer, BlockRenderLayer compareToLayer) { this.block = block; this.state = state; this.layer = layer; diff --git a/src/main/java/com/matt/forgehax/asm/events/RenderBlockLayerEvent.java b/src/main/java/com/matt/forgehax/asm/events/RenderBlockLayerEvent.java index 5dbba7d58..207227777 100644 --- a/src/main/java/com/matt/forgehax/asm/events/RenderBlockLayerEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/RenderBlockLayerEvent.java @@ -5,6 +5,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class RenderBlockLayerEvent extends Event { + private final BlockRenderLayer renderLayer; private final double partialTicks; @@ -23,12 +24,14 @@ public double getPartialTicks() { @Cancelable public static class Pre extends RenderBlockLayerEvent { + public Pre(BlockRenderLayer renderLayer, double partialTicks) { super(renderLayer, partialTicks); } } public static class Post extends RenderBlockLayerEvent { + public Post(BlockRenderLayer renderLayer, double partialTicks) { super(renderLayer, partialTicks); } diff --git a/src/main/java/com/matt/forgehax/asm/events/RenderBoatEvent.java b/src/main/java/com/matt/forgehax/asm/events/RenderBoatEvent.java index ad34e52dc..ad24782e3 100644 --- a/src/main/java/com/matt/forgehax/asm/events/RenderBoatEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/RenderBoatEvent.java @@ -4,9 +4,12 @@ import net.minecraftforge.fml.common.eventhandler.Cancelable; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created by Babbaj on 9/2/2017. */ +/** + * Created by Babbaj on 9/2/2017. + */ @Cancelable public class RenderBoatEvent extends Event { + private float yaw; private EntityBoat boat; diff --git a/src/main/java/com/matt/forgehax/asm/events/RenderTabNameEvent.java b/src/main/java/com/matt/forgehax/asm/events/RenderTabNameEvent.java index c2cb435b1..21e8597e0 100644 --- a/src/main/java/com/matt/forgehax/asm/events/RenderTabNameEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/RenderTabNameEvent.java @@ -8,8 +8,9 @@ public class RenderTabNameEvent extends Event { private final String name; private final int color; - - private @Nullable String newName; + + private @Nullable + String newName; private OptionalInt newColor = OptionalInt.empty(); public RenderTabNameEvent(String name, int color) { diff --git a/src/main/java/com/matt/forgehax/asm/events/SchematicaPlaceBlockEvent.java b/src/main/java/com/matt/forgehax/asm/events/SchematicaPlaceBlockEvent.java index fdd63e7eb..18db96d94 100644 --- a/src/main/java/com/matt/forgehax/asm/events/SchematicaPlaceBlockEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/SchematicaPlaceBlockEvent.java @@ -5,7 +5,9 @@ import net.minecraft.util.math.Vec3d; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created by Babbaj on 9/20/2017. */ +/** + * Created by Babbaj on 9/20/2017. + */ public class SchematicaPlaceBlockEvent extends Event { private ItemStack item; diff --git a/src/main/java/com/matt/forgehax/asm/events/SetupTerrainEvent.java b/src/main/java/com/matt/forgehax/asm/events/SetupTerrainEvent.java index b1ee1934a..18f691c38 100644 --- a/src/main/java/com/matt/forgehax/asm/events/SetupTerrainEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/SetupTerrainEvent.java @@ -4,6 +4,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class SetupTerrainEvent extends Event { + private final Entity renderEntity; private boolean culling; diff --git a/src/main/java/com/matt/forgehax/asm/events/WaterMovementEvent.java b/src/main/java/com/matt/forgehax/asm/events/WaterMovementEvent.java index ec29ab825..f6e099737 100644 --- a/src/main/java/com/matt/forgehax/asm/events/WaterMovementEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/WaterMovementEvent.java @@ -7,6 +7,7 @@ @Cancelable public class WaterMovementEvent extends Event { + private Entity entity; private Vec3d movement; diff --git a/src/main/java/com/matt/forgehax/asm/events/WorldCheckLightForEvent.java b/src/main/java/com/matt/forgehax/asm/events/WorldCheckLightForEvent.java index cb6e07e0a..b66edf965 100644 --- a/src/main/java/com/matt/forgehax/asm/events/WorldCheckLightForEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/WorldCheckLightForEvent.java @@ -5,9 +5,12 @@ import net.minecraftforge.fml.common.eventhandler.Cancelable; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 2/10/2018 by fr1kin */ +/** + * Created on 2/10/2018 by fr1kin + */ @Cancelable public class WorldCheckLightForEvent extends Event { + private final EnumSkyBlock enumSkyBlock; private final BlockPos pos; diff --git a/src/main/java/com/matt/forgehax/asm/events/WorldRendererAllocatedEvent.java b/src/main/java/com/matt/forgehax/asm/events/WorldRendererAllocatedEvent.java index eab97f8e0..49d5d1ce8 100644 --- a/src/main/java/com/matt/forgehax/asm/events/WorldRendererAllocatedEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/WorldRendererAllocatedEvent.java @@ -4,8 +4,11 @@ import net.minecraft.client.renderer.chunk.RenderChunk; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/11/2017 by fr1kin */ +/** + * Created on 5/11/2017 by fr1kin + */ public class WorldRendererAllocatedEvent extends Event { + private final ChunkCompileTaskGenerator generator; private final RenderChunk renderChunk; diff --git a/src/main/java/com/matt/forgehax/asm/events/WorldRendererDeallocatedEvent.java b/src/main/java/com/matt/forgehax/asm/events/WorldRendererDeallocatedEvent.java index d55ea8c13..d159af707 100644 --- a/src/main/java/com/matt/forgehax/asm/events/WorldRendererDeallocatedEvent.java +++ b/src/main/java/com/matt/forgehax/asm/events/WorldRendererDeallocatedEvent.java @@ -4,13 +4,16 @@ import net.minecraft.client.renderer.chunk.RenderChunk; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/11/2017 by fr1kin */ +/** + * Created on 5/11/2017 by fr1kin + */ public class WorldRendererDeallocatedEvent extends Event { + private final ChunkCompileTaskGenerator generator; private final RenderChunk renderChunk; public WorldRendererDeallocatedEvent( - ChunkCompileTaskGenerator generator, RenderChunk renderChunk) { + ChunkCompileTaskGenerator generator, RenderChunk renderChunk) { this.generator = generator; this.renderChunk = renderChunk; } diff --git a/src/main/java/com/matt/forgehax/asm/events/listeners/BlockModelRenderListener.java b/src/main/java/com/matt/forgehax/asm/events/listeners/BlockModelRenderListener.java index ae39a789c..06ad8c184 100644 --- a/src/main/java/com/matt/forgehax/asm/events/listeners/BlockModelRenderListener.java +++ b/src/main/java/com/matt/forgehax/asm/events/listeners/BlockModelRenderListener.java @@ -5,7 +5,10 @@ import net.minecraft.client.renderer.chunk.RenderChunk; import net.minecraft.util.math.BlockPos; -/** Created on 5/8/2017 by fr1kin */ +/** + * Created on 5/8/2017 by fr1kin + */ public interface BlockModelRenderListener extends ListenerHook { + void onBlockRenderInLoop(RenderChunk renderChunk, Block block, IBlockState state, BlockPos pos); } diff --git a/src/main/java/com/matt/forgehax/asm/events/listeners/ListenerHook.java b/src/main/java/com/matt/forgehax/asm/events/listeners/ListenerHook.java index f2b80a020..4e045ec26 100644 --- a/src/main/java/com/matt/forgehax/asm/events/listeners/ListenerHook.java +++ b/src/main/java/com/matt/forgehax/asm/events/listeners/ListenerHook.java @@ -1,4 +1,8 @@ package com.matt.forgehax.asm.events.listeners; -/** Created on 2/11/2018 by fr1kin */ -public interface ListenerHook {} +/** + * Created on 2/11/2018 by fr1kin + */ +public interface ListenerHook { + +} diff --git a/src/main/java/com/matt/forgehax/asm/events/listeners/ListenerObject.java b/src/main/java/com/matt/forgehax/asm/events/listeners/ListenerObject.java index d4a83a143..a04ec8e6c 100644 --- a/src/main/java/com/matt/forgehax/asm/events/listeners/ListenerObject.java +++ b/src/main/java/com/matt/forgehax/asm/events/listeners/ListenerObject.java @@ -3,8 +3,11 @@ import com.google.common.collect.Sets; import java.util.Collection; -/** Created on 5/12/2017 by fr1kin */ +/** + * Created on 5/12/2017 by fr1kin + */ public class ListenerObject { + private Collection listeners = Sets.newConcurrentHashSet(); public void register(E listener) { diff --git a/src/main/java/com/matt/forgehax/asm/events/listeners/Listeners.java b/src/main/java/com/matt/forgehax/asm/events/listeners/Listeners.java index b008be198..df08148e0 100644 --- a/src/main/java/com/matt/forgehax/asm/events/listeners/Listeners.java +++ b/src/main/java/com/matt/forgehax/asm/events/listeners/Listeners.java @@ -1,6 +1,9 @@ package com.matt.forgehax.asm.events.listeners; -/** Created on 5/12/2017 by fr1kin */ +/** + * Created on 5/12/2017 by fr1kin + */ public interface Listeners { + ListenerObject BLOCK_MODEL_RENDER_LISTENER = new ListenerObject<>(); } diff --git a/src/main/java/com/matt/forgehax/asm/patches/BlockPatch.java b/src/main/java/com/matt/forgehax/asm/patches/BlockPatch.java index 7696ba974..6ac5b0f14 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/BlockPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/BlockPatch.java @@ -1,21 +1,30 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; -import com.matt.forgehax.asm.utils.transforming.*; +import com.matt.forgehax.asm.utils.transforming.ClassTransformer; +import com.matt.forgehax.asm.utils.transforming.Inject; +import com.matt.forgehax.asm.utils.transforming.InjectPriority; +import com.matt.forgehax.asm.utils.transforming.MethodTransformer; +import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; public class BlockPatch extends ClassTransformer { + public BlockPatch() { super(Classes.Block); } @RegisterMethodTransformer private class CanRenderInLayer extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.Block_canRenderInLayer; @@ -24,7 +33,7 @@ public ASMMethod getMethod() { @Inject(description = "Changes in layer code so that we can change it") public void inject(MethodNode main) { AbstractInsnNode node = - ASMHelper.findPattern(main.instructions.getFirst(), new int[] {INVOKEVIRTUAL}, "x"); + ASMHelper.findPattern(main.instructions.getFirst(), new int[]{INVOKEVIRTUAL}, "x"); Objects.requireNonNull(node, "Find pattern failed for node"); @@ -37,9 +46,9 @@ public void inject(MethodNode main) { insnList.add(new VarInsnNode(ALOAD, 1)); // push block state insnList.add(new VarInsnNode(ALOAD, 3)); // push this.getBlockLayer() result insnList.add( - new VarInsnNode(ALOAD, 2)); // push the block layer of the block we are comparing to + new VarInsnNode(ALOAD, 2)); // push the block layer of the block we are comparing to insnList.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onRenderBlockInLayer)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onRenderBlockInLayer)); // now our result is on the stack main.instructions.insert(node, insnList); @@ -48,6 +57,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class AddCollisionBoxToList extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.Block_addCollisionBoxToList; @@ -55,13 +65,13 @@ public ASMMethod getMethod() { @Inject( description = - "Redirects method to our hook and allows the vanilla code to be canceled from executing", + "Redirects method to our hook and allows the vanilla code to be canceled from executing", priority = InjectPriority.LOWEST ) public void inject(MethodNode main) { AbstractInsnNode node = main.instructions.getFirst(); AbstractInsnNode end = - ASMHelper.findPattern(main.instructions.getFirst(), new int[] {RETURN}, "x"); + ASMHelper.findPattern(main.instructions.getFirst(), new int[]{RETURN}, "x"); Objects.requireNonNull(node, "Find pattern failed for node"); Objects.requireNonNull(end, "Find pattern failed for end"); @@ -78,7 +88,7 @@ public void inject(MethodNode main) { insnList.add(new VarInsnNode(ALOAD, 6)); // entityIn insnList.add(new VarInsnNode(ILOAD, 7)); // bool insnList.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onAddCollisionBoxToList)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onAddCollisionBoxToList)); insnList.add(new JumpInsnNode(IFNE, jumpPast)); main.instructions.insertBefore(end, jumpPast); diff --git a/src/main/java/com/matt/forgehax/asm/patches/BoatPatch.java b/src/main/java/com/matt/forgehax/asm/patches/BoatPatch.java index 6f32d999d..947c13064 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/BoatPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/BoatPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,128 +8,142 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; public class BoatPatch extends ClassTransformer { + public BoatPatch() { super(Classes.EntityBoat); } - + @RegisterMethodTransformer private class UpdateMotion extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityBoat_updateMotion; } - + @Inject(description = "Add hook to disable boat gravity") public void inject(MethodNode main) { AbstractInsnNode gravityNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, DUP, GETFIELD, DLOAD, DADD, PUTFIELD}, - "xxxxxx"); - + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, DUP, GETFIELD, DLOAD, DADD, PUTFIELD}, + "xxxxxx"); + Objects.requireNonNull(gravityNode, "Find pattern failed for gravityNode"); - + AbstractInsnNode putFieldNode = gravityNode; - for (int i = 0; i < 5; i++) putFieldNode = putFieldNode.getNext(); - + for (int i = 0; i < 5; i++) { + putFieldNode = putFieldNode.getNext(); + } + LabelNode newLabelNode = new LabelNode(); - + InsnList insnList = new InsnList(); insnList.add( - ASMHelper.call(GETSTATIC, TypesHook.Fields.ForgeHaxHooks_isNoBoatGravityActivated)); + ASMHelper.call(GETSTATIC, TypesHook.Fields.ForgeHaxHooks_isNoBoatGravityActivated)); insnList.add(new JumpInsnNode(IFNE, newLabelNode)); // if nogravity is enabled - + main.instructions.insertBefore(gravityNode, insnList); // insert if main.instructions.insert(putFieldNode, newLabelNode); // end if } } - + @RegisterMethodTransformer private class ControlBoat extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityBoat_controlBoat; } - + @Inject(description = "Add hooks to disable boat rotation") public void inject(MethodNode main) { AbstractInsnNode rotationLeftNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, DUP, GETFIELD, LDC, FADD, PUTFIELD}, - "xxxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, DUP, GETFIELD, LDC, FADD, PUTFIELD}, + "xxxxxx"); AbstractInsnNode rotationRightNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, DUP, GETFIELD, FCONST_1, FADD, PUTFIELD}, - "xxxxxx"); - + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, DUP, GETFIELD, FCONST_1, FADD, PUTFIELD}, + "xxxxxx"); + Objects.requireNonNull(rotationLeftNode, "Find pattern failed for leftNode"); Objects.requireNonNull(rotationRightNode, "Find pattern failed for rightNode"); - + AbstractInsnNode putFieldNodeLeft = rotationLeftNode; // get last instruction for left - for (int i = 0; i < 5; i++) putFieldNodeLeft = putFieldNodeLeft.getNext(); - + for (int i = 0; i < 5; i++) { + putFieldNodeLeft = putFieldNodeLeft.getNext(); + } + AbstractInsnNode putFieldNodeRight = rotationRightNode; // get last instruction for right - for (int i = 0; i < 5; i++) putFieldNodeRight = putFieldNodeRight.getNext(); - + for (int i = 0; i < 5; i++) { + putFieldNodeRight = putFieldNodeRight.getNext(); + } + /* * disable updating deltaRotation for strafing left */ LabelNode newLabelNodeLeft = new LabelNode(); - + InsnList insnListLeft = new InsnList(); insnListLeft.add( - ASMHelper.call(GETSTATIC, TypesHook.Fields.ForgeHaxHooks_isBoatSetYawActivated)); + ASMHelper.call(GETSTATIC, TypesHook.Fields.ForgeHaxHooks_isBoatSetYawActivated)); insnListLeft.add(new JumpInsnNode(IFNE, newLabelNodeLeft)); // if nogravity is enabled - + main.instructions.insertBefore(rotationLeftNode, insnListLeft); // insert if main.instructions.insert(putFieldNodeLeft, newLabelNodeLeft); // end if - + /* * disable updating deltaRotation for strafing right */ LabelNode newLabelNodeRight = new LabelNode(); - + InsnList insnListRight = new InsnList(); insnListRight.add( - ASMHelper.call(GETSTATIC, TypesHook.Fields.ForgeHaxHooks_isBoatSetYawActivated)); + ASMHelper.call(GETSTATIC, TypesHook.Fields.ForgeHaxHooks_isBoatSetYawActivated)); insnListRight.add(new JumpInsnNode(IFNE, newLabelNodeRight)); // if nogravity is enabled - + main.instructions.insertBefore(rotationRightNode, insnListRight); // insert if main.instructions.insert(putFieldNodeRight, newLabelNodeRight); // end if } } - + @RegisterMethodTransformer private class RemoveClamp extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityBoat_applyYawToEntity; } - + @Inject(description = "Disable boat view clamping") public void inject(MethodNode main) { AbstractInsnNode pre = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {FLOAD, LDC, LDC, INVOKESTATIC, FSTORE}, - "xxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{FLOAD, LDC, LDC, INVOKESTATIC, FSTORE}, + "xxxxx"); AbstractInsnNode post = pre.getNext().getNext().getNext(); // INVOKESTATIC - + Objects.requireNonNull(pre, "Find pattern failed for clamp node"); Objects.requireNonNull(post, "Find pattern failed for clamp node post"); - + InsnList insnList = new InsnList(); - + LabelNode jump = new LabelNode(); - + insnList.add(ASMHelper.call(GETSTATIC, TypesHook.Fields.ForgeHaxHooks_isNoClampingActivated)); insnList.add(new JumpInsnNode(IFNE, jump)); // if nogravity is enabled - + main.instructions.insert(pre, insnList); main.instructions.insert(post, jump); } diff --git a/src/main/java/com/matt/forgehax/asm/patches/BufferBuilderPatch.java b/src/main/java/com/matt/forgehax/asm/patches/BufferBuilderPatch.java index ccb589ed9..f23f56fe1 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/BufferBuilderPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/BufferBuilderPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,15 +8,24 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.IntInsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; public class BufferBuilderPatch extends ClassTransformer { + public BufferBuilderPatch() { super(Classes.BufferBuilder); } @RegisterMethodTransformer private class PutColorMultiplier extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.BufferBuilder_putColorMultiplier; @@ -27,29 +34,29 @@ public ASMMethod getMethod() { @Inject(description = "Add hook that allows method to be overwritten") public void inject(MethodNode main) { AbstractInsnNode preNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - INVOKESTATIC, - GETSTATIC, - IF_ACMPNE, - 0x00, - 0x00, - ILOAD, - SIPUSH, - IAND, - I2F, - FLOAD, - FMUL, - F2I, - ISTORE - }, - "xxx??xxxxxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + INVOKESTATIC, + GETSTATIC, + IF_ACMPNE, + 0x00, + 0x00, + ILOAD, + SIPUSH, + IAND, + I2F, + FLOAD, + FMUL, + F2I, + ISTORE + }, + "xxx??xxxxxxxx"); AbstractInsnNode postNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, GETFIELD, ILOAD, ILOAD, INVOKEVIRTUAL, POP}, - "xxxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, GETFIELD, ILOAD, ILOAD, INVOKEVIRTUAL, POP}, + "xxxxxx"); Objects.requireNonNull(preNode, "Find pattern failed for preNode"); Objects.requireNonNull(postNode, "Find pattern failed for postNode"); @@ -70,7 +77,7 @@ public void inject(MethodNode main) { insnPre.add(new VarInsnNode(ILOAD, 6)); insnPre.add(new VarInsnNode(ALOAD, 10)); insnPre.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onPutColorMultiplier)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onPutColorMultiplier)); insnPre.add(new VarInsnNode(ISTORE, 6)); insnPre.add(new VarInsnNode(ALOAD, 10)); insnPre.add(new InsnNode(ICONST_0)); diff --git a/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderContainerPatch.java b/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderContainerPatch.java index 84ddf9958..7ad5ef7c0 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderContainerPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderContainerPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,16 +8,23 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; - -/** Created on 5/9/2017 by fr1kin */ +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Created on 5/9/2017 by fr1kin + */ public class ChunkRenderContainerPatch extends ClassTransformer { + public ChunkRenderContainerPatch() { super(Classes.ChunkRenderContainer); } @RegisterMethodTransformer private class AddRenderChunk extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.ChunkRenderContainer_addRenderChunk; diff --git a/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderDispatcherPatch.java b/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderDispatcherPatch.java index 9f2b9db4b..1e7ef9385 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderDispatcherPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderDispatcherPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,16 +8,23 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; - -/** Created on 5/7/2017 by fr1kin */ +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Created on 5/7/2017 by fr1kin + */ public class ChunkRenderDispatcherPatch extends ClassTransformer { + public ChunkRenderDispatcherPatch() { super(Classes.ChunkRenderDispatcher); } @RegisterMethodTransformer private class UploadChunk extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.ChunkRenderDispatcher_uploadChunk; @@ -28,12 +33,12 @@ public ASMMethod getMethod() { @Inject(description = "Insert hook before buffer is uploaded") public void inject(MethodNode main) { AbstractInsnNode node = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - INVOKESTATIC, IFEQ, 0x00, 0x00, ALOAD, - }, - "xx??x"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + INVOKESTATIC, IFEQ, 0x00, 0x00, ALOAD, + }, + "xx??x"); Objects.requireNonNull(node, "Find pattern failed for node"); diff --git a/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderWorkerPatch.java b/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderWorkerPatch.java index 12fda9d9f..3e2ce4949 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderWorkerPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/ChunkRenderWorkerPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,16 +8,23 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; - -/** Created on 5/11/2017 by fr1kin */ +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Created on 5/11/2017 by fr1kin + */ public class ChunkRenderWorkerPatch extends ClassTransformer { + public ChunkRenderWorkerPatch() { super(Classes.ChunkRenderWorker); } @RegisterMethodTransformer private class FreeRenderBuilder extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.ChunkRenderWorker_freeRenderBuilder; @@ -34,7 +39,7 @@ public void inject(MethodNode main) { InsnList insnList = new InsnList(); insnList.add(new VarInsnNode(ALOAD, 1)); insnList.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onWorldRendererDeallocated)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onWorldRendererDeallocated)); main.instructions.insertBefore(node, insnList); } diff --git a/src/main/java/com/matt/forgehax/asm/patches/EntityLivingBasePatch.java b/src/main/java/com/matt/forgehax/asm/patches/EntityLivingBasePatch.java index d90c80bcd..26194e2e1 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/EntityLivingBasePatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/EntityLivingBasePatch.java @@ -1,7 +1,6 @@ package com.matt.forgehax.asm.patches; import com.matt.forgehax.asm.TypesHook; -import com.matt.forgehax.asm.TypesHook.Methods; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; import com.matt.forgehax.asm.utils.transforming.ClassTransformer; @@ -16,12 +15,14 @@ import org.objectweb.asm.tree.VarInsnNode; public class EntityLivingBasePatch extends ClassTransformer { + public EntityLivingBasePatch() { super(Classes.EntityLivingBase); } @RegisterMethodTransformer public class Travel extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityLivingBase_travel; @@ -31,28 +32,28 @@ public ASMMethod getMethod() { public void injectFirst(MethodNode node) { // at first underState.getBlock().getSlipperiness(...) AbstractInsnNode first = - ASMHelper.findPattern( - node, - INVOKEVIRTUAL, - LDC, - FMUL, - FSTORE, - NONE, - NONE, - NONE, - LDC, - FLOAD, - FLOAD, - FMUL, - FLOAD, - FMUL, - FDIV, - FSTORE, - NONE, - NONE, - ALOAD, - GETFIELD, - IFEQ); + ASMHelper.findPattern( + node, + INVOKEVIRTUAL, + LDC, + FMUL, + FSTORE, + NONE, + NONE, + NONE, + LDC, + FLOAD, + FLOAD, + FMUL, + FLOAD, + FMUL, + FDIV, + FSTORE, + NONE, + NONE, + ALOAD, + GETFIELD, + IFEQ); Objects.requireNonNull(first, "Could not find first slip motion node"); @@ -61,7 +62,7 @@ public void injectFirst(MethodNode node) { list.add(new VarInsnNode(ALOAD, 6)); list.add(new InsnNode(ICONST_0)); list.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onEntityBlockSlipApply)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onEntityBlockSlipApply)); // top of stack should be a modified or unmodified slippery float node.instructions.insert(first, list); // insert after @@ -71,31 +72,31 @@ public void injectFirst(MethodNode node) { public void injectSecond(MethodNode node) { // at second underState.getBlock().getSlipperiness(...) AbstractInsnNode second = - ASMHelper.findPattern( - node, - INVOKEVIRTUAL, - LDC, - FMUL, - FSTORE, - NONE, - NONE, - NONE, - ALOAD, - INVOKEVIRTUAL, - IFEQ, - NONE, - NONE, - LDC, - FSTORE, - NONE, - NONE, - ALOAD, - ALOAD, - GETFIELD, - LDC, - LDC, - INVOKESTATIC, - PUTFIELD); + ASMHelper.findPattern( + node, + INVOKEVIRTUAL, + LDC, + FMUL, + FSTORE, + NONE, + NONE, + NONE, + ALOAD, + INVOKEVIRTUAL, + IFEQ, + NONE, + NONE, + LDC, + FSTORE, + NONE, + NONE, + ALOAD, + ALOAD, + GETFIELD, + LDC, + LDC, + INVOKESTATIC, + PUTFIELD); Objects.requireNonNull(second, "Could not find second slip motion node"); @@ -104,7 +105,7 @@ public void injectSecond(MethodNode node) { list.add(new VarInsnNode(ALOAD, 8)); list.add(new InsnNode(ICONST_1)); list.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onEntityBlockSlipApply)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onEntityBlockSlipApply)); // top of stack should be a modified or unmodified slippery float node.instructions.insert(second, list); // insert after diff --git a/src/main/java/com/matt/forgehax/asm/patches/EntityPatch.java b/src/main/java/com/matt/forgehax/asm/patches/EntityPatch.java index fefc976fb..394f9b229 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/EntityPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/EntityPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,15 +8,23 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; public class EntityPatch extends ClassTransformer { + public EntityPatch() { super(Classes.Entity); } @RegisterMethodTransformer private class ApplyEntityCollision extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.Entity_applyEntityCollision; @@ -27,21 +33,21 @@ public ASMMethod getMethod() { @Inject(description = "Add hook to disable push motion") private void inject(MethodNode main) { AbstractInsnNode thisEntityPreNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, DLOAD, DNEG, DCONST_0, DLOAD, DNEG, INVOKEVIRTUAL}, - "xxxxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, DLOAD, DNEG, DCONST_0, DLOAD, DNEG, INVOKEVIRTUAL}, + "xxxxxxx"); // start at preNode, and scan for next INVOKEVIRTUAL sig AbstractInsnNode thisEntityPostNode = - ASMHelper.findPattern(thisEntityPreNode, new int[] {INVOKEVIRTUAL}, "x"); + ASMHelper.findPattern(thisEntityPreNode, new int[]{INVOKEVIRTUAL}, "x"); AbstractInsnNode otherEntityPreNode = - ASMHelper.findPattern( - thisEntityPostNode, - new int[] {ALOAD, DLOAD, DCONST_0, DLOAD, INVOKEVIRTUAL}, - "xxxxx"); + ASMHelper.findPattern( + thisEntityPostNode, + new int[]{ALOAD, DLOAD, DCONST_0, DLOAD, INVOKEVIRTUAL}, + "xxxxx"); // start at preNode, and scan for next INVOKEVIRTUAL sig AbstractInsnNode otherEntityPostNode = - ASMHelper.findPattern(otherEntityPreNode, new int[] {INVOKEVIRTUAL}, "x"); + ASMHelper.findPattern(otherEntityPreNode, new int[]{INVOKEVIRTUAL}, "x"); Objects.requireNonNull(thisEntityPreNode, "Find pattern failed for thisEntityPreNode"); Objects.requireNonNull(thisEntityPostNode, "Find pattern failed for thisEntityPostNode"); @@ -61,7 +67,7 @@ private void inject(MethodNode main) { insnThisPre.add(new VarInsnNode(DLOAD, 4)); insnThisPre.add(new InsnNode(DNEG)); // push -Z insnThisPre.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onApplyCollisionMotion)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onApplyCollisionMotion)); insnThisPre.add(new JumpInsnNode(IFNE, endJumpForThis)); InsnList insnOtherPre = new InsnList(); @@ -70,7 +76,7 @@ private void inject(MethodNode main) { insnOtherPre.add(new VarInsnNode(DLOAD, 2)); // push X insnOtherPre.add(new VarInsnNode(DLOAD, 4)); // push Z insnOtherPre.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onApplyCollisionMotion)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onApplyCollisionMotion)); insnOtherPre.add(new JumpInsnNode(IFNE, endJumpForOther)); main.instructions.insertBefore(thisEntityPreNode, insnThisPre); @@ -83,6 +89,7 @@ private void inject(MethodNode main) { @RegisterMethodTransformer private class MoveEntity extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.Entity_move; @@ -91,10 +98,10 @@ public ASMMethod getMethod() { @Inject(description = "Insert flag into statement that performs sneak movement") public void inject(MethodNode main) { AbstractInsnNode sneakFlagNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {IFEQ, ALOAD, INSTANCEOF, IFEQ, 0x00, 0x00, LDC, DSTORE}, - "xxxx??xx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{IFEQ, ALOAD, INSTANCEOF, IFEQ, 0x00, 0x00, LDC, DSTORE}, + "xxxx??xx"); Objects.requireNonNull(sneakFlagNode, "Find pattern failed for sneakFlagNode"); @@ -111,8 +118,8 @@ public void inject(MethodNode main) { InsnList insnList = new InsnList(); insnList.add( - new JumpInsnNode( - IFNE, orJump)); // if not equal, jump past the ForgeHaxHooks.isSafeWalkActivated + new JumpInsnNode( + IFNE, orJump)); // if not equal, jump past the ForgeHaxHooks.isSafeWalkActivated insnList.add(ASMHelper.call(GETSTATIC, TypesHook.Fields.ForgeHaxHooks_isSafeWalkActivated)); insnList.add(new JumpInsnNode(IFEQ, jumpToLabel)); insnList.add(orJump); @@ -125,6 +132,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class DoBlockCollisions extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.Entity_doBlockCollisions; @@ -133,23 +141,23 @@ public ASMMethod getMethod() { @Inject(description = "Add hook to disable block motion effects") public void inject(MethodNode main) { AbstractInsnNode preNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - ASTORE, - 0x00, - 0x00, - ALOAD, - INVOKEINTERFACE, - ALOAD, - GETFIELD, - ALOAD, - ALOAD, - ALOAD, - INVOKEVIRTUAL - }, - "x??xxxxxxxx"); - AbstractInsnNode postNode = ASMHelper.findPattern(preNode, new int[] {GOTO}, "x"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + ASTORE, + 0x00, + 0x00, + ALOAD, + INVOKEINTERFACE, + ALOAD, + GETFIELD, + ALOAD, + ALOAD, + ALOAD, + INVOKEVIRTUAL + }, + "x??xxxxxxxx"); + AbstractInsnNode postNode = ASMHelper.findPattern(preNode, new int[]{GOTO}, "x"); Objects.requireNonNull(preNode, "Find pattern failed for preNode"); Objects.requireNonNull(postNode, "Find pattern failed for postNode"); diff --git a/src/main/java/com/matt/forgehax/asm/patches/EntityPlayerSPPatch.java b/src/main/java/com/matt/forgehax/asm/patches/EntityPlayerSPPatch.java index 812e07b60..087a1f5c0 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/EntityPlayerSPPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/EntityPlayerSPPatch.java @@ -1,7 +1,6 @@ package com.matt.forgehax.asm.patches; import static com.matt.forgehax.asm.utils.AsmPattern.CODE_ONLY; -import static org.objectweb.asm.Opcodes.*; import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; @@ -12,16 +11,26 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; - -/** Created on 11/13/2016 by fr1kin */ +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Created on 11/13/2016 by fr1kin + */ public class EntityPlayerSPPatch extends ClassTransformer { + public EntityPlayerSPPatch() { super(Classes.EntityPlayerSP); } @RegisterMethodTransformer private class ApplyLivingUpdate extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityPlayerSP_onLivingUpdate; @@ -30,13 +39,13 @@ public ASMMethod getMethod() { @Inject(description = "Add hook to disable the use slowdown effect") public void inject(MethodNode main) { AbstractInsnNode applySlowdownSpeedNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {IFNE, 0x00, 0x00, ALOAD, GETFIELD, DUP, GETFIELD, LDC, FMUL, PUTFIELD}, - "x??xxxxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{IFNE, 0x00, 0x00, ALOAD, GETFIELD, DUP, GETFIELD, LDC, FMUL, PUTFIELD}, + "x??xxxxxxx"); Objects.requireNonNull( - applySlowdownSpeedNode, "Find pattern failed for applySlowdownSpeedNode"); + applySlowdownSpeedNode, "Find pattern failed for applySlowdownSpeedNode"); // get label it jumps to LabelNode jumpTo = ((JumpInsnNode) applySlowdownSpeedNode).label; @@ -51,6 +60,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class OnUpdate extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityPlayerSP_onUpdate; @@ -61,15 +71,15 @@ public void inject(MethodNode main) { // AbstractInsnNode top = // ASMHelper.findPattern(main, INVOKESPECIAL, NONE, NONE, ALOAD, INVOKEVIRTUAL, IFEQ); AbstractInsnNode top = - new AsmPattern.Builder(CODE_ONLY) - .opcodes(INVOKESPECIAL, ALOAD, INVOKEVIRTUAL, IFEQ) - .build() - .test(main) - .getFirst(); + new AsmPattern.Builder(CODE_ONLY) + .opcodes(INVOKESPECIAL, ALOAD, INVOKEVIRTUAL, IFEQ) + .build() + .test(main) + .getFirst(); AbstractInsnNode afterRiding = ASMHelper.findPattern(main, GOTO); AbstractInsnNode afterWalking = - ASMHelper.findPattern(main, INVOKESPECIAL, NONE, NONE, NONE, RETURN); + ASMHelper.findPattern(main, INVOKESPECIAL, NONE, NONE, NONE, RETURN); AbstractInsnNode ret = ASMHelper.findPattern(main, RETURN); Objects.requireNonNull(top, "Find pattern failed for top node"); @@ -81,18 +91,18 @@ public void inject(MethodNode main) { InsnList pre = new InsnList(); pre.add(new VarInsnNode(ALOAD, 0)); pre.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onUpdateWalkingPlayerPre)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onUpdateWalkingPlayerPre)); pre.add(new JumpInsnNode(IFNE, jmp)); InsnList postRiding = new InsnList(); postRiding.add(new VarInsnNode(ALOAD, 0)); postRiding.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onUpdateWalkingPlayerPost)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onUpdateWalkingPlayerPost)); InsnList postWalking = new InsnList(); postWalking.add(new VarInsnNode(ALOAD, 0)); postWalking.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onUpdateWalkingPlayerPost)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onUpdateWalkingPlayerPost)); main.instructions.insert(top, pre); main.instructions.insertBefore(afterRiding, postRiding); @@ -103,6 +113,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class pushOutOfBlocks extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityPlayerSP_pushOutOfBlocks; @@ -112,7 +123,7 @@ public ASMMethod getMethod() { public void inject(MethodNode main) { AbstractInsnNode preNode = main.instructions.getFirst(); AbstractInsnNode postNode = - ASMHelper.findPattern(main.instructions.getFirst(), new int[] {ICONST_0, IRETURN}, "xx"); + ASMHelper.findPattern(main.instructions.getFirst(), new int[]{ICONST_0, IRETURN}, "xx"); Objects.requireNonNull(preNode, "Find pattern failed for pre node"); Objects.requireNonNull(postNode, "Find pattern failed for post node"); @@ -130,6 +141,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class RowingBoat extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityPlayerSP_isRowingBoat; diff --git a/src/main/java/com/matt/forgehax/asm/patches/EntityRendererPatch.java b/src/main/java/com/matt/forgehax/asm/patches/EntityRendererPatch.java index 243c38e79..3aefeb2db 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/EntityRendererPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/EntityRendererPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,15 +8,22 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; public class EntityRendererPatch extends ClassTransformer { + public EntityRendererPatch() { super(Classes.EntityRenderer); } @RegisterMethodTransformer private class HurtCameraEffect extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.EntityRenderer_hurtCameraEffect; @@ -28,7 +33,7 @@ public ASMMethod getMethod() { public void inject(MethodNode main) { AbstractInsnNode preNode = main.instructions.getFirst(); AbstractInsnNode postNode = - ASMHelper.findPattern(main.instructions.getFirst(), new int[] {RETURN}, "x"); + ASMHelper.findPattern(main.instructions.getFirst(), new int[]{RETURN}, "x"); Objects.requireNonNull(preNode, "Find pattern failed for preNode"); Objects.requireNonNull(postNode, "Find pattern failed for postNode"); diff --git a/src/main/java/com/matt/forgehax/asm/patches/KeyBindingPatch.java b/src/main/java/com/matt/forgehax/asm/patches/KeyBindingPatch.java index fa3f9bed8..aabf83dfc 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/KeyBindingPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/KeyBindingPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; import com.matt.forgehax.asm.utils.transforming.ClassTransformer; @@ -9,16 +7,21 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.MethodNode; -/** Created by Babbaj on 9/5/2017. */ +/** + * Created by Babbaj on 9/5/2017. + */ public class KeyBindingPatch extends ClassTransformer { + public KeyBindingPatch() { super(Classes.KeyBinding); } @RegisterMethodTransformer private class IsKeyDown extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.KeyBinding_isKeyDown; @@ -27,14 +30,14 @@ public ASMMethod getMethod() { @Inject(description = "Shut down forge's shit for GuiMove") public void inject(MethodNode main) { AbstractInsnNode node = - ASMHelper.findPattern( - main.instructions.getFirst(), new int[] {ALOAD, GETFIELD, IFEQ}, "xxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), new int[]{ALOAD, GETFIELD, IFEQ}, "xxx"); Objects.requireNonNull(node, "Find pattern failed for getfield node"); // Delete forge code AbstractInsnNode iteratorNode = - node.getNext().getNext(); // set the iterator to the IFEQ instruction + node.getNext().getNext(); // set the iterator to the IFEQ instruction while (iteratorNode.getOpcode() != IRETURN) { iteratorNode = iteratorNode.getNext(); main.instructions.remove(iteratorNode.getPrevious()); diff --git a/src/main/java/com/matt/forgehax/asm/patches/MinecraftPatch.java b/src/main/java/com/matt/forgehax/asm/patches/MinecraftPatch.java index 771a543d4..717e628fc 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/MinecraftPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/MinecraftPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,15 +8,20 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; public class MinecraftPatch extends ClassTransformer { + public MinecraftPatch() { super(Classes.Minecraft); } @RegisterMethodTransformer public class SetIngameFocus extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.Minecraft_setIngameFocus; @@ -27,10 +30,10 @@ public ASMMethod getMethod() { @Inject(description = "Add callback before setting leftclick timer") public void inject(MethodNode method) { AbstractInsnNode node = - ASMHelper.findPattern( - method.instructions.getFirst(), - new int[] {SIPUSH, PUTFIELD, 0, 0, 0, RETURN}, - "xx???x"); + ASMHelper.findPattern( + method.instructions.getFirst(), + new int[]{SIPUSH, PUTFIELD, 0, 0, 0, RETURN}, + "xx???x"); Objects.requireNonNull(node, "Failed to find SIPUSH node"); InsnList list = new InsnList(); @@ -43,6 +46,7 @@ public void inject(MethodNode method) { @RegisterMethodTransformer public class RunTick extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.Minecraft_runTick; @@ -51,24 +55,24 @@ public ASMMethod getMethod() { @Inject(description = "Add callback before setting leftclick timer") public void inject(MethodNode method) { AbstractInsnNode node = - ASMHelper.findPattern( - method.instructions.getFirst(), - new int[] { - SIPUSH, - PUTFIELD, - 0, - 0, - 0, - ALOAD, - GETFIELD, - IFNULL, - 0, - 0, - ALOAD, - GETFIELD, - INVOKEVIRTUAL - }, - "xx???xxx??xxx"); + ASMHelper.findPattern( + method.instructions.getFirst(), + new int[]{ + SIPUSH, + PUTFIELD, + 0, + 0, + 0, + ALOAD, + GETFIELD, + IFNULL, + 0, + 0, + ALOAD, + GETFIELD, + INVOKEVIRTUAL + }, + "xx???xxx??xxx"); Objects.requireNonNull(node, "Failed to find SIPUSH node"); InsnList list = new InsnList(); @@ -81,6 +85,7 @@ public void inject(MethodNode method) { @RegisterMethodTransformer public class SendClickBlockToController extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.Minecraft_sendClickBlockToController; @@ -92,8 +97,8 @@ public void inject(MethodNode method) { list.add(new VarInsnNode(ALOAD, 0)); list.add(new VarInsnNode(ILOAD, 1)); list.add( - ASMHelper.call( - INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onSendClickBlockToController)); + ASMHelper.call( + INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onSendClickBlockToController)); list.add(new VarInsnNode(ISTORE, 1)); method.instructions.insert(list); diff --git a/src/main/java/com/matt/forgehax/asm/patches/NetManager$4Patch.java b/src/main/java/com/matt/forgehax/asm/patches/NetManager$4Patch.java index 7ff4861ce..f54d8a38a 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/NetManager$4Patch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/NetManager$4Patch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,15 +8,22 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; public class NetManager$4Patch extends ClassTransformer { + public NetManager$4Patch() { super(Classes.NetworkManager$4); } @RegisterMethodTransformer private class Run extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.NetworkManager$4_run; @@ -27,13 +32,13 @@ public ASMMethod getMethod() { @Inject(description = "Add a pre and post hook that allows the method to be disabled") public void inject(MethodNode main) { AbstractInsnNode preNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, GETFIELD, ALOAD, GETFIELD, IF_ACMPEQ}, - "xxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, GETFIELD, ALOAD, GETFIELD, IF_ACMPEQ}, + "xxxxx"); AbstractInsnNode postNode = - ASMHelper.findPattern(main.instructions.getFirst(), new int[] {RETURN}, "x"); + ASMHelper.findPattern(main.instructions.getFirst(), new int[]{RETURN}, "x"); Objects.requireNonNull(preNode, "Find pattern failed for preNode"); Objects.requireNonNull(postNode, "Find pattern failed for postNode"); diff --git a/src/main/java/com/matt/forgehax/asm/patches/NetManagerPatch.java b/src/main/java/com/matt/forgehax/asm/patches/NetManagerPatch.java index 59bdd5cfc..f012e6d23 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/NetManagerPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/NetManagerPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,15 +8,22 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; public class NetManagerPatch extends ClassTransformer { + public NetManagerPatch() { super(Classes.NetworkManager); } @RegisterMethodTransformer private class DispatchPacket extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.NetworkManager_dispatchPacket; @@ -27,29 +32,29 @@ public ASMMethod getMethod() { @Inject(description = "Add pre and post hooks that allow method to be disabled") public void inject(MethodNode main) { AbstractInsnNode preNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - ALOAD, - ALOAD, - IF_ACMPEQ, - ALOAD, - INSTANCEOF, - IFNE, - 0x00, - 0x00, - ALOAD, - ALOAD, - INVOKEVIRTUAL - }, - "xxxxxx??xxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + ALOAD, + ALOAD, + IF_ACMPEQ, + ALOAD, + INSTANCEOF, + IFNE, + 0x00, + 0x00, + ALOAD, + ALOAD, + INVOKEVIRTUAL + }, + "xxxxxx??xxx"); AbstractInsnNode postNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - POP, 0x00, 0x00, GOTO, 0x00, 0x00, 0x00, ALOAD, GETFIELD, INVOKEINTERFACE, NEW, DUP - }, - "x??x???xxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + POP, 0x00, 0x00, GOTO, 0x00, 0x00, 0x00, ALOAD, GETFIELD, INVOKEINTERFACE, NEW, DUP + }, + "x??x???xxxxx"); Objects.requireNonNull(preNode, "Find pattern failed for preNode"); Objects.requireNonNull(postNode, "Find pattern failed for postNode"); @@ -73,6 +78,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class ChannelRead0 extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.NetworkManager_channelRead0; @@ -81,17 +87,17 @@ public ASMMethod getMethod() { @Inject(description = "Add pre and post hook that allows the method to be disabled") public void inject(MethodNode main) { AbstractInsnNode preNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, ALOAD, GETFIELD, INVOKEINTERFACE}, - "xxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, ALOAD, GETFIELD, INVOKEINTERFACE}, + "xxxx"); AbstractInsnNode postNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - INVOKEINTERFACE, 0x00, 0x00, GOTO, - }, - "x??x"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + INVOKEINTERFACE, 0x00, 0x00, GOTO, + }, + "x??x"); Objects.requireNonNull(preNode, "Find pattern failed for preNode"); Objects.requireNonNull(postNode, "Find pattern failed for postNode"); diff --git a/src/main/java/com/matt/forgehax/asm/patches/PlayerControllerMCPatch.java b/src/main/java/com/matt/forgehax/asm/patches/PlayerControllerMCPatch.java index 79be5fe1d..79980fcc1 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/PlayerControllerMCPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/PlayerControllerMCPatch.java @@ -1,12 +1,6 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.ALOAD; -import static org.objectweb.asm.Opcodes.IFNE; -import static org.objectweb.asm.Opcodes.INVOKESTATIC; -import static org.objectweb.asm.Opcodes.RETURN; - import com.matt.forgehax.asm.TypesHook; -import com.matt.forgehax.asm.TypesHook.Methods; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; import com.matt.forgehax.asm.utils.transforming.ClassTransformer; @@ -22,12 +16,14 @@ import org.objectweb.asm.tree.VarInsnNode; public class PlayerControllerMCPatch extends ClassTransformer { + public PlayerControllerMCPatch() { super(Classes.PlayerControllerMP); } @RegisterMethodTransformer public class SyncCurrentPlayItem extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.PlayerControllerMC_syncCurrentPlayItem; @@ -45,6 +41,7 @@ public void inject(MethodNode node) { @RegisterMethodTransformer public class AttackEntity extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.PlayerControllerMC_attackEntity; @@ -64,6 +61,7 @@ public void inject(MethodNode node) { @RegisterMethodTransformer public class OnPlayerDamageBlock extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.PlayerControllerMC_onPlayerDamageBlock; @@ -83,6 +81,7 @@ public void inject(MethodNode node) { @RegisterMethodTransformer public class OnStoppedUsingItem extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.PlayerControllerMC_onStoppedUsingItem; @@ -91,7 +90,7 @@ public ASMMethod getMethod() { @Inject(description = "Add callback at top of method") public void inject(MethodNode node) { AbstractInsnNode last = - ASMHelper.findPattern(node.instructions.getFirst(), new int[] {RETURN}, "x"); + ASMHelper.findPattern(node.instructions.getFirst(), new int[]{RETURN}, "x"); Objects.requireNonNull(last, "Could not find RET opcode"); diff --git a/src/main/java/com/matt/forgehax/asm/patches/PlayerTabOverlayPatch.java b/src/main/java/com/matt/forgehax/asm/patches/PlayerTabOverlayPatch.java index d945097e3..b3ac32ccc 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/PlayerTabOverlayPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/PlayerTabOverlayPatch.java @@ -1,9 +1,6 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; -import com.matt.forgehax.asm.TypesHook.Methods; import com.matt.forgehax.asm.events.RenderTabNameEvent; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.AsmPattern; @@ -15,16 +12,28 @@ import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; import org.objectweb.asm.Type; -import org.objectweb.asm.tree.*; - -/** Created by Babbaj on 8/9/2017. thanks 086 :3 */ +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Created by Babbaj on 8/9/2017. thanks 086 :3 + */ public class PlayerTabOverlayPatch extends ClassTransformer { + public PlayerTabOverlayPatch() { super(Classes.GuiPlayerTabOverlay); } @RegisterMethodTransformer private class RenderPlayerlist_renderIcon extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.PlayerTabOverlay_renderPlayerList; @@ -33,19 +42,19 @@ public ASMMethod getMethod() { @Inject(description = "Add hook to increase the size of the tab list") public void inject(MethodNode main) { AbstractInsnNode subListNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - ALOAD, - ICONST_0, - ALOAD, - INVOKEINTERFACE, - BIPUSH, - INVOKESTATIC, - INVOKEINTERFACE, - ASTORE - }, - "xxxxxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + ALOAD, + ICONST_0, + ALOAD, + INVOKEINTERFACE, + BIPUSH, + INVOKESTATIC, + INVOKEINTERFACE, + ASTORE + }, + "xxxxxxxx"); AbstractInsnNode astoreNode = subListNode; for (int i = 0; i < 7; i++) { @@ -68,6 +77,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class RenderPlayerlist_renderName extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.PlayerTabOverlay_renderPlayerList; @@ -76,34 +86,34 @@ public ASMMethod getMethod() { @Inject(description = "Add hook to change color of names in player list") public void inject(MethodNode main) { // TODO: do this better final LabelNode eventVarStart = - (LabelNode) - new AsmPattern.Builder(AsmPattern.IGNORE_FRAMES | AsmPattern.IGNORE_LINENUMBERS) - .custom( - insn -> - insn.getOpcode() == ALOAD - && ((VarInsnNode) insn).var == 24) // networkplayerinfo1 - .opcodes( - INVOKEVIRTUAL, - GETSTATIC, - IF_ACMPNE) // if (networkplayerinfo1.getGameType() == GameType.SPECTATOR) - .build() - .test(main) - .getLast() - .getNext(); // start of the scope of the new local var + (LabelNode) + new AsmPattern.Builder(AsmPattern.IGNORE_FRAMES | AsmPattern.IGNORE_LINENUMBERS) + .custom( + insn -> + insn.getOpcode() == ALOAD + && ((VarInsnNode) insn).var == 24) // networkplayerinfo1 + .opcodes( + INVOKEVIRTUAL, + GETSTATIC, + IF_ACMPNE) // if (networkplayerinfo1.getGameType() == GameType.SPECTATOR) + .build() + .test(main) + .getLast() + .getNext(); // start of the scope of the new local var final AsmPattern getFontRendererPattern = - new AsmPattern.Builder(AsmPattern.CODE_ONLY) - .custom(insn -> insn.getOpcode() == ALOAD && ((VarInsnNode) insn).var == 0) // this - .opcodes(GETFIELD, GETFIELD) - .build(); + new AsmPattern.Builder(AsmPattern.CODE_ONLY) + .custom(insn -> insn.getOpcode() == ALOAD && ((VarInsnNode) insn).var == 0) // this + .opcodes(GETFIELD, GETFIELD) + .build(); final AsmPattern drawStringPattern = - new AsmPattern.Builder(AsmPattern.CODE_ONLY) - .opcodes(ILOAD, I2F, ILOAD, I2F) - .any() // color - .opcode(INVOKEVIRTUAL) - .opcode(POP) - .build(); + new AsmPattern.Builder(AsmPattern.CODE_ONLY) + .opcodes(ILOAD, I2F, ILOAD, I2F) + .any() // color + .opcode(INVOKEVIRTUAL) + .opcode(POP) + .build(); final int index_s4 = 26; // TODO: get this dynamically @@ -114,15 +124,15 @@ public void inject(MethodNode main) { // TODO: do this better final InsnPattern renderNormal = drawStringPattern.test(renderSpectator.getLast()); final LabelNode eventVarEnd = - ((JumpInsnNode) renderSpectator.getLast().getNext()).label; // label from the goto + ((JumpInsnNode) renderSpectator.getLast().getNext()).label; // label from the goto final int eventVar = - ASMHelper.addNewLocalVariable( - main, - "event", - Type.getDescriptor(RenderTabNameEvent.class), - eventVarStart, - eventVarEnd); + ASMHelper.addNewLocalVariable( + main, + "event", + Type.getDescriptor(RenderTabNameEvent.class), + eventVarStart, + eventVarEnd); createAndFireEvent(main, renderSpectatorPre.getLast(), eventVar, index_s4); createAndFireEvent(main, renderNormalPre.getLast(), eventVar, index_s4); @@ -136,8 +146,8 @@ private void replaceConstant(MethodNode method, AbstractInsnNode node, int event InsnList list = new InsnList(); list.add(new VarInsnNode(ALOAD, eventVar)); list.add( - new MethodInsnNode( - INVOKEVIRTUAL, Type.getInternalName(RenderTabNameEvent.class), "getColor", "()I")); + new MethodInsnNode( + INVOKEVIRTUAL, Type.getInternalName(RenderTabNameEvent.class), "getColor", "()I")); method.instructions.insert(node, list); // insert at constant method.instructions.remove(node); // remove constant @@ -145,7 +155,7 @@ private void replaceConstant(MethodNode method, AbstractInsnNode node, int event // creates and fires the event, sets the variable for the event and sets name variable private void createAndFireEvent( - MethodNode method, AbstractInsnNode location, int variableIndex, int nameIndex) { + MethodNode method, AbstractInsnNode location, int variableIndex, int nameIndex) { final InsnList list = new InsnList(); // arguments @@ -154,20 +164,20 @@ private void createAndFireEvent( eventObjectArgs.add(new LdcInsnNode(-1)); // TODO: get original value list.add( - ASMHelper.newInstance( - Type.getInternalName(RenderTabNameEvent.class), - "(Ljava/lang/String;I)V", - eventObjectArgs)); + ASMHelper.newInstance( + Type.getInternalName(RenderTabNameEvent.class), + "(Ljava/lang/String;I)V", + eventObjectArgs)); list.add(new InsnNode(DUP)); // for firing event list.add(new InsnNode(DUP)); // for getName list.add(new VarInsnNode(ASTORE, variableIndex)); list.add(ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_fireEvent_v)); list.add( - new MethodInsnNode( - INVOKEVIRTUAL, - Type.getInternalName(RenderTabNameEvent.class), - "getName", - "()Ljava/lang/String;")); + new MethodInsnNode( + INVOKEVIRTUAL, + Type.getInternalName(RenderTabNameEvent.class), + "getName", + "()Ljava/lang/String;")); list.add(new VarInsnNode(ASTORE, nameIndex)); method.instructions.insert(location, list); diff --git a/src/main/java/com/matt/forgehax/asm/patches/RenderBoatPatch.java b/src/main/java/com/matt/forgehax/asm/patches/RenderBoatPatch.java index 3fe841a1b..284beed7e 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/RenderBoatPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/RenderBoatPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -9,16 +7,22 @@ import com.matt.forgehax.asm.utils.transforming.Inject; import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; -/** Created by Babbaj on 8/9/2017. */ +/** + * Created by Babbaj on 8/9/2017. + */ public class RenderBoatPatch extends ClassTransformer { + public RenderBoatPatch() { super(Classes.RenderBoat); } @RegisterMethodTransformer private class DoRender extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.RenderBoat_doRender; @@ -32,10 +36,10 @@ public void inject(MethodNode main) { insnList.add(new VarInsnNode(ALOAD, 1)); // load the boat entity insnList.add(new VarInsnNode(FLOAD, 8)); // load the boat yaw insnList.add( - ASMHelper.call( - INVOKESTATIC, - TypesHook.Methods - .ForgeHaxHooks_onRenderBoat)); // fire the event and get the value(player + ASMHelper.call( + INVOKESTATIC, + TypesHook.Methods + .ForgeHaxHooks_onRenderBoat)); // fire the event and get the value(player // rotationYaw) returned by the method in // ForgeHaxHooks insnList.add(new VarInsnNode(FSTORE, 8)); // store it in entityYaw diff --git a/src/main/java/com/matt/forgehax/asm/patches/RenderChunkPatch.java b/src/main/java/com/matt/forgehax/asm/patches/RenderChunkPatch.java index d8607b953..39ffae44f 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/RenderChunkPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/RenderChunkPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,16 +8,27 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; - -/** Created on 5/5/2017 by fr1kin */ +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FrameNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Created on 5/5/2017 by fr1kin + */ public class RenderChunkPatch extends ClassTransformer { + public RenderChunkPatch() { super(Classes.RenderChunk); } @RegisterMethodTransformer private class RebuildChunk extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.RenderChunk_rebuildChunk; @@ -29,10 +38,10 @@ public ASMMethod getMethod() { public void inject(MethodNode main) { // searches for ++renderChunksUpdated; AbstractInsnNode top = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {GETSTATIC, ICONST_1, IADD, PUTSTATIC}, - "xxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{GETSTATIC, ICONST_1, IADD, PUTSTATIC}, + "xxxx"); Objects.requireNonNull(top, "Find pattern failed for top"); @@ -41,22 +50,22 @@ public void inject(MethodNode main) { // <--- inject somewhere here // if (iblockstate.isOpaqueCube()) AbstractInsnNode loop = - ASMHelper.findPattern( - top, - new int[] { - ASTORE, - 0x00, - 0x00, - ALOAD, - INVOKEINTERFACE, - ASTORE, - 0x00, - 0x00, - ALOAD, - INVOKEINTERFACE, - IFEQ - }, - "x??xxx??xxx"); + ASMHelper.findPattern( + top, + new int[]{ + ASTORE, + 0x00, + 0x00, + ALOAD, + INVOKEINTERFACE, + ASTORE, + 0x00, + 0x00, + ALOAD, + INVOKEINTERFACE, + IFEQ + }, + "x??xxx??xxx"); Objects.requireNonNull(loop, "Find pattern failed for loop"); @@ -112,7 +121,7 @@ public void inject(MethodNode main) { patch.add(new FrameNode(F_SAME, 0, null, 0, null)); patch.add(new InsnNode(ICONST_0)); patch.add(jumpPast); - patch.add(new FrameNode(F_SAME1, 0, null, 1, new Object[] {INTEGER})); + patch.add(new FrameNode(F_SAME1, 0, null, 1, new Object[]{INTEGER})); patch.add(new InsnNode(DUP)); patch.add(new VarInsnNode(ISTORE, STORE_AT)); patch.add(new JumpInsnNode(IFEQ, skipRenderingLabel)); @@ -149,14 +158,18 @@ public void inject(MethodNode main) { // for the index of blockpos$mutableblockpos, which SHOULD be the last ALOAD // i have to do this because optifine changes up the code at that line AbstractInsnNode prev = loop; - while (prev.getOpcode() != ALOAD) prev = prev.getPrevious(); + while (prev.getOpcode() != ALOAD) { + prev = prev.getPrevious(); + } int BLOCK_POS_INDEX = ((VarInsnNode) prev).var; // now find block // should just be the next ASTORE starting at the loop node AbstractInsnNode next2 = loop.getNext(); - while (next2.getOpcode() != ASTORE) next2 = next2.getNext(); + while (next2.getOpcode() != ASTORE) { + next2 = next2.getNext(); + } int BLOCK_INDEX = ((VarInsnNode) next2).var; @@ -191,6 +204,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class DeleteGlResources extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.RenderChunk_deleteGlResources; @@ -205,7 +219,7 @@ public void inject(MethodNode main) { InsnList insnList = new InsnList(); insnList.add(new VarInsnNode(ALOAD, 0)); insnList.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onDeleteGlResources)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onDeleteGlResources)); main.instructions.insertBefore(node, insnList); } diff --git a/src/main/java/com/matt/forgehax/asm/patches/RenderGlobalPatch.java b/src/main/java/com/matt/forgehax/asm/patches/RenderGlobalPatch.java index 75d80b625..d443731b8 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/RenderGlobalPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/RenderGlobalPatch.java @@ -1,9 +1,6 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; -import com.matt.forgehax.asm.TypesHook.Methods; import com.matt.forgehax.asm.events.DrawBlockBoundingBoxEvent; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -12,16 +9,25 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; import scala.tools.asm.Type; public class RenderGlobalPatch extends ClassTransformer { + public RenderGlobalPatch() { super(Classes.RenderGlobal); } @RegisterMethodTransformer private class LoadRenderers extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.RenderGlobal_loadRenderers; @@ -30,10 +36,10 @@ public ASMMethod getMethod() { @Inject(description = "At hook callback at end of method") public void inject(MethodNode main) { AbstractInsnNode node = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {PUTFIELD, 0x00, 0x00, 0x00, RETURN}, - "x???x"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{PUTFIELD, 0x00, 0x00, 0x00, RETURN}, + "x???x"); Objects.requireNonNull(node, "Find pattern failed for node"); @@ -50,6 +56,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class RenderBlockLayer extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.RenderGlobal_renderBlockLayer; @@ -58,27 +65,27 @@ public ASMMethod getMethod() { @Inject(description = "Add hooks at the top and bottom of the method") public void inject(MethodNode main) { AbstractInsnNode preNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - INVOKESTATIC, - 0x00, - 0x00, - ALOAD, - GETSTATIC, - IF_ACMPNE, - 0x00, - 0x00, - ALOAD, - GETFIELD, - GETFIELD - }, - "x??xxx??xxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + INVOKESTATIC, + 0x00, + 0x00, + ALOAD, + GETSTATIC, + IF_ACMPNE, + 0x00, + 0x00, + ALOAD, + GETFIELD, + GETFIELD + }, + "x??xxx??xxx"); AbstractInsnNode postNode = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, GETFIELD, GETFIELD, INVOKEVIRTUAL, 0x00, 0x00, ILOAD, IRETURN}, - "xxxx??xx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, GETFIELD, GETFIELD, INVOKEVIRTUAL, 0x00, 0x00, ILOAD, IRETURN}, + "xxxx??xx"); Objects.requireNonNull(preNode, "Find pattern failed for preNode"); Objects.requireNonNull(postNode, "Find pattern failed for postNode"); @@ -91,14 +98,14 @@ public void inject(MethodNode main) { insnPre.add(new VarInsnNode(ALOAD, 1)); insnPre.add(new VarInsnNode(DLOAD, 2)); insnPre.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onPreRenderBlockLayer)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onPreRenderBlockLayer)); insnPre.add(new JumpInsnNode(IFNE, endJump)); InsnList insnPost = new InsnList(); insnPost.add(new VarInsnNode(ALOAD, 1)); insnPost.add(new VarInsnNode(DLOAD, 2)); insnPost.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onPostRenderBlockLayer)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onPostRenderBlockLayer)); insnPost.add(endJump); main.instructions.insertBefore(preNode, insnPre); @@ -108,6 +115,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class SetupTerrain extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.RenderGlobal_setupTerrain; @@ -116,10 +124,10 @@ public ASMMethod getMethod() { @Inject(description = "Add hook at the top of the method") public void inject(MethodNode main) { AbstractInsnNode node = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] {ALOAD, GETFIELD, GETFIELD, GETFIELD, ALOAD}, - "xxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ALOAD, GETFIELD, GETFIELD, GETFIELD, ALOAD}, + "xxxxx"); Objects.requireNonNull(node, "Find pattern failed for node"); @@ -136,32 +144,32 @@ public void inject(MethodNode main) { public void injectAtFlag(MethodNode main) { // inject at this.mc.renderChunksMany AbstractInsnNode node = - ASMHelper.findPattern( - main.instructions.getFirst(), - new int[] { - ISTORE, - 0x00, - 0x00, - ALOAD, - IFNULL, - 0x00, - 0x00, - ICONST_0, - ISTORE, - 0x00, - 0x00, - NEW, - DUP, - ALOAD, - ALOAD, - ACONST_NULL, - CHECKCAST, - ICONST_0, - ACONST_NULL, - INVOKESPECIAL, - ASTORE - }, - "x??xx??xx??xxxxxxxxxx"); + ASMHelper.findPattern( + main.instructions.getFirst(), + new int[]{ + ISTORE, + 0x00, + 0x00, + ALOAD, + IFNULL, + 0x00, + 0x00, + ICONST_0, + ISTORE, + 0x00, + 0x00, + NEW, + DUP, + ALOAD, + ALOAD, + ACONST_NULL, + CHECKCAST, + ICONST_0, + ACONST_NULL, + INVOKESPECIAL, + ASTORE + }, + "x??xx??xx??xxxxxxxxxx"); Objects.requireNonNull(node, "Find pattern failed for node"); @@ -171,7 +179,7 @@ public void injectAtFlag(MethodNode main) { InsnList insnList = new InsnList(); insnList.add(new JumpInsnNode(IFEQ, falseLabel)); insnList.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_shouldDisableCaveCulling)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_shouldDisableCaveCulling)); insnList.add(new JumpInsnNode(IFNE, falseLabel)); insnList.add(new InsnNode(ICONST_1)); insnList.add(new JumpInsnNode(GOTO, storeLabel)); @@ -198,8 +206,8 @@ public void inject(MethodNode main) { AbstractInsnNode end = ASMHelper.findPattern(start, RETURN); final int eventIndex = - ASMHelper.addNewLocalVariable( - main, "forgehax_event", Type.getDescriptor(DrawBlockBoundingBoxEvent.Pre.class)); + ASMHelper.addNewLocalVariable( + main, "forgehax_event", Type.getDescriptor(DrawBlockBoundingBoxEvent.Pre.class)); InsnList pushArgs = new InsnList(); pushArgs.add(new VarInsnNode(FLOAD, 12)); @@ -208,8 +216,8 @@ public void inject(MethodNode main) { pushArgs.add(new VarInsnNode(FLOAD, 15)); InsnList newEvent = - ASMHelper.newInstance( - Type.getInternalName(DrawBlockBoundingBoxEvent.Pre.class), "(FFFF)V", pushArgs); + ASMHelper.newInstance( + Type.getInternalName(DrawBlockBoundingBoxEvent.Pre.class), "(FFFF)V", pushArgs); final InsnList pre = new InsnList(); pre.add(newEvent); @@ -223,7 +231,7 @@ public void inject(MethodNode main) { final InsnList post = new InsnList(); post.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onDrawBoundingBox_Post)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onDrawBoundingBox_Post)); main.instructions.insert(start, pre); main.instructions.insertBefore(end, post); @@ -233,8 +241,8 @@ private InsnList setColor(int eventIndex, String field, int colorIndex) { InsnList list = new InsnList(); list.add(new VarInsnNode(ALOAD, eventIndex)); list.add( - new FieldInsnNode( - GETFIELD, Type.getInternalName(DrawBlockBoundingBoxEvent.class), field, "F")); + new FieldInsnNode( + GETFIELD, Type.getInternalName(DrawBlockBoundingBoxEvent.class), field, "F")); list.add(new VarInsnNode(FSTORE, colorIndex)); return list; diff --git a/src/main/java/com/matt/forgehax/asm/patches/VisGraphPatch.java b/src/main/java/com/matt/forgehax/asm/patches/VisGraphPatch.java index 895f66ef8..ac115f145 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/VisGraphPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/VisGraphPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,15 +8,21 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; public class VisGraphPatch extends ClassTransformer { + public VisGraphPatch() { super(Classes.VisGraph); } @RegisterMethodTransformer private class SetOpaqueCube extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.VisGraph_setOpaqueCube; @@ -28,7 +32,7 @@ public ASMMethod getMethod() { public void inject(MethodNode main) { AbstractInsnNode top = main.instructions.getFirst(); AbstractInsnNode bottom = - ASMHelper.findPattern(main.instructions.getFirst(), new int[] {RETURN}, "x"); + ASMHelper.findPattern(main.instructions.getFirst(), new int[]{RETURN}, "x"); Objects.requireNonNull(top, "Find pattern failed for top"); Objects.requireNonNull(bottom, "Find pattern failed for bottom"); @@ -37,7 +41,7 @@ public void inject(MethodNode main) { InsnList insnList = new InsnList(); insnList.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_shouldDisableCaveCulling)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_shouldDisableCaveCulling)); insnList.add(new JumpInsnNode(IFNE, cancelNode)); main.instructions.insertBefore(top, insnList); @@ -47,6 +51,7 @@ public void inject(MethodNode main) { @RegisterMethodTransformer private class ComputeVisibility extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.VisGraph_computeVisibility; @@ -54,11 +59,11 @@ public ASMMethod getMethod() { @Inject( description = - "Add hook that adds or logic to the jump that checks if setAllVisible(true) should be called" + "Add hook that adds or logic to the jump that checks if setAllVisible(true) should be called" ) public void inject(MethodNode main) { AbstractInsnNode node = - ASMHelper.findPattern(main.instructions.getFirst(), new int[] {SIPUSH, IF_ICMPGE}, "xx"); + ASMHelper.findPattern(main.instructions.getFirst(), new int[]{SIPUSH, IF_ICMPGE}, "xx"); Objects.requireNonNull(node, "Find pattern failed for node"); @@ -73,7 +78,7 @@ public void inject(MethodNode main) { InsnList insnList = new InsnList(); insnList.add(new JumpInsnNode(IF_ICMPLT, orLabel)); insnList.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_shouldDisableCaveCulling)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_shouldDisableCaveCulling)); insnList.add(new JumpInsnNode(IFEQ, nextIfStatement)); insnList.add(orLabel); diff --git a/src/main/java/com/matt/forgehax/asm/patches/WorldPatch.java b/src/main/java/com/matt/forgehax/asm/patches/WorldPatch.java index fb8d804b4..351146fec 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/WorldPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/WorldPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.utils.ASMHelper; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -10,15 +8,23 @@ import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; import java.util.Objects; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; public class WorldPatch extends ClassTransformer { + public WorldPatch() { super(Classes.World); } @RegisterMethodTransformer private class HandleMaterialAcceleration extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.World_handleMaterialAcceleration; @@ -27,31 +33,31 @@ public ASMMethod getMethod() { @Inject(description = "Add hook that allows water movement math to be skipped") public void inject(MethodNode method) { AbstractInsnNode preNode = - ASMHelper.findPattern( - method.instructions.getFirst(), - new int[] { - ALOAD, - INVOKEVIRTUAL, - ASTORE, - 0x00, - 0x00, - LDC, - DSTORE, - 0x00, - 0x00, - ALOAD, - DUP, - GETFIELD, - ALOAD, - GETFIELD, - LDC, - DMUL, - DADD, - PUTFIELD - }, - "xxx??xx??xxxxxxxxx"); + ASMHelper.findPattern( + method.instructions.getFirst(), + new int[]{ + ALOAD, + INVOKEVIRTUAL, + ASTORE, + 0x00, + 0x00, + LDC, + DSTORE, + 0x00, + 0x00, + ALOAD, + DUP, + GETFIELD, + ALOAD, + GETFIELD, + LDC, + DMUL, + DADD, + PUTFIELD + }, + "xxx??xx??xxxxxxxxx"); AbstractInsnNode postNode = - ASMHelper.findPattern(method.instructions.getFirst(), new int[] {ILOAD, IRETURN}, "xx"); + ASMHelper.findPattern(method.instructions.getFirst(), new int[]{ILOAD, IRETURN}, "xx"); Objects.requireNonNull(preNode, "Find pattern failed for preNode"); Objects.requireNonNull(postNode, "Find pattern failed for postNode"); @@ -71,6 +77,7 @@ public void inject(MethodNode method) { @RegisterMethodTransformer private class CheckLightFor extends MethodTransformer { + @Override public ASMMethod getMethod() { return Methods.World_checkLightFor; diff --git a/src/main/java/com/matt/forgehax/asm/patches/special/SchematicPrinterPatch.java b/src/main/java/com/matt/forgehax/asm/patches/special/SchematicPrinterPatch.java index bf458faa4..7968f0585 100644 --- a/src/main/java/com/matt/forgehax/asm/patches/special/SchematicPrinterPatch.java +++ b/src/main/java/com/matt/forgehax/asm/patches/special/SchematicPrinterPatch.java @@ -1,7 +1,5 @@ package com.matt.forgehax.asm.patches.special; -import static org.objectweb.asm.Opcodes.*; - import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.TypesSpecial; import com.matt.forgehax.asm.utils.ASMHelper; @@ -11,10 +9,16 @@ import com.matt.forgehax.asm.utils.transforming.Inject; import com.matt.forgehax.asm.utils.transforming.MethodTransformer; import com.matt.forgehax.asm.utils.transforming.RegisterMethodTransformer; -import org.objectweb.asm.tree.*; - -/** Created on 9/20/2017 by Babbaj TODO: Fix obfuscation problem so this can work */ +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Created on 9/20/2017 by Babbaj TODO: Fix obfuscation problem so this can work + */ public class SchematicPrinterPatch extends ClassTransformer { + public SchematicPrinterPatch() { super(TypesSpecial.Classes.SchematicPrinter); } @@ -41,7 +45,7 @@ public void inject(MethodNode main) { insnList.add(new VarInsnNode(ALOAD, 4)); // load BlockPos insnList.add(new VarInsnNode(ALOAD, 6)); // load Vec insnList.add( - ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onSchematicaPlaceBlock)); + ASMHelper.call(INVOKESTATIC, TypesHook.Methods.ForgeHaxHooks_onSchematicaPlaceBlock)); main.instructions.insertBefore(start, insnList); } diff --git a/src/main/java/com/matt/forgehax/asm/reflection/FastReflection.java b/src/main/java/com/matt/forgehax/asm/reflection/FastReflection.java index 204a47057..608f2564f 100644 --- a/src/main/java/com/matt/forgehax/asm/reflection/FastReflection.java +++ b/src/main/java/com/matt/forgehax/asm/reflection/FastReflection.java @@ -58,522 +58,598 @@ import net.minecraft.world.chunk.storage.AnvilChunkLoader; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; -/** Created on 5/8/2017 by fr1kin */ +/** + * Created on 5/8/2017 by fr1kin + */ public interface FastReflection extends ASMCommon { + // **************************************** // FIELDS // **************************************** interface Fields { - /** ActiveRenderInfo */ + + /** + * ActiveRenderInfo + */ FastField ActiveRenderInfo_MODELVIEW = - FastTypeBuilder.create() - .setInsideClass(ActiveRenderInfo.class) - .setName("MODELVIEW") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(ActiveRenderInfo.class) + .setName("MODELVIEW") + .autoAssign() + .asField(); + FastField ActiveRenderInfo_PROJECTION = - FastTypeBuilder.create() - .setInsideClass(ActiveRenderInfo.class) - .setName("PROJECTION") - .autoAssign() - .asField(); + FastTypeBuilder.create() + .setInsideClass(ActiveRenderInfo.class) + .setName("PROJECTION") + .autoAssign() + .asField(); FastField ActiveRenderInfo_position = - FastTypeBuilder.create() - .setInsideClass(ActiveRenderInfo.class) - .setName("position") - .autoAssign() - .asField(); - - /** CPacketPlayer */ + FastTypeBuilder.create() + .setInsideClass(ActiveRenderInfo.class) + .setName("position") + .autoAssign() + .asField(); + + /** + * CPacketPlayer + */ FastField CPacketPlayer_pitch = - FastTypeBuilder.create() - .setInsideClass(CPacketPlayer.class) - .setName("pitch") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(CPacketPlayer.class) + .setName("pitch") + .autoAssign() + .asField(); + FastField CPacketPlayer_yaw = - FastTypeBuilder.create() - .setInsideClass(CPacketPlayer.class) - .setName("yaw") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(CPacketPlayer.class) + .setName("yaw") + .autoAssign() + .asField(); + FastField CPacketPlayer_moving = - FastTypeBuilder.create() - .setInsideClass(CPacketPlayer.class) - .setName("moving") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(CPacketPlayer.class) + .setName("moving") + .autoAssign() + .asField(); + FastField CPacketPlayer_rotating = - FastTypeBuilder.create() - .setInsideClass(CPacketPlayer.class) - .setName("rotating") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(CPacketPlayer.class) + .setName("rotating") + .autoAssign() + .asField(); + FastField CPacketPlayer_onGround = - FastTypeBuilder.create() - .setInsideClass(CPacketPlayer.class) - .setName("onGround") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(CPacketPlayer.class) + .setName("onGround") + .autoAssign() + .asField(); + FastField CPacketPlayer_x = - FastTypeBuilder.create() - .setInsideClass(CPacketPlayer.class) - .setName("x") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(CPacketPlayer.class) + .setName("x") + .autoAssign() + .asField(); + FastField CPacketPlayer_y = - FastTypeBuilder.create() - .setInsideClass(CPacketPlayer.class) - .setName("y") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(CPacketPlayer.class) + .setName("y") + .autoAssign() + .asField(); + FastField CPacketPlayer_z = - FastTypeBuilder.create() - .setInsideClass(CPacketPlayer.class) - .setName("z") - .autoAssign() - .asField(); - - /** CPacketVehicleMove */ + FastTypeBuilder.create() + .setInsideClass(CPacketPlayer.class) + .setName("z") + .autoAssign() + .asField(); + /** + * CPacketVehicleMove + */ FastField CPacketVehicleMove_yaw = - FastTypeBuilder.create() - .setInsideClass(CPacketVehicleMove.class) - .setName("yaw") - .autoAssign() - .asField(); - - /** CPacketCloseWindow */ + FastTypeBuilder.create() + .setInsideClass(CPacketVehicleMove.class) + .setName("yaw") + .autoAssign() + .asField(); + + /** + * CPacketCloseWindow + */ FastField CPacketCloseWindow_windowId = - FastTypeBuilder.create() - .setInsideClass(CPacketCloseWindow.class) - .setName("windowId") - .autoAssign() - .asField(); - - /** CPacketEntityAction */ + FastTypeBuilder.create() + .setInsideClass(CPacketCloseWindow.class) + .setName("windowId") + .autoAssign() + .asField(); + + /** + * CPacketEntityAction + */ FastField CPacketEntityAction_entityID = - FastTypeBuilder.create() - .setInsideClass(CPacketEntityAction.class) - .setName("entityID") - .autoAssign() - .asField(); - - /** SPacketPlayerPosLook */ + FastTypeBuilder.create() + .setInsideClass(CPacketEntityAction.class) + .setName("entityID") + .autoAssign() + .asField(); + + /** + * SPacketPlayerPosLook + */ FastField SPacketPlayer_pitch = - FastTypeBuilder.create() - .setInsideClass(SPacketPlayerPosLook.class) - .setName("pitch") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(SPacketPlayerPosLook.class) + .setName("pitch") + .autoAssign() + .asField(); + FastField SPacketPlayer_yaw = - FastTypeBuilder.create() - .setInsideClass(SPacketPlayerPosLook.class) - .setName("yaw") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(SPacketPlayerPosLook.class) + .setName("yaw") + .autoAssign() + .asField(); + FastField SPacketPlayer_x = - FastTypeBuilder.create() - .setInsideClass(SPacketPlayerPosLook.class) - .setName("x") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(SPacketPlayerPosLook.class) + .setName("x") + .autoAssign() + .asField(); + FastField SPacketPlayer_y = - FastTypeBuilder.create() - .setInsideClass(SPacketPlayerPosLook.class) - .setName("y") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(SPacketPlayerPosLook.class) + .setName("y") + .autoAssign() + .asField(); + FastField SPacketPlayer_z = - FastTypeBuilder.create() - .setInsideClass(SPacketPlayerPosLook.class) - .setName("z") - .autoAssign() - .asField(); - - /** Entity */ + FastTypeBuilder.create() + .setInsideClass(SPacketPlayerPosLook.class) + .setName("z") + .autoAssign() + .asField(); + + /** + * Entity + */ FastField Entity_dataManager = - FastTypeBuilder.create() - .setInsideClass(Entity.class) - .setName("dataManager") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(Entity.class) + .setName("dataManager") + .autoAssign() + .asField(); + FastField Entity_inPortal = - FastTypeBuilder.create() - .setInsideClass(Entity.class) - .setName("inPortal") - .autoAssign() - .asField(); - - /** EntityPigZombie */ + FastTypeBuilder.create() + .setInsideClass(Entity.class) + .setName("inPortal") + .autoAssign() + .asField(); + + /** + * EntityPigZombie + */ FastField EntityPigZombie_angerLevel = - FastTypeBuilder.create() - .setInsideClass(EntityPigZombie.class) - .setName("angerLevel") - .autoAssign() - .asField(); - - /** EntityPlayer */ + FastTypeBuilder.create() + .setInsideClass(EntityPigZombie.class) + .setName("angerLevel") + .autoAssign() + .asField(); + + /** + * EntityPlayer + */ FastField EntityPlayer_sleeping = - FastTypeBuilder.create() - .setInsideClass(EntityPlayer.class) - .setName("sleeping") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(EntityPlayer.class) + .setName("sleeping") + .autoAssign() + .asField(); + FastField EntityPlayer_sleepTimer = - FastTypeBuilder.create() - .setInsideClass(EntityPlayer.class) - .setName("sleepTimer") - .autoAssign() - .asField(); - - /** EntityPlayerSP */ + FastTypeBuilder.create() + .setInsideClass(EntityPlayer.class) + .setName("sleepTimer") + .autoAssign() + .asField(); + + /** + * EntityPlayerSP + */ FastField EntityPlayerSP_horseJumpPower = - FastTypeBuilder.create() - .setInsideClass(EntityPlayerSP.class) - .setName("horseJumpPower") - .autoAssign() - .asField(); - - /** GuiConnecting */ + FastTypeBuilder.create() + .setInsideClass(EntityPlayerSP.class) + .setName("horseJumpPower") + .autoAssign() + .asField(); + + /** + * GuiConnecting + */ FastField GuiConnecting_networkManager = - FastTypeBuilder.create() - .setInsideClass(GuiConnecting.class) - .setName("networkManager") - .autoAssign() - .asField(); - - /** GuiDisconnected */ + FastTypeBuilder.create() + .setInsideClass(GuiConnecting.class) + .setName("networkManager") + .autoAssign() + .asField(); + + /** + * GuiDisconnected + */ FastField GuiDisconnected_parentScreen = - FastTypeBuilder.create() - .setInsideClass(GuiDisconnected.class) - .setName("parentScreen") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(GuiDisconnected.class) + .setName("parentScreen") + .autoAssign() + .asField(); + FastField GuiDisconnected_message = - FastTypeBuilder.create() - .setInsideClass(GuiDisconnected.class) - .setName("message") - .autoAssign() - .asField(); + FastTypeBuilder.create() + .setInsideClass(GuiDisconnected.class) + .setName("message") + .autoAssign() + .asField(); FastField GuiDisconnected_reason = - FastTypeBuilder.create() - .setInsideClass(GuiDisconnected.class) - .setName("reason") - .autoAssign() - .asField(); - - /** Minecraft */ + FastTypeBuilder.create() + .setInsideClass(GuiDisconnected.class) + .setName("reason") + .autoAssign() + .asField(); + + /** + * Minecraft + */ FastField Minecraft_leftClickCounter = - FastTypeBuilder.create() - .setInsideClass(Minecraft.class) - .setName("leftClickCounter") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(Minecraft.class) + .setName("leftClickCounter") + .autoAssign() + .asField(); + FastField Minecraft_rightClickDelayTimer = - FastTypeBuilder.create() - .setInsideClass(Minecraft.class) - .setName("rightClickDelayTimer") - .autoAssign() - .asField(); + FastTypeBuilder.create() + .setInsideClass(Minecraft.class) + .setName("rightClickDelayTimer") + .autoAssign() + .asField(); FastField Minecraft_timer = - FastTypeBuilder.create() - .setInsideClass(Minecraft.class) - .setName("timer") - .autoAssign() - .asField(); - - /** PlayerControllerMP */ + FastTypeBuilder.create() + .setInsideClass(Minecraft.class) + .setName("timer") + .autoAssign() + .asField(); + + /** + * PlayerControllerMP + */ FastField PlayerControllerMP_blockHitDelay = - FastTypeBuilder.create() - .setInsideClass(PlayerControllerMP.class) - .setName("blockHitDelay") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(PlayerControllerMP.class) + .setName("blockHitDelay") + .autoAssign() + .asField(); + FastField PlayerControllerMP_curBlockDamageMP = - FastTypeBuilder.create() - .setInsideClass(PlayerControllerMP.class) - .setName("curBlockDamageMP") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(PlayerControllerMP.class) + .setName("curBlockDamageMP") + .autoAssign() + .asField(); + FastField PlayerControllerMP_currentPlayerItem = - FastTypeBuilder.create() - .setInsideClass(PlayerControllerMP.class) - .setName("currentPlayerItem") - .autoAssign() - .asField(); - - /** SPacketEntityVelocity */ + FastTypeBuilder.create() + .setInsideClass(PlayerControllerMP.class) + .setName("currentPlayerItem") + .autoAssign() + .asField(); + + /** + * SPacketEntityVelocity + */ FastField SPacketEntityVelocity_motionX = - FastTypeBuilder.create() - .setInsideClass(SPacketEntityVelocity.class) - .setName("motionX") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(SPacketEntityVelocity.class) + .setName("motionX") + .autoAssign() + .asField(); + FastField SPacketEntityVelocity_motionY = - FastTypeBuilder.create() - .setInsideClass(SPacketEntityVelocity.class) - .setName("motionY") - .autoAssign() - .asField(); + FastTypeBuilder.create() + .setInsideClass(SPacketEntityVelocity.class) + .setName("motionY") + .autoAssign() + .asField(); FastField SPacketEntityVelocity_motionZ = - FastTypeBuilder.create() - .setInsideClass(SPacketEntityVelocity.class) - .setName("motionZ") - .autoAssign() - .asField(); - - /** SPacketExplosion */ + FastTypeBuilder.create() + .setInsideClass(SPacketEntityVelocity.class) + .setName("motionZ") + .autoAssign() + .asField(); + + /** + * SPacketExplosion + */ FastField SPacketExplosion_motionX = - FastTypeBuilder.create() - .setInsideClass(SPacketExplosion.class) - .setName("motionX") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(SPacketExplosion.class) + .setName("motionX") + .autoAssign() + .asField(); + FastField SPacketExplosion_motionY = - FastTypeBuilder.create() - .setInsideClass(SPacketExplosion.class) - .setName("motionY") - .autoAssign() - .asField(); + FastTypeBuilder.create() + .setInsideClass(SPacketExplosion.class) + .setName("motionY") + .autoAssign() + .asField(); FastField SPacketExplosion_motionZ = - FastTypeBuilder.create() - .setInsideClass(SPacketExplosion.class) - .setName("motionZ") - .autoAssign() - .asField(); - - /** BufferBuilder */ + FastTypeBuilder.create() + .setInsideClass(SPacketExplosion.class) + .setName("motionZ") + .autoAssign() + .asField(); + + /** + * BufferBuilder + */ FastField BufferBuilder_isDrawing = - FastTypeBuilder.create() - .setInsideClass(BufferBuilder.class) - .setName("isDrawing") - .autoAssign() - .asField(); - - /** Session */ + FastTypeBuilder.create() + .setInsideClass(BufferBuilder.class) + .setName("isDrawing") + .autoAssign() + .asField(); + + /** + * Session + */ FastField Session_username = - FastTypeBuilder.create() - .setInsideClass(Session.class) - .setName("username") - .autoAssign() - .asField(); - - /** TextureManager */ + FastTypeBuilder.create() + .setInsideClass(Session.class) + .setName("username") + .autoAssign() + .asField(); + + /** + * TextureManager + */ FastField> TextureManager_mapTextureObjects = - FastTypeBuilder.create() - .setInsideClass(TextureManager.class) - .setName("mapTextureObjects") - .autoAssign() - .asField(); - - /** EntityRenderer */ + FastTypeBuilder.create() + .setInsideClass(TextureManager.class) + .setName("mapTextureObjects") + .autoAssign() + .asField(); + + /** + * EntityRenderer + */ FastField EntityRenderer_itemActivationItem = - FastTypeBuilder.create() - .setInsideClass(EntityRenderer.class) - .setName("itemActivationItem") - .autoAssign() - .asField(); - - /** AbstractHorse */ + FastTypeBuilder.create() + .setInsideClass(EntityRenderer.class) + .setName("itemActivationItem") + .autoAssign() + .asField(); + + /** + * AbstractHorse + */ FastField AbstractHorse_JUMP_STRENGTH = - FastTypeBuilder.create() - .setInsideClass(AbstractHorse.class) - .setName("JUMP_STRENGTH") - .autoAssign() - .asField(); - /** SharedMonsterAttributes */ + FastTypeBuilder.create() + .setInsideClass(AbstractHorse.class) + .setName("JUMP_STRENGTH") + .autoAssign() + .asField(); + /** + * SharedMonsterAttributes + */ FastField SharedMonsterAttributes_MOVEMENT_SPEED = - FastTypeBuilder.create() - .setInsideClass(SharedMonsterAttributes.class) - .setName("MOVEMENT_SPEED") - .autoAssign() - .asField(); - /** GuiEditSign */ + FastTypeBuilder.create() + .setInsideClass(SharedMonsterAttributes.class) + .setName("MOVEMENT_SPEED") + .autoAssign() + .asField(); + /** + * GuiEditSign + */ FastField GuiEditSign_tileSign = - FastTypeBuilder.create() - .setInsideClass(GuiEditSign.class) - .setName("tileSign") - .autoAssign() - .asField(); - /** NBTTagCompound */ + FastTypeBuilder.create() + .setInsideClass(GuiEditSign.class) + .setName("tileSign") + .autoAssign() + .asField(); + /** + * NBTTagCompound + */ FastField> NBTTag_tagMap = - FastTypeBuilder.create() - .setInsideClass(NBTTagCompound.class) - .setName("tagMap") - .autoAssign() - .asField(); - /** Timer */ + FastTypeBuilder.create() + .setInsideClass(NBTTagCompound.class) + .setName("tagMap") + .autoAssign() + .asField(); + /** + * Timer + */ FastField Timer_tickLength = - FastTypeBuilder.create() - .setInsideClass(Timer.class) - .setName("tickLength") - .autoAssign() - .asField(); - /** KeyBinding */ + FastTypeBuilder.create() + .setInsideClass(Timer.class) + .setName("tickLength") + .autoAssign() + .asField(); + /** + * KeyBinding + */ FastField Binding_pressTime = - FastTypeBuilder.create() - .setInsideClass(KeyBinding.class) - .setName("pressTime") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(KeyBinding.class) + .setName("pressTime") + .autoAssign() + .asField(); + FastField Binding_pressed = - FastTypeBuilder.create() - .setInsideClass(KeyBinding.class) - .setName("pressed") - .autoAssign() - .asField(); - - /** ItemSword */ + FastTypeBuilder.create() + .setInsideClass(KeyBinding.class) + .setName("pressed") + .autoAssign() + .asField(); + + /** + * ItemSword + */ FastField ItemSword_attackDamage = - FastTypeBuilder.create() - .setInsideClass(ItemSword.class) - .setName("attackDamage") - .autoAssign() - .asField(); - - /** ItemTool */ + FastTypeBuilder.create() + .setInsideClass(ItemSword.class) + .setName("attackDamage") + .autoAssign() + .asField(); + + /** + * ItemTool + */ FastField ItemTool_damageVsEntity = - FastTypeBuilder.create() - .setInsideClass(ItemTool.class) - .setName("damageVsEntity") - .autoAssign() - .asField(); - + FastTypeBuilder.create() + .setInsideClass(ItemTool.class) + .setName("damageVsEntity") + .autoAssign() + .asField(); + FastField ItemTool_attackSpeed = - FastTypeBuilder.create() - .setInsideClass(ItemTool.class) - .setName("attackSpeed") - .autoAssign() - .asField(); - - /** ItemFood */ + FastTypeBuilder.create() + .setInsideClass(ItemTool.class) + .setName("attackSpeed") + .autoAssign() + .asField(); + + /** + * ItemFood + */ FastField ItemFood_potionId = - FastTypeBuilder.create() - .setInsideClass(ItemFood.class) - .setName("potionId") - .autoAssign() - .asField(); - - /** Chunk */ + FastTypeBuilder.create() + .setInsideClass(ItemFood.class) + .setName("potionId") + .autoAssign() + .asField(); + + /** + * Chunk + */ FastField Chunk_storageArrays = - FastTypeBuilder.create() - .setInsideClass(Chunk.class) - .setName("storageArrays") - .autoAssign() - .asField(); + FastTypeBuilder.create() + .setInsideClass(Chunk.class) + .setName("storageArrays") + .autoAssign() + .asField(); } - + // **************************************** // METHODS // **************************************** - + interface Methods { - /** Block */ + + /** + * Block + */ FastMethod Block_onBlockActivated = - FastTypeBuilder.create() - .setInsideClass(Block.class) - .setName("onBlockActivated") - .setParameters( - World.class, - BlockPos.class, - IBlockState.class, - EntityPlayer.class, - EnumHand.class, - EnumFacing.class, - float.class, - float.class, - float.class) - .setReturnType(boolean.class) - .autoAssign() - .asMethod(); - - /** Entity */ + FastTypeBuilder.create() + .setInsideClass(Block.class) + .setName("onBlockActivated") + .setParameters( + World.class, + BlockPos.class, + IBlockState.class, + EntityPlayer.class, + EnumHand.class, + EnumFacing.class, + float.class, + float.class, + float.class) + .setReturnType(boolean.class) + .autoAssign() + .asMethod(); + + /** + * Entity + */ FastMethod Entity_getFlag = - FastTypeBuilder.create() - .setInsideClass(Entity.class) - .setName("getFlag") - .setParameters(int.class) - .setReturnType(boolean.class) - .autoAssign() - .asMethod(); - + FastTypeBuilder.create() + .setInsideClass(Entity.class) + .setName("getFlag") + .setParameters(int.class) + .setReturnType(boolean.class) + .autoAssign() + .asMethod(); + FastMethod Entity_setFlag = - FastTypeBuilder.create() - .setInsideClass(Entity.class) - .setName("setFlag") - .setParameters(int.class, boolean.class) - .setReturnType(void.class) - .autoAssign() - .asMethod(); - - /** EntityLivingBase */ + FastTypeBuilder.create() + .setInsideClass(Entity.class) + .setName("setFlag") + .setParameters(int.class, boolean.class) + .setReturnType(void.class) + .autoAssign() + .asMethod(); + + /** + * EntityLivingBase + */ FastMethod EntityLivingBase_resetPotionEffectMetadata = - FastTypeBuilder.create() - .setInsideClass(EntityLivingBase.class) - .setName("resetPotionEffectMetadata") - .setParameters() - .setReturnType(void.class) - .autoAssign() - .asMethod(); - - /** Minecraft */ + FastTypeBuilder.create() + .setInsideClass(EntityLivingBase.class) + .setName("resetPotionEffectMetadata") + .setParameters() + .setReturnType(void.class) + .autoAssign() + .asMethod(); + + /** + * Minecraft + */ FastMethod Minecraft_clickMouse = - FastTypeBuilder.create() - .setInsideClass(Minecraft.class) - .setName("clickMouse") - .setParameters() - .setReturnType(void.class) - .autoAssign() - .asMethod(); - + FastTypeBuilder.create() + .setInsideClass(Minecraft.class) + .setName("clickMouse") + .setParameters() + .setReturnType(void.class) + .autoAssign() + .asMethod(); + FastMethod Minecraft_rightClickMouse = - FastTypeBuilder.create() - .setInsideClass(Minecraft.class) - .setName("rightClickMouse") - .setParameters() - .setReturnType(void.class) - .autoAssign() - .asMethod(); - - /** KeyBinding */ + FastTypeBuilder.create() + .setInsideClass(Minecraft.class) + .setName("rightClickMouse") + .setParameters() + .setReturnType(void.class) + .autoAssign() + .asMethod(); + + /** + * KeyBinding + */ FastMethod KeyBinding_unPress = - FastTypeBuilder.create() - .setInsideClass(KeyBinding.class) - .setName("unpressKey") - .setParameters() - .setReturnType(void.class) - .autoAssign() - .asMethod(); - - /** IChunkLoader */ + FastTypeBuilder.create() + .setInsideClass(KeyBinding.class) + .setName("unpressKey") + .setParameters() + .setReturnType(void.class) + .autoAssign() + .asMethod(); + + /** + * IChunkLoader + */ FastMethod AnvilChunkLoader_writeChunkToNBT = - FastTypeBuilder.create() - .setInsideClass(AnvilChunkLoader.class) - .setName("writeChunkToNBT") - .setParameters(Chunk.class, World.class, NBTTagCompound.class) - .setReturnType(void.class) - .autoAssign() - .asMethod(); + FastTypeBuilder.create() + .setInsideClass(AnvilChunkLoader.class) + .setName("writeChunkToNBT") + .setParameters(Chunk.class, World.class, NBTTagCompound.class) + .setReturnType(void.class) + .autoAssign() + .asMethod(); } } diff --git a/src/main/java/com/matt/forgehax/asm/reflection/FastReflectionForge.java b/src/main/java/com/matt/forgehax/asm/reflection/FastReflectionForge.java index e4bae06a4..eaecaf483 100644 --- a/src/main/java/com/matt/forgehax/asm/reflection/FastReflectionForge.java +++ b/src/main/java/com/matt/forgehax/asm/reflection/FastReflectionForge.java @@ -9,37 +9,42 @@ /** * Created on 5/27/2017 by fr1kin * - *

Minecraft classes and other classes need to be separated so that if the non-minecraft class is + *

Minecraft classes and other classes need to be separated so that if the non-minecraft class + * is * required before minecraft classes are loaded, they are not accidentally loaded too early */ public interface FastReflectionForge { + interface Fields { - /** FMLDeobfuscatingRemapper */ + + /** + * FMLDeobfuscatingRemapper + */ FastField> FMLDeobfuscatingRemapper_classNameBiMap = - FastTypeBuilder.create() - .setInsideClass(FMLDeobfuscatingRemapper.class) - .setName("classNameBiMap") - .asField(); - + FastTypeBuilder.create() + .setInsideClass(FMLDeobfuscatingRemapper.class) + .setName("classNameBiMap") + .asField(); + FastField>> FMLDeobfuscatingRemapper_rawFieldMaps = - FastTypeBuilder.create() - .setInsideClass(FMLDeobfuscatingRemapper.class) - .setName("rawFieldMaps") - .asField(); + FastTypeBuilder.create() + .setInsideClass(FMLDeobfuscatingRemapper.class) + .setName("rawFieldMaps") + .asField(); FastField>> FMLDeobfuscatingRemapper_rawMethodMaps = - FastTypeBuilder.create() - .setInsideClass(FMLDeobfuscatingRemapper.class) - .setName("rawMethodMaps") - .asField(); + FastTypeBuilder.create() + .setInsideClass(FMLDeobfuscatingRemapper.class) + .setName("rawMethodMaps") + .asField(); FastField>> FMLDeobfuscatingRemapper_fieldNameMaps = - FastTypeBuilder.create() - .setInsideClass(FMLDeobfuscatingRemapper.class) - .setName("fieldNameMaps") - .asField(); + FastTypeBuilder.create() + .setInsideClass(FMLDeobfuscatingRemapper.class) + .setName("fieldNameMaps") + .asField(); FastField>> FMLDeobfuscatingRemapper_methodNameMaps = - FastTypeBuilder.create() - .setInsideClass(FMLDeobfuscatingRemapper.class) - .setName("methodNameMaps") - .asField(); + FastTypeBuilder.create() + .setInsideClass(FMLDeobfuscatingRemapper.class) + .setName("methodNameMaps") + .asField(); } } diff --git a/src/main/java/com/matt/forgehax/asm/reflection/FastReflectionSpecial.java b/src/main/java/com/matt/forgehax/asm/reflection/FastReflectionSpecial.java index 723d08f87..b37dd098a 100644 --- a/src/main/java/com/matt/forgehax/asm/reflection/FastReflectionSpecial.java +++ b/src/main/java/com/matt/forgehax/asm/reflection/FastReflectionSpecial.java @@ -5,15 +5,25 @@ import java.util.Map; import org.lwjgl.input.Keyboard; -/** Created on 5/8/2017 by fr1kin */ +/** + * Created on 5/8/2017 by fr1kin + */ public interface FastReflectionSpecial { - interface Classes {} - - interface Methods {} + + interface Classes { + + } + + interface Methods { + + } interface Fields { - /** LJGLW Keyboard */ + + /** + * LJGLW Keyboard + */ FastField> Keyboard_keyMap = - FastTypeBuilder.create().setInsideClass(Keyboard.class).setName("keyMap").asField(); + FastTypeBuilder.create().setInsideClass(Keyboard.class).setName("keyMap").asField(); } } diff --git a/src/main/java/com/matt/forgehax/asm/test/TestCode.java b/src/main/java/com/matt/forgehax/asm/test/TestCode.java deleted file mode 100644 index 90a7bf873..000000000 --- a/src/main/java/com/matt/forgehax/asm/test/TestCode.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.matt.forgehax.asm.test; - -import com.google.common.collect.Lists; -import java.util.List; - -/** Created on 9/4/2016 by fr1kin */ -public class TestCode { - private static boolean isNoSlowOn = false; - private static int empty = 0; - - private boolean movementInput = false; - private boolean onGround = false; - - private double stepHeight = 0; - - public boolean isSneaking() { - return true; - } - - public boolean isHandActive() { - return true; - } - - public boolean isRiding() { - return true; - } - - public void moveEntity(Float a1, Float a2, Float a3, Object o) { - boolean flag; - if (flag = !isSneaking()) { - double local1, l2, l3, l4; - isHandActive(); - for (int i = 0; i < 4; i++) ; - local1 = 12310; - l2 = 457; - l3 = 6435; - l4 = 1243; - } - if (flag) { - isRiding(); - } - - List list = Lists.newArrayList(); - return; - } -} diff --git a/src/main/java/com/matt/forgehax/asm/utils/ASMHelper.java b/src/main/java/com/matt/forgehax/asm/utils/ASMHelper.java index 49e309900..0035bb352 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/ASMHelper.java +++ b/src/main/java/com/matt/forgehax/asm/utils/ASMHelper.java @@ -1,6 +1,8 @@ package com.matt.forgehax.asm.utils; -import static org.objectweb.asm.Opcodes.*; +import static org.objectweb.asm.Opcodes.DUP; +import static org.objectweb.asm.Opcodes.INVOKESPECIAL; +import static org.objectweb.asm.Opcodes.NEW; import com.matt.forgehax.asm.utils.asmtype.ASMField; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; @@ -13,37 +15,48 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nullable; -import org.objectweb.asm.tree.*; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.LabelNode; +import org.objectweb.asm.tree.LocalVariableNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.TypeInsnNode; public class ASMHelper { - + /** * Finds a pattern of opcodes and returns the first node of the matched pattern if found * * @param start starting node * @param pattern integer array of opcodes * @param mask same length as the pattern. 'x' indicates the node will be checked, '?' indicates - * the node will be skipped over (has a bad opcode) + * the node will be skipped over (has a bad opcode) * @return top node of matching pattern or null if nothing is found */ public static AbstractInsnNode findPattern(AbstractInsnNode start, int[] pattern, char[] mask) { - if (pattern.length != mask.length) + if (pattern.length != mask.length) { throw new IllegalArgumentException("Mask must be same length as pattern"); + } return findPattern( - start, - pattern.length, - (node) -> true, - (found, next) -> mask[found] != 'x' || next.getOpcode() == pattern[found], - (first, last) -> first); + start, + pattern.length, + (node) -> true, + (found, next) -> mask[found] != 'x' || next.getOpcode() == pattern[found], + (first, last) -> first); } - + public static T findPattern( - final AbstractInsnNode start, - final int patternSize, - Predicate - isValidNode, // if this returns false then dont invoke the predicate and dont update found - BiPredicate nodePredicate, - BiFunction outputFunction) { + final AbstractInsnNode start, + final int patternSize, + Predicate + isValidNode, // if this returns false then dont invoke the predicate and dont update found + BiPredicate nodePredicate, + BiFunction outputFunction) { if (start != null) { int found = 0; AbstractInsnNode next = start; @@ -65,7 +78,7 @@ public static T findPattern( // Reset the number of insns matched found = 0; } - + // Check if found entire pattern if (found >= patternSize) { final AbstractInsnNode end = next; @@ -81,34 +94,38 @@ public static T findPattern( // failed to find pattern return null; } - + public static AbstractInsnNode findPattern(AbstractInsnNode start, int[] pattern, String mask) { return findPattern(start, pattern, mask.toCharArray()); } - + public static AbstractInsnNode findPattern(AbstractInsnNode start, int... opcodes) { StringBuilder mask = new StringBuilder(); - for (int op : opcodes) mask.append(op == MagicOpcodes.NONE ? '?' : 'x'); + for (int op : opcodes) { + mask.append(op == MagicOpcodes.NONE ? '?' : 'x'); + } return findPattern(start, opcodes, mask.toString()); } - + public static AbstractInsnNode findPattern(InsnList instructions, int... opcodes) { return findPattern(instructions.getFirst(), opcodes); } - + public static AbstractInsnNode findPattern(MethodNode node, int... opcodes) { return findPattern(node.instructions, opcodes); } - + @Nullable public static AbstractInsnNode forward(AbstractInsnNode start, int n) { AbstractInsnNode node = start; for (int i = 0; - i < Math.abs(n) && node != null; - ++i, node = n > 0 ? node.getNext() : node.getPrevious()) ; + i < Math.abs(n) && node != null; + ++i, node = n > 0 ? node.getNext() : node.getPrevious()) { + ; + } return node; } - + public static String getClassData(ClassNode node) { StringBuilder builder = new StringBuilder("METHODS:\n"); for (MethodNode method : node.methods) { @@ -127,77 +144,84 @@ public static String getClassData(ClassNode node) { } return builder.toString(); } - + public static MethodInsnNode call(int opcode, boolean isInterface, ASMMethod method) { Objects.requireNonNull(method.getParentClass(), "Method requires assigned parent class"); return new MethodInsnNode( - opcode, - method.getParentClass().getRuntimeInternalName(), - method.getRuntimeName(), - method.getRuntimeDescriptor(), - false); + opcode, + method.getParentClass().getRuntimeInternalName(), + method.getRuntimeName(), + method.getRuntimeDescriptor(), + false); } - + public static MethodInsnNode call(int opcode, ASMMethod method) { return call(opcode, false, method); } - + public static FieldInsnNode call(int opcode, ASMField field) { Objects.requireNonNull(field.getParentClass(), "Field requires assigned parent class"); return new FieldInsnNode( - opcode, - field.getParentClass().getRuntimeInternalName(), - field.getRuntimeName(), - field.getRuntimeDescriptor()); + opcode, + field.getParentClass().getRuntimeInternalName(), + field.getRuntimeName(), + field.getRuntimeDescriptor()); } - + // scope is from first label to last label public static int addNewLocalVariable(MethodNode method, String name, String desc) { AsmPattern labelPattern = new AsmPattern.Builder(0).label().build(); - + final LabelNode start = labelPattern.test(method).getFirst(); - + // TODO: implement backwards pattern matching so this can be refactored AbstractInsnNode iter = method.instructions.getFirst(); LabelNode end = null; do { - if (iter instanceof LabelNode) end = (LabelNode) iter; + if (iter instanceof LabelNode) { + end = (LabelNode) iter; + } iter = iter.getNext(); } while (iter != null); - if (end == null) throw new IllegalArgumentException("Failed to find LabelNode"); - + if (end == null) { + throw new IllegalArgumentException("Failed to find LabelNode"); + } + return addNewLocalVariable(method, name, desc, start, end); } - + public static int addNewLocalVariable( - MethodNode method, String name, String desc, LabelNode start, LabelNode end) { + MethodNode method, String name, String desc, LabelNode start, LabelNode end) { Optional lastVar = - method.localVariables.stream().max(Comparator.comparingInt(var -> var.index)); + method.localVariables.stream().max(Comparator.comparingInt(var -> var.index)); final int newIndex = - lastVar.map(var -> var.desc.matches("[JD]") ? var.index + 2 : var.index + 1).orElse(0); - + lastVar.map(var -> var.desc.matches("[JD]") ? var.index + 2 : var.index + 1).orElse(0); + LocalVariableNode variable = new LocalVariableNode(name, desc, null, start, end, newIndex); method.localVariables.add(variable); - + return newIndex; } - + // args should be type descriptors public static InsnList newInstance(String name, String[] argTypes, @Nullable InsnList args) { final String desc = Stream.of(argTypes).collect(Collectors.joining("", "(", ")V")); return newInstance(name, desc, args); } - + public static InsnList newInstance(String name, String desc, @Nullable InsnList args) { InsnList list = new InsnList(); list.add(new TypeInsnNode(NEW, name)); list.add(new InsnNode(DUP)); - if (args != null) list.add(args); + if (args != null) { + list.add(args); + } list.add(new MethodInsnNode(INVOKESPECIAL, name, "", desc, false)); return list; } - + public interface MagicOpcodes { + int NONE = -666; } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/ASMStackLogger.java b/src/main/java/com/matt/forgehax/asm/utils/ASMStackLogger.java index 212beaea5..8ebbfb0c3 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/ASMStackLogger.java +++ b/src/main/java/com/matt/forgehax/asm/utils/ASMStackLogger.java @@ -4,8 +4,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** Created on 5/4/2017 by fr1kin */ +/** + * Created on 5/4/2017 by fr1kin + */ public class ASMStackLogger { + private static final Logger STACK_LOGGER = LogManager.getLogger("ForgeHaxAsmStackTrace"); public static void printStackTrace(Throwable e) { diff --git a/src/main/java/com/matt/forgehax/asm/utils/AsmPattern.java b/src/main/java/com/matt/forgehax/asm/utils/AsmPattern.java index b6f86c686..bb15331c7 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/AsmPattern.java +++ b/src/main/java/com/matt/forgehax/asm/utils/AsmPattern.java @@ -12,87 +12,88 @@ import org.objectweb.asm.tree.MethodNode; public class AsmPattern { - + public static final int IGNORE_FRAMES = 1 << 0; public static final int IGNORE_LABELS = 1 << 1; public static final int IGNORE_LINENUMBERS = 1 << 2; public static final int CODE_ONLY = IGNORE_FRAMES | IGNORE_LABELS | IGNORE_LINENUMBERS; - + private final int flags; private final ImmutableList> insnPredicates; - + private AsmPattern(List> predicates, int flags) { this.insnPredicates = ImmutableList.copyOf(predicates); this.flags = flags; } - + public InsnPattern test(MethodNode main) { return test(main.instructions.getFirst()); } - + public InsnPattern test(AbstractInsnNode start) { return ASMHelper.findPattern( - start, - insnPredicates.size(), - // isValidNode - (node) -> - !testFlag(node, FrameNode.class, IGNORE_FRAMES) - && !testFlag(node, LabelNode.class, IGNORE_LABELS) - && !testFlag(node, LineNumberNode.class, IGNORE_LINENUMBERS), - // nodePredicate - (found, node) -> insnPredicates.get(found).test(node), - InsnPattern::new); + start, + insnPredicates.size(), + // isValidNode + (node) -> + !testFlag(node, FrameNode.class, IGNORE_FRAMES) + && !testFlag(node, LabelNode.class, IGNORE_LABELS) + && !testFlag(node, LineNumberNode.class, IGNORE_LINENUMBERS), + // nodePredicate + (found, node) -> insnPredicates.get(found).test(node), + InsnPattern::new); } - + // returns true if the node is an instance of the given type and the given flag is present private boolean testFlag( - AbstractInsnNode node, Class type, int flag) { + AbstractInsnNode node, Class type, int flag) { return type.isInstance(node) && (this.flags & flag) != 0; } - + public static class Builder { - + private final int flags; private final List> predicates = new ArrayList<>(); - + public Builder(final int flags) { this.flags = flags; } - + public Builder opcode(int opcode) { return add(insn -> insn.getOpcode() == opcode); } - + public Builder opcodes(int... opcodes) { for (int o : opcodes) { opcode(o); } return this; } - + public Builder invoke() { return add(insn -> insn instanceof MethodInsnNode); } - + public Builder any() { return add(insn -> true); } - + public Builder label() { - if ((flags & IGNORE_LABELS) != 0) + if ((flags & IGNORE_LABELS) != 0) { throw new IllegalStateException("Attempting to find a label with flag IGNORE_LABELS"); + } return add(insn -> insn instanceof LabelNode); } - + public Builder custom(Predicate predicate) { return add(predicate); } - + private Builder add(Predicate predicate) { predicates.add((Predicate) predicate); return this; } - + public AsmPattern build() { return new AsmPattern(predicates, flags); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/InsnPattern.java b/src/main/java/com/matt/forgehax/asm/utils/InsnPattern.java index f52b370fa..3f484c5d7 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/InsnPattern.java +++ b/src/main/java/com/matt/forgehax/asm/utils/InsnPattern.java @@ -4,25 +4,25 @@ import org.objectweb.asm.tree.AbstractInsnNode; public class InsnPattern { - + private final AbstractInsnNode first; private final AbstractInsnNode last; - + public InsnPattern(AbstractInsnNode first, AbstractInsnNode last) { Objects.requireNonNull(first); Objects.requireNonNull(last); this.first = first; this.last = last; } - + public T getFirst() { return (T) this.first; } - + public T getLast() { return (T) this.last; } - + public T getIndex(final int index) { AbstractInsnNode node = this.first; for (int i = 0; i < index; i++) { diff --git a/src/main/java/com/matt/forgehax/asm/utils/MultiBoolean.java b/src/main/java/com/matt/forgehax/asm/utils/MultiBoolean.java index 3e558ef8d..82a605737 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/MultiBoolean.java +++ b/src/main/java/com/matt/forgehax/asm/utils/MultiBoolean.java @@ -3,9 +3,14 @@ import com.google.common.collect.Sets; import java.util.Set; -/** Created on 5/12/2017 by fr1kin */ +/** + * Created on 5/12/2017 by fr1kin + */ public class MultiBoolean { - /** A list of unique string ids so that one mod cannot increment the level more than once. */ + + /** + * A list of unique string ids so that one mod cannot increment the level more than once. + */ private final Set ids = Sets.newCopyOnWriteArraySet(); private int level = 0; diff --git a/src/main/java/com/matt/forgehax/asm/utils/ReflectionHelper.java b/src/main/java/com/matt/forgehax/asm/utils/ReflectionHelper.java index 86985adde..6b915a528 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/ReflectionHelper.java +++ b/src/main/java/com/matt/forgehax/asm/utils/ReflectionHelper.java @@ -4,90 +4,98 @@ import com.matt.forgehax.asm.utils.environment.State; import com.matt.forgehax.asm.utils.fasttype.FastMethod; import com.matt.forgehax.asm.utils.name.IName; -import java.lang.reflect.*; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; public class ReflectionHelper { + public static void copyOf(F from, T to, boolean ignoreFinal) - throws NoSuchFieldException, IllegalAccessException { + throws NoSuchFieldException, IllegalAccessException { Objects.requireNonNull(from); Objects.requireNonNull(to); - + Class clazz = from.getClass(); - + for (Field field : clazz.getDeclaredFields()) { makePublic(field); - - if (isStatic(field) || (ignoreFinal && isFinal(field))) continue; - else makeMutable(field); - + + if (isStatic(field) || (ignoreFinal && isFinal(field))) { + continue; + } else { + makeMutable(field); + } + field.set(to, field.get(from)); } } - + public static void copyOf(F from, T to) - throws NoSuchFieldException, IllegalAccessException { + throws NoSuchFieldException, IllegalAccessException { copyOf(from, to, false); } - + public static boolean isStatic(Member instance) { return (instance.getModifiers() & Modifier.STATIC) != 0; } - + public static boolean isFinal(Member instance) { return (instance.getModifiers() & Modifier.FINAL) != 0; } - + public static void makeAccessible(AccessibleObject instance, boolean accessible) { Objects.requireNonNull(instance); instance.setAccessible(accessible); } - + public static void makePublic(AccessibleObject instance) { makeAccessible(instance, true); } - + public static void makePrivate(AccessibleObject instance) { makeAccessible(instance, false); } - + public static void makeMutable(Member instance) - throws NoSuchFieldException, IllegalAccessException { + throws NoSuchFieldException, IllegalAccessException { Objects.requireNonNull(instance); Field modifiers = Field.class.getDeclaredField("modifiers"); makePublic(modifiers); modifiers.setInt(instance, instance.getModifiers() & ~Modifier.FINAL); } - + public static void makeImmutable(Member instance) - throws NoSuchFieldException, IllegalAccessException { + throws NoSuchFieldException, IllegalAccessException { Objects.requireNonNull(instance); Field modifiers = Field.class.getDeclaredField("modifiers"); makePublic(modifiers); modifiers.setInt(instance, instance.getModifiers() & Modifier.FINAL); } - + public static Class getMethodDeclaringClass(FastMethod method, Object instance) { Objects.requireNonNull(instance); IName names = method.getName(); return Arrays.stream(State.values()) - .sorted(Comparator.comparing(state -> RuntimeState.getState().equals(state))) - .map(names::getByState) - .filter(Objects::nonNull) - .map( - name -> { - try { - return instance.getClass().getDeclaredMethod(name, method.getParameters()); - } catch (NoSuchMethodException e) { - return null; - } - }) - .filter(Objects::nonNull) - .peek(ReflectionHelper::makePublic) - .findAny() - .map(Method::getDeclaringClass) - .orElse(null); + .sorted(Comparator.comparing(state -> RuntimeState.getState().equals(state))) + .map(names::getByState) + .filter(Objects::nonNull) + .map( + name -> { + try { + return instance.getClass().getDeclaredMethod(name, method.getParameters()); + } catch (NoSuchMethodException e) { + return null; + } + }) + .filter(Objects::nonNull) + .peek(ReflectionHelper::makePublic) + .findAny() + .map(Method::getDeclaringClass) + .orElse(null); } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMClass.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMClass.java index 2ff23571a..87f91c0b2 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMClass.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMClass.java @@ -11,8 +11,11 @@ import java.util.Objects; import org.objectweb.asm.Type; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public class ASMClass implements IASMType { + private final IName className; public ASMClass(IName className) { @@ -83,7 +86,9 @@ public String toString() { State next = it.next(); Type type = className.getByState(next); if (type != null) { - if (needsSeparator) builder.append(","); + if (needsSeparator) { + builder.append(","); + } builder.append(next.name()); builder.append("="); builder.append(type.getInternalName()); diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMClassChild.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMClassChild.java index 692751111..8856fa8a3 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMClassChild.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMClassChild.java @@ -2,14 +2,17 @@ import javax.annotation.Nullable; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public abstract class ASMClassChild implements IASMType { + private final ASMClass parentClass; - + public ASMClassChild(@Nullable ASMClass parentClass) { this.parentClass = parentClass; } - + /** * The parent class to this child element * diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMField.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMField.java index 44790d3eb..b1336d596 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMField.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMField.java @@ -8,8 +8,11 @@ import javax.annotation.Nullable; import org.objectweb.asm.Type; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public class ASMField extends ASMClassChild { + private final IName fieldName; private final IName type; @@ -38,23 +41,25 @@ public String getDescriptorByState(State state) { @Override public boolean equals(Object obj) { return obj instanceof ASMField - && Objects.equals(getName(), ((ASMField) obj).getName()) - && Objects.equals(getDescriptor(), ((ASMField) obj).getDescriptor()); + && Objects.equals(getName(), ((ASMField) obj).getName()) + && Objects.equals(getDescriptor(), ((ASMField) obj).getDescriptor()); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append( - String.format( - "FIELD[states=%d,maxStates=%d]{", - fieldName.getStateCount(), Math.max(fieldName.getStateCount(), type.getStateCount()))); + String.format( + "FIELD[states=%d,maxStates=%d]{", + fieldName.getStateCount(), Math.max(fieldName.getStateCount(), type.getStateCount()))); Iterator it = Arrays.asList(State.values()).iterator(); boolean needsSeparator = false; while (it.hasNext()) { State next = it.next(); if (fieldName.getByState(next) != null || type.getByState(next) != null) { - if (needsSeparator) builder.append(","); + if (needsSeparator) { + builder.append(","); + } builder.append(next.name()); builder.append("="); builder.append(getNameByState(next)); diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMMethod.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMMethod.java index c595836b3..d9509cc6e 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMMethod.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/ASMMethod.java @@ -9,23 +9,26 @@ import javax.annotation.Nullable; import org.objectweb.asm.Type; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public class ASMMethod extends ASMClassChild { + private final IName methodName; private final IName[] parameters; private final IName returnType; - + public ASMMethod( - @Nullable ASMClass parentClass, - IName methodName, - IName[] parameters, - IName returnType) { + @Nullable ASMClass parentClass, + IName methodName, + IName[] parameters, + IName returnType) { super(parentClass); this.methodName = methodName; this.parameters = Arrays.copyOf(parameters, parameters.length); this.returnType = returnType; } - + /** * The method type, specified by state, containing the method name * @@ -36,13 +39,13 @@ public ASMMethod( public String getNameByState(State state) { return methodName.getByStateSafe(state); } - + @Override public String getDescriptorByState(State state) { return Type.getMethodType(getReturnTypeByState(state), getArgumentTypesByState(state)) - .getDescriptor(); + .getDescriptor(); } - + /** * An array of argument types for the normal method * @@ -51,7 +54,7 @@ public String getDescriptorByState(State state) { public Type[] getArgumentTypes() { return getArgumentTypesByState(State.NORMAL); } - + public Type[] getArgumentTypesByState(State state) { Type[] all = new Type[parameters.length]; for (int i = 0; i < parameters.length; i++) { @@ -59,21 +62,20 @@ public Type[] getArgumentTypesByState(State state) { } return all; } - + /** * Check if the state has a unique signature because a type in the arguments has multiple states - * - * @param state - * @return */ private boolean isArgumentStatePresent(State state) { for (int i = 0; i < parameters.length; i++) { Type arg = parameters[i].getByState(state); - if (arg != null) return true; + if (arg != null) { + return true; + } } return false; } - + /** * An array of argument types for the runtime method * @@ -82,7 +84,7 @@ private boolean isArgumentStatePresent(State state) { public Type[] getRuntimeArgumentTypes() { return getArgumentTypesByState(RuntimeState.getState()); } - + /** * The return type for the normal method * @@ -91,11 +93,11 @@ public Type[] getRuntimeArgumentTypes() { public Type getReturnType() { return returnType.get(); } - + public Type getReturnTypeByState(State state) { return returnType.getByStateSafe(state); } - + /** * The return type for the runtime method * @@ -104,32 +106,36 @@ public Type getReturnTypeByState(State state) { public Type getRuntimeReturnType() { return getReturnTypeByState(RuntimeState.getState()); } - + @Override public boolean equals(Object obj) { return obj instanceof ASMMethod - && Objects.equals(getName(), ((ASMMethod) obj).getName()) - && Objects.equals(getDescriptor(), ((ASMMethod) obj).getDescriptor()); + && Objects.equals(getName(), ((ASMMethod) obj).getName()) + && Objects.equals(getDescriptor(), ((ASMMethod) obj).getDescriptor()); } - + @Override public String toString() { StringBuilder builder = new StringBuilder(); // if any member has another state the entire signature will change for that state // so we must find the maximum number of different states int maxStates = Math.max(methodName.getStateCount(), returnType.getStateCount()); - for (IName nm : parameters) maxStates = Math.max(maxStates, nm.getStateCount()); + for (IName nm : parameters) { + maxStates = Math.max(maxStates, nm.getStateCount()); + } builder.append( - String.format("METHOD[states=%d,maxStates=%d]{", methodName.getStateCount(), maxStates)); + String.format("METHOD[states=%d,maxStates=%d]{", methodName.getStateCount(), maxStates)); Iterator it = Arrays.asList(State.values()).iterator(); boolean needsSeparator = false; while (it.hasNext()) { State next = it.next(); // if any are not null then a unique signature for this state exists if (methodName.getByState(next) != null - || returnType.getByState(next) != null - || isArgumentStatePresent(next)) { - if (needsSeparator) builder.append(","); + || returnType.getByState(next) != null + || isArgumentStatePresent(next)) { + if (needsSeparator) { + builder.append(","); + } builder.append(next.name()); builder.append("="); builder.append(getNameByState(next)); diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/IASMType.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/IASMType.java index ae33d6594..64c215b3e 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/IASMType.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/IASMType.java @@ -3,40 +3,43 @@ import com.matt.forgehax.asm.utils.environment.RuntimeState; import com.matt.forgehax.asm.utils.environment.State; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public interface IASMType { + String getNameByState(State state); - + String getDescriptorByState(State state); - + default String getName() { return getNameByState(State.NORMAL); } - + default String getDescriptor() { return getDescriptorByState(State.NORMAL); } - + default String getSrgName() { return getNameByState(State.SRG); } - + default String getSrgDescriptor() { return getDescriptorByState(State.SRG); } - + default String getObfuscatedName() { return getNameByState(State.OBFUSCATED); } - + default String getObfuscatedDescriptor() { return getDescriptorByState(State.OBFUSCATED); } - + default String getRuntimeName() { return getNameByState(RuntimeState.getState()); } - + default String getRuntimeDescriptor() { return getDescriptorByState(RuntimeState.getState()); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMBuilders.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMBuilders.java index db5933a03..b2f20b8ec 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMBuilders.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMBuilders.java @@ -1,19 +1,22 @@ package com.matt.forgehax.asm.utils.asmtype.builders; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public class ASMBuilders { + public static ASMClassBuilder newClassBuilder() { return new ASMClassBuilder(); } - + public static ASMMethodBuilder newMethodBuilder() { return new ASMMethodBuilder(); } - + public static ASMFieldBuilder newFieldBuilder() { return new ASMFieldBuilder(); } - + public static ParameterBuilder newParameterBuilder() { return new ParameterBuilder(); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMClassBuilder.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMClassBuilder.java index 4db85f501..6088fce4b 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMClassBuilder.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMClassBuilder.java @@ -7,13 +7,17 @@ import joptsimple.internal.Strings; import org.objectweb.asm.Type; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public class ASMClassBuilder implements ASMCommon { + private Type name = null, srgName = null, obfuscatedName = null; private boolean auto = false; - - protected ASMClassBuilder() {} + + protected ASMClassBuilder() { + } public ASMClassBuilder setClassName(Type type) { name = type; @@ -22,7 +26,7 @@ public ASMClassBuilder setClassName(Type type) { public ASMClassBuilder setClassName(String internalClassName) { return setClassName( - !Strings.isNullOrEmpty(internalClassName) ? Type.getObjectType(internalClassName) : null); + !Strings.isNullOrEmpty(internalClassName) ? Type.getObjectType(internalClassName) : null); } public ASMClassBuilder setClassName(Class clazz) { @@ -31,17 +35,17 @@ public ASMClassBuilder setClassName(Class clazz) { public ASMClassBuilder setSrgClassName(String srgInternalClassName) { srgName = - !Strings.isNullOrEmpty(srgInternalClassName) - ? Type.getObjectType(srgInternalClassName) - : null; + !Strings.isNullOrEmpty(srgInternalClassName) + ? Type.getObjectType(srgInternalClassName) + : null; return this; } public ASMClassBuilder setObfuscatedClassName(String obfuscatedInternalClassName) { obfuscatedName = - !Strings.isNullOrEmpty(obfuscatedInternalClassName) - ? Type.getObjectType(obfuscatedInternalClassName) - : null; + !Strings.isNullOrEmpty(obfuscatedInternalClassName) + ? Type.getObjectType(obfuscatedInternalClassName) + : null; return this; } @@ -57,7 +61,9 @@ private void attemptAutoAssign() { public ASMClass build() { Objects.requireNonNull(name, "Class name is missing"); - if (auto) attemptAutoAssign(); + if (auto) { + attemptAutoAssign(); + } return new ASMClass(NameBuilder.create(name, srgName, obfuscatedName)); } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMFieldBuilder.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMFieldBuilder.java index bb6613b6a..440a17d47 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMFieldBuilder.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMFieldBuilder.java @@ -9,15 +9,19 @@ import joptsimple.internal.Strings; import org.objectweb.asm.Type; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public class ASMFieldBuilder implements ASMCommon { + private ASMClass parentClass = null; private String name = null, srgName = null, obfuscatedName = null; private IName type = null; private boolean auto = false; - - protected ASMFieldBuilder() {} + + protected ASMFieldBuilder() { + } public ASMFieldBuilder setParentClass(ASMClass parentClass) { this.parentClass = parentClass; @@ -62,7 +66,7 @@ public ASMFieldBuilder setType(Type type) { public ASMFieldBuilder setType(String internalClassName) { return setType( - !Strings.isNullOrEmpty(internalClassName) ? Type.getObjectType(internalClassName) : null); + !Strings.isNullOrEmpty(internalClassName) ? Type.getObjectType(internalClassName) : null); } public ASMFieldBuilder setType(Class clazz) { @@ -86,7 +90,9 @@ private void attemptAutoAssign() { public ASMField build() { Objects.requireNonNull(name, "Missing field name"); Objects.requireNonNull(type, "Missing field type"); - if (auto) attemptAutoAssign(); + if (auto) { + attemptAutoAssign(); + } return new ASMField(parentClass, NameBuilder.create(name, srgName, obfuscatedName), type); } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMMethodBuilder.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMMethodBuilder.java index 032869dd4..abe843a71 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMMethodBuilder.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ASMMethodBuilder.java @@ -9,8 +9,11 @@ import joptsimple.internal.Strings; import org.objectweb.asm.Type; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public class ASMMethodBuilder implements ASMCommon { + private static final IName[] NO_PARAMETERS = new ParameterBuilder().asArray(); private ASMClass parentClass = null; @@ -19,8 +22,9 @@ public class ASMMethodBuilder implements ASMCommon { private IName returnType = null; private boolean auto = false; - - protected ASMMethodBuilder() {} + + protected ASMMethodBuilder() { + } public ASMMethodBuilder setParentClass(ASMClass parentClass) { this.parentClass = parentClass; @@ -78,7 +82,7 @@ public ASMMethodBuilder setReturnType(Type returnType) { public ASMMethodBuilder setReturnType(String internalClassName) { return setReturnType( - !Strings.isNullOrEmpty(internalClassName) ? Type.getObjectType(internalClassName) : null); + !Strings.isNullOrEmpty(internalClassName) ? Type.getObjectType(internalClassName) : null); } public ASMMethodBuilder setReturnType(Class clazz) { @@ -97,7 +101,9 @@ public ASMMethodBuilder autoAssign() { private void attemptAutoAssign() { // build parameter list for normal state Type[] normalParameters = new Type[parameterTypes.length]; - for (int i = 0; i < parameterTypes.length; i++) normalParameters[i] = parameterTypes[i].get(); + for (int i = 0; i < parameterTypes.length; i++) { + normalParameters[i] = parameterTypes[i].get(); + } // create method descriptor String descriptor = Type.getMethodType(returnType.get(), normalParameters).getDescriptor(); @@ -109,10 +115,12 @@ public ASMMethod build() { // parent class not required Objects.requireNonNull(name, "Missing method name"); Objects.requireNonNull( - parameterTypes, "Missing method parameters (use emptyParameters() if none are present)"); + parameterTypes, "Missing method parameters (use emptyParameters() if none are present)"); Objects.requireNonNull(returnType, "Missing method return type"); - if (auto) attemptAutoAssign(); + if (auto) { + attemptAutoAssign(); + } return new ASMMethod( - parentClass, NameBuilder.create(name, srgName, obfuscatedName), parameterTypes, returnType); + parentClass, NameBuilder.create(name, srgName, obfuscatedName), parameterTypes, returnType); } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ParameterBuilder.java b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ParameterBuilder.java index 866a72dd6..171ff3078 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ParameterBuilder.java +++ b/src/main/java/com/matt/forgehax/asm/utils/asmtype/builders/ParameterBuilder.java @@ -1,6 +1,6 @@ package com.matt.forgehax.asm.utils.asmtype.builders; -import com.google.common.collect.*; +import com.google.common.collect.Lists; import com.matt.forgehax.asm.utils.asmtype.ASMClass; import com.matt.forgehax.asm.utils.name.IName; import com.matt.forgehax.asm.utils.name.NameBuilder; @@ -11,13 +11,17 @@ import joptsimple.internal.Strings; import org.objectweb.asm.Type; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public class ParameterBuilder { + private ASMMethodBuilder callback = null; private List> parameters = Lists.newArrayList(); private boolean overrideObfuscation = false; - - protected ParameterBuilder() {} + + protected ParameterBuilder() { + } protected ParameterBuilder(ASMMethodBuilder callback) { this.callback = callback; @@ -37,7 +41,7 @@ public ParameterBuilder add(Type parameter) { public ParameterBuilder add(String internalClassName) { return add( - !Strings.isNullOrEmpty(internalClassName) ? Type.getObjectType(internalClassName) : null); + !Strings.isNullOrEmpty(internalClassName) ? Type.getObjectType(internalClassName) : null); } public ParameterBuilder add(Class clazz) { @@ -45,8 +49,11 @@ public ParameterBuilder add(Class clazz) { } public ParameterBuilder add(ASMClass parameter) { - if (overrideObfuscation) parameters.add(NameBuilder.createSingleName(parameter.getAll().get())); - else parameters.add(parameter.getAll()); + if (overrideObfuscation) { + parameters.add(NameBuilder.createSingleName(parameter.getAll().get())); + } else { + parameters.add(parameter.getAll()); + } return this; } diff --git a/src/main/java/com/matt/forgehax/asm/utils/debug/HookReporter.java b/src/main/java/com/matt/forgehax/asm/utils/debug/HookReporter.java index 6d43e0e58..a139817c8 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/debug/HookReporter.java +++ b/src/main/java/com/matt/forgehax/asm/utils/debug/HookReporter.java @@ -14,8 +14,11 @@ import java.util.stream.Collectors; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 2/11/2018 by fr1kin */ +/** + * Created on 2/11/2018 by fr1kin + */ public class HookReporter { + private final Method method; private final List hookedMethods; @@ -25,18 +28,20 @@ public class HookReporter { private MultiBoolean activator = new MultiBoolean(); private HookReporter( - Method method, - Collection hookedMethods, - Collection> eventClasses, - boolean startDisabled) - throws NullPointerException { + Method method, + Collection hookedMethods, + Collection> eventClasses, + boolean startDisabled) + throws NullPointerException { Objects.requireNonNull(method); this.method = method; this.hookedMethods = Immutables.copyToList(hookedMethods); this.eventClasses = Immutables.copyToList(eventClasses); - - if (!startDisabled) enable(); + + if (!startDisabled) { + enable(); + } } /** @@ -59,8 +64,6 @@ public List getHookedMethods() { /** * Gets all the event classes that are created by this hook - * - * @return */ public List> getEventClasses() { return eventClasses; @@ -74,19 +77,19 @@ public List> getEventClasses() { @SuppressWarnings("unchecked") public List> getForgeEventClasses() { return eventClasses - .stream() - .filter(Event.class::isAssignableFrom) - .map(clazz -> (Class) clazz) - .collect(Immutables.toImmutableList()); + .stream() + .filter(Event.class::isAssignableFrom) + .map(clazz -> (Class) clazz) + .collect(Immutables.toImmutableList()); } @SuppressWarnings("unchecked") public List> getListenerEventClasses() { return eventClasses - .stream() - .filter(ListenerHook.class::isAssignableFrom) - .map(clazz -> (Class) clazz) - .collect(Immutables.toImmutableList()); + .stream() + .filter(ListenerHook.class::isAssignableFrom) + .map(clazz -> (Class) clazz) + .collect(Immutables.toImmutableList()); } /** @@ -116,13 +119,17 @@ public boolean reportHook() { public MultiBoolean getActivator() { return activator; } - - /** Enables the hook */ + + /** + * Enables the hook + */ public void enable() { activator.enable("root"); } - - /** Force disables the hook */ + + /** + * Force disables the hook + */ public void disable() { activator.forceDisable(); } @@ -144,8 +151,8 @@ public int hashCode() { @Override public boolean equals(Object obj) { return this == obj - || (obj instanceof HookReporter - && Objects.equals(getMethod(), ((HookReporter) obj).getMethod())); + || (obj instanceof HookReporter + && Objects.equals(getMethod(), ((HookReporter) obj).getMethod())); } @Override @@ -154,11 +161,13 @@ public String toString() { } public static class Builder { + public static Builder of() { return new Builder(); } - - private Builder() {} + + private Builder() { + } private Method method; private List hookedMethods = Lists.newArrayList(); @@ -190,19 +199,22 @@ public Builder hook(Method method) { } public Builder hook(Class parentClass, final String methodName) - throws InvalidMethodException { + throws InvalidMethodException { Objects.requireNonNull(parentClass); Objects.requireNonNull(methodName); List results = - Arrays.stream(parentClass.getDeclaredMethods()) - .filter(m -> methodName.equals(m.getName())) - .collect(Collectors.toList()); - - if (results.size() == 1) return hook(results.get(0)); - else if (results.size() > 1) + Arrays.stream(parentClass.getDeclaredMethods()) + .filter(m -> methodName.equals(m.getName())) + .collect(Collectors.toList()); + + if (results.size() == 1) { + return hook(results.get(0)); + } else if (results.size() > 1) { throw new InvalidMethodException("Found two methods with the same name"); - else throw new InvalidMethodException("No such method found"); + } else { + throw new InvalidMethodException("No such method found"); + } } public Builder hook(final String methodName) throws InvalidMethodException { @@ -254,12 +266,15 @@ public Builder finalizeBy(Consumer finalizeBy) { public HookReporter build() { final HookReporter hp = new HookReporter(method, hookedMethods, eventClasses, startDisabled); - if (finalizeBy != null) finalizeBy.accept(hp); + if (finalizeBy != null) { + finalizeBy.accept(hp); + } return hp; } } public static class InvalidMethodException extends RuntimeException { + public InvalidMethodException(String message) { super(message); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/environment/IStateMapper.java b/src/main/java/com/matt/forgehax/asm/utils/environment/IStateMapper.java index 92b4a126d..2e21d2e87 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/environment/IStateMapper.java +++ b/src/main/java/com/matt/forgehax/asm/utils/environment/IStateMapper.java @@ -2,23 +2,26 @@ import javax.annotation.Nullable; -/** Created on 5/28/2017 by fr1kin */ +/** + * Created on 5/28/2017 by fr1kin + */ public interface IStateMapper { + @Nullable String getObfClassName(String className); - + @Nullable String getMcpClassName(String className); - + @Nullable String getSrgMethodName(String parentClassName, String methodName, String methodDescriptor); - + @Nullable String getObfMethodName(String parentClassName, String methodName, String methodDescriptor); - + @Nullable String getSrgFieldName(String parentClassName, String fieldName); - + @Nullable String getObfFieldName(String parentClassName, String fieldName); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/environment/RuntimeState.java b/src/main/java/com/matt/forgehax/asm/utils/environment/RuntimeState.java index 3cb354b4a..67b43f902 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/environment/RuntimeState.java +++ b/src/main/java/com/matt/forgehax/asm/utils/environment/RuntimeState.java @@ -3,9 +3,14 @@ import com.matt.forgehax.asm.utils.remapping.NonObfuscatedStateMapper; import com.matt.forgehax.asm.utils.remapping.ObfuscatedStateMapper; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public class RuntimeState { - /** Used for remapping Notch to SRG and obfuscated naming conventions */ + + /** + * Used for remapping Notch to SRG and obfuscated naming conventions + */ private static IStateMapper remapper = null; /** @@ -13,9 +18,11 @@ public class RuntimeState { * feeds us the obfuscation state */ private static ThreadLocal localState = - ThreadLocal.withInitial(RuntimeState::getDefaultState); - - /** Default state use (unless specified not to) */ + ThreadLocal.withInitial(RuntimeState::getDefaultState); + + /** + * Default state use (unless specified not to) + */ private static State defaultState = State.OBFUSCATED; public static State getDefaultState() { @@ -60,10 +67,10 @@ public static boolean isObfuscated() { public static IStateMapper getMapper() { return remapper == null - ? remapper = - (isObfuscated() - ? ObfuscatedStateMapper.getInstance() - : NonObfuscatedStateMapper.getInstance()) - : remapper; + ? remapper = + (isObfuscated() + ? ObfuscatedStateMapper.getInstance() + : NonObfuscatedStateMapper.getInstance()) + : remapper; } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/environment/State.java b/src/main/java/com/matt/forgehax/asm/utils/environment/State.java index 5c8abc5db..fe53883b4 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/environment/State.java +++ b/src/main/java/com/matt/forgehax/asm/utils/environment/State.java @@ -1,6 +1,8 @@ package com.matt.forgehax.asm.utils.environment; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public enum State { NORMAL, SRG, diff --git a/src/main/java/com/matt/forgehax/asm/utils/exception/NoMatchingPatternException.java b/src/main/java/com/matt/forgehax/asm/utils/exception/NoMatchingPatternException.java deleted file mode 100644 index 5345d0eaf..000000000 --- a/src/main/java/com/matt/forgehax/asm/utils/exception/NoMatchingPatternException.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.matt.forgehax.asm.utils.exception; - -/** Created on 5/4/2017 by fr1kin */ -public class NoMatchingPatternException extends RuntimeException { - public NoMatchingPatternException() { - super(); - } - - public NoMatchingPatternException(String message) { - super(message); - } - - public NoMatchingPatternException(String message, Throwable cause) { - super(message, cause); - } - - public NoMatchingPatternException(Throwable cause) { - super(cause); - } - - protected NoMatchingPatternException( - String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastClass.java b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastClass.java index e76b2c1bb..e17aaa21d 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastClass.java +++ b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastClass.java @@ -4,24 +4,31 @@ import com.matt.forgehax.asm.utils.environment.RuntimeState; import com.matt.forgehax.asm.utils.name.IName; -/** Created on 7/6/2017 by fr1kin */ +/** + * Created on 7/6/2017 by fr1kin + */ public class FastClass extends FastType> { + public FastClass(IName name) { super(null, name); } - + public Class getClassHandle() { try { - if (attemptLookup()) return type; + if (attemptLookup()) { + return type; + } } catch (Throwable t) { - if (printOnce.compareAndSet(false, true)) ASMStackLogger.printStackTrace(t); + if (printOnce.compareAndSet(false, true)) { + ASMStackLogger.printStackTrace(t); + } } return null; } - + @Override protected Class lookup() throws Exception { return Class.forName( - name.getByStateSafe(RuntimeState.getState()), false, getClass().getClassLoader()); + name.getByStateSafe(RuntimeState.getState()), false, getClass().getClassLoader()); } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastField.java b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastField.java index 97e4039f6..8c2f31a91 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastField.java +++ b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastField.java @@ -7,8 +7,11 @@ import java.lang.reflect.Modifier; import joptsimple.internal.Strings; -/** Created on 5/25/2017 by fr1kin */ +/** + * Created on 5/25/2017 by fr1kin + */ public class FastField extends FastType { + private final boolean stripFinal; public FastField(Class insideClass, IName name, boolean stripFinal) { @@ -18,9 +21,13 @@ public FastField(Class insideClass, IName name, boolean stripFinal) { public V get(E instance, V defaultValue) { try { - if (attemptLookup()) return (V) type.get(instance); + if (attemptLookup()) { + return (V) type.get(instance); + } } catch (Exception e) { - if (printOnce.compareAndSet(false, true)) ASMStackLogger.printStackTrace(e); + if (printOnce.compareAndSet(false, true)) { + ASMStackLogger.printStackTrace(e); + } } return defaultValue; } @@ -44,7 +51,9 @@ public boolean set(E instance, V to) { return true; } } catch (Exception e) { - if (printOnce.compareAndSet(false, true)) ASMStackLogger.printStackTrace(e); + if (printOnce.compareAndSet(false, true)) { + ASMStackLogger.printStackTrace(e); + } } return false; // failed to set } @@ -57,7 +66,7 @@ public boolean setStatic(V to) { protected Field lookup() throws Exception { for (State state : State.values()) { String n = name.getByState(state); - if (!Strings.isNullOrEmpty(n)) + if (!Strings.isNullOrEmpty(n)) { try { Field f = insideClass.getDeclaredField(n); f.setAccessible(true); @@ -67,8 +76,10 @@ protected Field lookup() throws Exception { modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL); } return f; - } catch (Exception e) {; + } catch (Exception e) { + ; } + } } return null; } diff --git a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastMethod.java b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastMethod.java index 913ac9a0f..083737ecd 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastMethod.java +++ b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastMethod.java @@ -8,8 +8,11 @@ import java.util.Objects; import joptsimple.internal.Strings; -/** Created on 5/25/2017 by fr1kin */ +/** + * Created on 5/25/2017 by fr1kin + */ public class FastMethod extends FastType { + private final Class[] parameters; public FastMethod(Class insideClass, IName name, Class[] parameters) { @@ -23,9 +26,13 @@ public Class[] getParameters() { public V invoke(E instance, V defaultValue, Object... args) { try { - if (attemptLookup()) return (V) type.invoke(instance, args); + if (attemptLookup()) { + return (V) type.invoke(instance, args); + } } catch (Exception e) { - if (printOnce.compareAndSet(false, true)) ASMStackLogger.printStackTrace(e); + if (printOnce.compareAndSet(false, true)) { + ASMStackLogger.printStackTrace(e); + } } return defaultValue; } @@ -43,13 +50,15 @@ protected Method lookup() throws Exception { Objects.requireNonNull(parameters); for (State state : State.values()) { String n = name.getByState(state); - if (!Strings.isNullOrEmpty(n)) + if (!Strings.isNullOrEmpty(n)) { try { Method m = insideClass.getDeclaredMethod(n, parameters); m.setAccessible(true); return m; - } catch (Exception e) {; + } catch (Exception e) { + ; } + } } return null; } diff --git a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastType.java b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastType.java index d01c61970..ae3b41301 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastType.java +++ b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastType.java @@ -3,8 +3,11 @@ import com.matt.forgehax.asm.utils.name.IName; import java.util.concurrent.atomic.AtomicBoolean; -/** Created on 5/25/2017 by fr1kin */ +/** + * Created on 5/25/2017 by fr1kin + */ public abstract class FastType { + protected final Class insideClass; protected final IName name; @@ -37,9 +40,13 @@ protected boolean attemptLookup() throws Exception { lookupFailed = (type == null); } return !lookupFailed; - } else return true; // previous attempt failed, trying again wont work + } else { + return true; // previous attempt failed, trying again wont work + } } - - /** Reflection lookup */ + + /** + * Reflection lookup + */ protected abstract T lookup() throws Exception; } diff --git a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastTypeBuilder.java b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastTypeBuilder.java index 1943c982c..8359f6328 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastTypeBuilder.java +++ b/src/main/java/com/matt/forgehax/asm/utils/fasttype/FastTypeBuilder.java @@ -6,71 +6,72 @@ import java.util.Objects; import org.objectweb.asm.Type; -/** Created on 5/25/2017 by fr1kin */ +/** + * Created on 5/25/2017 by fr1kin + */ public class FastTypeBuilder implements ASMCommon { + public static FastTypeBuilder create() { return new FastTypeBuilder(); } - + private Class insideClass = null; private String name = null, srgName = null, obfuscatedName = null; - + // method only private Class[] parameters = null; private Class returnType = null; - + private boolean auto = false; private boolean stripFinal = false; - + public FastTypeBuilder setInsideClass(Class insideClass) { this.insideClass = insideClass; return this; } - + public FastTypeBuilder setInsideClass(FastClass clazz) { return setInsideClass(clazz.getClassHandle()); } - + public FastTypeBuilder setName(String name) { this.name = name; return this; } - + public FastTypeBuilder setSrgName(String name) { this.srgName = name; return this; } - + public FastTypeBuilder setObfuscatedName(String name) { this.obfuscatedName = name; return this; } - + public FastTypeBuilder setParameters(Class... parameters) { this.parameters = Arrays.copyOf(parameters, parameters.length); return this; } - + /** * Only required if you want to use autoAssign() on a method - * - * @param returnType */ public FastTypeBuilder setReturnType(Class returnType) { this.returnType = returnType; return this; } - + public FastTypeBuilder autoAssign() { auto = true; return this; } - + public FastTypeBuilder definalize() { this.stripFinal = true; return this; } - + public FastClass asClass() { Objects.requireNonNull(name); if (auto) { @@ -78,7 +79,7 @@ public FastClass asClass() { } return new FastClass(NameBuilder.create(name, srgName, obfuscatedName)); } - + public FastField asField() { Objects.requireNonNull(insideClass); Objects.requireNonNull(name); @@ -88,9 +89,9 @@ public FastField asField() { obfuscatedName = MAPPER.getObfFieldName(parentClassInternalName, name); } return new FastField( - insideClass, NameBuilder.create(name, srgName, obfuscatedName), stripFinal); + insideClass, NameBuilder.create(name, srgName, obfuscatedName), stripFinal); } - + public FastMethod asMethod() { Objects.requireNonNull(insideClass); Objects.requireNonNull(name); @@ -100,12 +101,14 @@ public FastMethod asMethod() { String parentClassInternalName = Type.getType(insideClass).getInternalName(); // build method descriptor Type[] args = new Type[parameters.length]; - for (int i = 0; i < args.length; i++) args[i] = Type.getType(parameters[i]); + for (int i = 0; i < args.length; i++) { + args[i] = Type.getType(parameters[i]); + } String descriptor = Type.getMethodType(Type.getType(returnType), args).getDescriptor(); srgName = MAPPER.getSrgMethodName(parentClassInternalName, name, descriptor); obfuscatedName = MAPPER.getObfMethodName(parentClassInternalName, name, descriptor); } return new FastMethod( - insideClass, NameBuilder.create(name, srgName, obfuscatedName), parameters); + insideClass, NameBuilder.create(name, srgName, obfuscatedName), parameters); } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/name/IName.java b/src/main/java/com/matt/forgehax/asm/utils/name/IName.java index d0defd6c1..13dd68cd7 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/name/IName.java +++ b/src/main/java/com/matt/forgehax/asm/utils/name/IName.java @@ -4,19 +4,22 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public interface IName { + @Nonnull E get(); - + @Nullable E getByState(State state); - + @Nonnull default E getByStateSafe(State state) { E value = getByState(state); return value != null ? value : get(); } - + int getStateCount(); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/name/McMultiName.java b/src/main/java/com/matt/forgehax/asm/utils/name/McMultiName.java index a7479d4b4..91bdff959 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/name/McMultiName.java +++ b/src/main/java/com/matt/forgehax/asm/utils/name/McMultiName.java @@ -4,8 +4,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public class McMultiName extends SingleName { + private final E srg; private final E obf; diff --git a/src/main/java/com/matt/forgehax/asm/utils/name/NameBuilder.java b/src/main/java/com/matt/forgehax/asm/utils/name/NameBuilder.java index a60aeaf5e..d78b070b6 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/name/NameBuilder.java +++ b/src/main/java/com/matt/forgehax/asm/utils/name/NameBuilder.java @@ -1,10 +1,16 @@ package com.matt.forgehax.asm.utils.name; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ public class NameBuilder { + public static IName create(E real, E srg, E obf) { - if (srg == null && obf == null) return createSingleName(real); - else return createMcMultiName(real, srg, obf); + if (srg == null && obf == null) { + return createSingleName(real); + } else { + return createMcMultiName(real, srg, obf); + } } public static IName createSingleName(E real) { diff --git a/src/main/java/com/matt/forgehax/asm/utils/name/SingleName.java b/src/main/java/com/matt/forgehax/asm/utils/name/SingleName.java index ebcb53b7a..1c373d0b7 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/name/SingleName.java +++ b/src/main/java/com/matt/forgehax/asm/utils/name/SingleName.java @@ -5,8 +5,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -/** Created on 5/26/2017 by fr1kin */ +/** + * Created on 5/26/2017 by fr1kin + */ public class SingleName implements IName { + private final E normal; public SingleName(@Nonnull E normal) { diff --git a/src/main/java/com/matt/forgehax/asm/utils/remapping/FileDumper.java b/src/main/java/com/matt/forgehax/asm/utils/remapping/FileDumper.java index 23c81b28f..f71821b9d 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/remapping/FileDumper.java +++ b/src/main/java/com/matt/forgehax/asm/utils/remapping/FileDumper.java @@ -4,13 +4,21 @@ import com.matt.forgehax.asm.TypesHook; import com.matt.forgehax.asm.TypesMc; import com.matt.forgehax.asm.utils.asmtype.IASMType; -import java.io.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; -import java.util.*; +import java.util.Comparator; +import java.util.Map; +import java.util.TreeMap; import java.util.function.Consumer; -/** Created on 1/11/2017 by fr1kin */ +/** + * Created on 1/11/2017 by fr1kin + */ public class FileDumper { + private static void dump(File dumpLocation, Consumer consumer) { PrintWriter writer = null; try { @@ -21,85 +29,87 @@ private static void dump(File dumpLocation, Consumer consumer) { } catch (UnsupportedEncodingException e) { e.printStackTrace(); } finally { - if (writer != null) writer.close(); + if (writer != null) { + writer.close(); + } } } private static void dumpMap(File dumpLocation, final Map mapIn) { dump( - dumpLocation, - writer -> { - for (Map.Entry entry : new TreeMap<>(mapIn).entrySet()) { - writer.println(entry.getKey() + "->" + entry.getValue()); - } - }); + dumpLocation, + writer -> { + for (Map.Entry entry : new TreeMap<>(mapIn).entrySet()) { + writer.println(entry.getKey() + "->" + entry.getValue()); + } + }); } private static void dumpMaps(File dumpLocation, final Map> mapIn) { dump( - dumpLocation, - writer -> { - for (Map.Entry> entry : new TreeMap<>(mapIn).entrySet()) { - writer.println(entry.getKey()); - for (Map.Entry subEntry : new TreeMap<>(entry.getValue()).entrySet()) { - writer.println("\t" + subEntry.getKey() + "->" + subEntry.getValue()); - } + dumpLocation, + writer -> { + for (Map.Entry> entry : new TreeMap<>(mapIn).entrySet()) { + writer.println(entry.getKey()); + for (Map.Entry subEntry : new TreeMap<>(entry.getValue()).entrySet()) { + writer.println("\t" + subEntry.getKey() + "->" + subEntry.getValue()); } - }); + } + }); } private static void dumpASMTypes(File dumpLocation, Map mapIn) { dump( - dumpLocation, - writer -> { - final StringBuilder builder = new StringBuilder(); - mapIn.forEach( - (k, v) -> { - builder.append(k); - builder.append(":"); - builder.append(v.toString()); - builder.append("\n"); - }); - writer.println(builder.toString()); - }); + dumpLocation, + writer -> { + final StringBuilder builder = new StringBuilder(); + mapIn.forEach( + (k, v) -> { + builder.append(k); + builder.append(":"); + builder.append(v.toString()); + builder.append("\n"); + }); + writer.println(builder.toString()); + }); } private static void dumpMcpTypeMap( - File dumpLocation, final Map> mapIn) { + File dumpLocation, final Map> mapIn) { dump( - dumpLocation, - writer -> { - final StringBuilder builder = new StringBuilder(); - mapIn - .entrySet() - .stream() - .sorted(Comparator.comparing(Map.Entry::getKey)) - .forEach( - entry -> { - // class name - builder.append(entry.getKey()); - builder.append("\n{\n"); - entry - .getValue() - .entrySet() - .stream() - .sorted(Comparator.comparing(Map.Entry::getKey)) - .forEach( - dataEntry -> { - builder.append("\t"); - builder.append(dataEntry.getKey()); - builder.append("\n\t{\n\t\tSrgName: "); - builder.append(dataEntry.getValue().getSrgName()); - builder.append("\n\t\tObfName: "); - builder.append(dataEntry.getValue().getObfName()); - builder.append("\n\t\tMcpName: "); - builder.append(dataEntry.getValue().getMcpName()); - builder.append("\n\t}\n"); - }); - builder.append("}\n"); + dumpLocation, + writer -> { + final StringBuilder builder = new StringBuilder(); + mapIn + .entrySet() + .stream() + .sorted(Comparator.comparing(Map.Entry::getKey)) + .forEach( + entry -> { + // class name + builder.append(entry.getKey()); + builder.append("\n{\n"); + entry + .getValue() + .entrySet() + .stream() + .sorted(Comparator.comparing(Map.Entry::getKey)) + .forEach( + dataEntry -> { + builder.append("\t"); + builder.append(dataEntry.getKey()); + builder.append("\n\t{\n\t\tSrgName: "); + builder.append(dataEntry.getValue().getSrgName()); + builder.append("\n\t\tObfName: "); + builder.append(dataEntry.getValue().getObfName()); + builder.append("\n\t\tMcpName: "); + builder.append(dataEntry.getValue().getMcpName()); + builder.append("\n\t}\n"); }); - writer.println(builder.toString()); - }); + builder.append("}\n"); + }); + writer.println(builder.toString()); + }); } public static void dumpAllFiles() { @@ -115,14 +125,14 @@ public static void dumpAllFiles() { dumpMcpTypeMap(new File(dumpDir, "fields.txt"), obfuscatedRemapper.getMcpFieldData()); Class[] constants = - new Class[] { - TypesMc.Classes.class, - TypesMc.Fields.class, - TypesMc.Methods.class, - TypesHook.Classes.class, - TypesHook.Fields.class, - TypesHook.Methods.class - }; + new Class[]{ + TypesMc.Classes.class, + TypesMc.Fields.class, + TypesMc.Methods.class, + TypesHook.Classes.class, + TypesHook.Fields.class, + TypesHook.Methods.class + }; File typeDumpDir = new File(dumpDir, "typedump"); typeDumpDir.mkdirs(); @@ -133,14 +143,16 @@ public static void dumpAllFiles() { for (Field field : clazz.getFields()) { try { Object instance = field.get(null); - if (instance instanceof IASMType) types.put(field.getName(), (IASMType) instance); + if (instance instanceof IASMType) { + types.put(field.getName(), (IASMType) instance); + } } catch (IllegalAccessException e) { e.printStackTrace(); } } dumpASMTypes( - new File(typeDumpDir, clazz.getName().replaceAll("[^a-zA-Z0-9.-]", "_") + ".txt"), - types); + new File(typeDumpDir, clazz.getName().replaceAll("[^a-zA-Z0-9.-]", "_") + ".txt"), + types); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/remapping/MCPMappingLoader.java b/src/main/java/com/matt/forgehax/asm/utils/remapping/MCPMappingLoader.java index 410cd3f72..6ff23d7ac 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/remapping/MCPMappingLoader.java +++ b/src/main/java/com/matt/forgehax/asm/utils/remapping/MCPMappingLoader.java @@ -1,22 +1,30 @@ package com.matt.forgehax.asm.utils.remapping; -import bspkrs.mmv.*; +import bspkrs.mmv.CsvFile; +import bspkrs.mmv.ExcFile; +import bspkrs.mmv.ParamCsvFile; +import bspkrs.mmv.RemoteZipHandler; +import bspkrs.mmv.SrgFile; +import bspkrs.mmv.StaticMethodsFile; import com.matt.forgehax.asm.utils.ASMStackLogger; import java.io.File; import java.io.IOException; import java.security.DigestException; import java.security.NoSuchAlgorithmException; -/** Credits to bspkrs */ +/** + * Credits to bspkrs + */ public class MCPMappingLoader { + private final File baseDir = - new File(new File(System.getProperty("user.home")), ".cache/MCPMappingViewer"); + new File(new File(System.getProperty("user.home")), ".cache/MCPMappingViewer"); private final String baseSrgDir = "{mc_ver}"; private final String baseMappingDir = "{mc_ver}/{channel}_{map_ver}"; private final String baseMappingUrl = - "http://export.mcpbot.bspk.rs/mcp_{channel}/{map_ver}-{mc_ver}/mcp_{channel}-{map_ver}-{mc_ver}.zip"; + "http://export.mcpbot.bspk.rs/mcp_{channel}/{map_ver}-{mc_ver}/mcp_{channel}-{map_ver}-{mc_ver}.zip"; private final String baseSrgUrl = - "http://export.mcpbot.bspk.rs/mcp/{mc_ver}/mcp-{mc_ver}-srg.zip"; + "http://export.mcpbot.bspk.rs/mcp/{mc_ver}/mcp-{mc_ver}-srg.zip"; private final File srgDir; private final File mappingDir; @@ -31,10 +39,11 @@ public class MCPMappingLoader { private ParamCsvFile csvParamData; public MCPMappingLoader(String mapping) - throws IOException, CantLoadMCPMappingException, NoSuchAlgorithmException, DigestException { + throws IOException, CantLoadMCPMappingException, NoSuchAlgorithmException, DigestException { String[] tokens = mapping.split("_"); - if (tokens.length < 3) + if (tokens.length < 3) { throw new CantLoadMCPMappingException("Invalid mapping string specified."); + } srgDir = getSubDirForZip(tokens, baseSrgUrl, baseSrgDir); mappingDir = getSubDirForZip(tokens, baseMappingUrl, baseMappingDir); @@ -42,18 +51,21 @@ public MCPMappingLoader(String mapping) srgFile = new File(srgDir, "joined.srg"); excFile = new File(srgDir, "joined.exc"); staticMethodsFile = new File(srgDir, "static_methods.txt"); - - if (!srgFile.exists()) + + if (!srgFile.exists()) { throw new CantLoadMCPMappingException( - "Unable to find joined.srg. Your MCP conf folder may be corrupt."); - - if (!excFile.exists()) + "Unable to find joined.srg. Your MCP conf folder may be corrupt."); + } + + if (!excFile.exists()) { throw new CantLoadMCPMappingException( - "Unable to find joined.exc. Your MCP conf folder may be corrupt."); - - if (!staticMethodsFile.exists()) + "Unable to find joined.exc. Your MCP conf folder may be corrupt."); + } + + if (!staticMethodsFile.exists()) { throw new CantLoadMCPMappingException( - "Unable to find static_methods.txt. Your MCP conf folder may be corrupt."); + "Unable to find static_methods.txt. Your MCP conf folder may be corrupt."); + } staticMethods = new StaticMethodsFile(staticMethodsFile); excFileData = new ExcFile(excFile); @@ -77,18 +89,20 @@ public SrgFile getSrgFileData() { } private File getSubDirForZip(String[] tokens, String baseZipUrl, String baseSubDir) - throws CantLoadMCPMappingException, NoSuchAlgorithmException, DigestException, IOException { - if (!baseDir.exists() && !baseDir.mkdirs()) + throws CantLoadMCPMappingException, NoSuchAlgorithmException, DigestException, IOException { + if (!baseDir.exists() && !baseDir.mkdirs()) { throw new CantLoadMCPMappingException( - "Application data folder does not exist and cannot be created."); + "Application data folder does not exist and cannot be created."); + } File subDir = new File(baseDir, replaceTokens(baseSubDir, tokens)); - if (!subDir.exists() && !subDir.mkdirs()) + if (!subDir.exists() && !subDir.mkdirs()) { throw new CantLoadMCPMappingException("Data folder does not exist and cannot be created."); + } try { RemoteZipHandler rzh = - new RemoteZipHandler(replaceTokens(baseZipUrl, tokens), subDir, "SHA1"); + new RemoteZipHandler(replaceTokens(baseZipUrl, tokens), subDir, "SHA1"); rzh.checkRemoteZip(); } catch (Throwable t) { ASMStackLogger.printStackTrace(t); @@ -99,11 +113,12 @@ private File getSubDirForZip(String[] tokens, String baseZipUrl, String baseSubD private String replaceTokens(String s, String[] tokens) { return s.replace("{mc_ver}", tokens[0]) - .replace("{channel}", tokens[1]) - .replace("{map_ver}", tokens[2]); + .replace("{channel}", tokens[1]) + .replace("{map_ver}", tokens[2]); } public static class CantLoadMCPMappingException extends Exception { + public CantLoadMCPMappingException(String msg) { super(msg); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/remapping/NonObfuscatedStateMapper.java b/src/main/java/com/matt/forgehax/asm/utils/remapping/NonObfuscatedStateMapper.java index 40a3e46b0..4a823d146 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/remapping/NonObfuscatedStateMapper.java +++ b/src/main/java/com/matt/forgehax/asm/utils/remapping/NonObfuscatedStateMapper.java @@ -3,8 +3,11 @@ import com.matt.forgehax.asm.utils.environment.IStateMapper; import javax.annotation.Nullable; -/** Created on 5/28/2017 by fr1kin */ +/** + * Created on 5/28/2017 by fr1kin + */ public class NonObfuscatedStateMapper implements IStateMapper { + private static NonObfuscatedStateMapper INSTANCE = null; public static NonObfuscatedStateMapper getInstance() { @@ -26,15 +29,15 @@ public String getMcpClassName(String className) { @Nullable @Override public String getSrgMethodName( - String parentClassName, String methodName, String methodDescriptor) { + String parentClassName, String methodName, String methodDescriptor) { return ObfuscatedStateMapper.getInstance() - .getSrgMethodName(parentClassName, methodName, methodDescriptor); + .getSrgMethodName(parentClassName, methodName, methodDescriptor); } @Nullable @Override public String getObfMethodName( - String parentClassName, String methodName, String methodDescriptor) { + String parentClassName, String methodName, String methodDescriptor) { return null; } diff --git a/src/main/java/com/matt/forgehax/asm/utils/remapping/ObfuscatedStateMapper.java b/src/main/java/com/matt/forgehax/asm/utils/remapping/ObfuscatedStateMapper.java index 6530e9db0..2675ca76a 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/remapping/ObfuscatedStateMapper.java +++ b/src/main/java/com/matt/forgehax/asm/utils/remapping/ObfuscatedStateMapper.java @@ -15,28 +15,35 @@ import com.matt.forgehax.asm.utils.ASMStackLogger; import com.matt.forgehax.asm.utils.environment.IStateMapper; import com.matt.forgehax.asm.utils.environment.RuntimeState; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.function.Function; import javax.annotation.Nullable; import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper; import org.objectweb.asm.Type; -/** Created on 1/12/2017 by fr1kin */ +/** + * Created on 1/12/2017 by fr1kin + */ public class ObfuscatedStateMapper implements ASMCommon, IStateMapper { + private static ObfuscatedStateMapper INSTANCE = null; - + public static ObfuscatedStateMapper getInstance() { return INSTANCE == null ? INSTANCE = new ObfuscatedStateMapper() : INSTANCE; } - + private final BiMap mcClasses; - + private final Map> mcpMethodData; private final Map> mcpFieldData; - + protected ObfuscatedStateMapper() { LOGGER.info("Using build mapping \"" + ForgeHaxProperties.getMcpMappingUrl() + "\""); - + MCPMappingLoader mcpMappingLoader = null; try { mcpMappingLoader = new MCPMappingLoader(ForgeHaxProperties.getMcpMappingUrl()); @@ -44,118 +51,123 @@ protected ObfuscatedStateMapper() { LOGGER.error(e.getMessage()); ASMStackLogger.printStackTrace(e); } - + LOGGER.info("Mapping data successfully initialize"); - + Objects.requireNonNull(mcpMappingLoader, "MCPMappingLoader failed to lookup obfuscation data"); - - if (isObfuscated()) LOGGER.info("initializing ObfuscatedStateMapper WITH obfuscation"); - else LOGGER.info("initializing ObfuscatedStateMapper WITHOUT obfuscation"); - + + if (isObfuscated()) { + LOGGER.info("initializing ObfuscatedStateMapper WITH obfuscation"); + } else { + LOGGER.info("initializing ObfuscatedStateMapper WITHOUT obfuscation"); + } + this.mcClasses = - ImmutableBiMap.copyOf( - FastReflectionForge.Fields.FMLDeobfuscatingRemapper_classNameBiMap.get( - FMLDeobfuscatingRemapper.INSTANCE)); - + ImmutableBiMap.copyOf( + FastReflectionForge.Fields.FMLDeobfuscatingRemapper_classNameBiMap.get( + FMLDeobfuscatingRemapper.INSTANCE)); + this.mcpMethodData = - buildMcpTypeData( - mcpMappingLoader.getCsvMethodData(), - mcpMappingLoader.getSrgFileData().class2MethodDataSet, - getConvertedMap( - FastReflectionForge.Fields.FMLDeobfuscatingRemapper_rawMethodMaps.get( - FMLDeobfuscatingRemapper.INSTANCE), - str -> str.split("\\(")[0]), - ((csvData, data) -> csvData.getMcpName() + data.getSrgDescriptor())); + buildMcpTypeData( + mcpMappingLoader.getCsvMethodData(), + mcpMappingLoader.getSrgFileData().class2MethodDataSet, + getConvertedMap( + FastReflectionForge.Fields.FMLDeobfuscatingRemapper_rawMethodMaps.get( + FMLDeobfuscatingRemapper.INSTANCE), + str -> str.split("\\(")[0]), + ((csvData, data) -> csvData.getMcpName() + data.getSrgDescriptor())); this.mcpFieldData = - buildMcpTypeData( - mcpMappingLoader.getCsvFieldData(), - mcpMappingLoader.getSrgFileData().class2FieldDataSet, - getConvertedMap( - FastReflectionForge.Fields.FMLDeobfuscatingRemapper_rawFieldMaps.get( - FMLDeobfuscatingRemapper.INSTANCE), - str -> str.split(":")[0]), - ((csvData, data) -> csvData.getMcpName())); + buildMcpTypeData( + mcpMappingLoader.getCsvFieldData(), + mcpMappingLoader.getSrgFileData().class2FieldDataSet, + getConvertedMap( + FastReflectionForge.Fields.FMLDeobfuscatingRemapper_rawFieldMaps.get( + FMLDeobfuscatingRemapper.INSTANCE), + str -> str.split(":")[0]), + ((csvData, data) -> csvData.getMcpName())); } - + public boolean isObfuscated() { return RuntimeState.isObfuscated(); } - + public Map getMcClasses() { return Collections.unmodifiableMap(mcClasses); } - + public Map> getMcpFieldData() { return mcpFieldData; } - + public Map> getMcpMethodData() { return mcpMethodData; } - + protected String getClassName(String className, Map map) { // mcp map -> obf name String name = map.get(className); if (Strings.isNullOrEmpty(name)) { LOGGER.warn("Could not lookup name for class '" + className + "'"); return null; - } else return name; + } else { + return name; + } } - + @Nullable @Override public String getObfClassName(String className) { return getClassName(className, mcClasses.inverse()); } - + @Nullable @Override public String getMcpClassName(String className) { return getClassName(className, mcClasses); } - + @Nullable @Override public String getSrgMethodName( - String parentClassName, String methodName, String methodDescriptor) { + String parentClassName, String methodName, String methodDescriptor) { try { return getMcpMethodData() - .get(parentClassName) - .get(methodName + methodDescriptor) - .getSrgName(); + .get(parentClassName) + .get(methodName + methodDescriptor) + .getSrgName(); } catch (Exception e) { LOGGER.warn( - "Could not lookup srg name for method '" - + parentClassName - + "::" - + methodName - + methodDescriptor - + "'"); + "Could not lookup srg name for method '" + + parentClassName + + "::" + + methodName + + methodDescriptor + + "'"); return null; } } - + @Nullable @Override public String getObfMethodName( - String parentClassName, String methodName, String methodDescriptor) { + String parentClassName, String methodName, String methodDescriptor) { try { return getMcpMethodData() - .get(parentClassName) - .get(methodName + methodDescriptor) - .getObfName(); + .get(parentClassName) + .get(methodName + methodDescriptor) + .getObfName(); } catch (Exception e) { LOGGER.warn( - "Could not lookup obf name for method '" - + parentClassName - + "::" - + methodName - + methodDescriptor - + "'"); + "Could not lookup obf name for method '" + + parentClassName + + "::" + + methodName + + methodDescriptor + + "'"); return null; } } - + @Nullable @Override public String getSrgFieldName(String parentClassName, String fieldName) { @@ -163,11 +175,11 @@ public String getSrgFieldName(String parentClassName, String fieldName) { return getMcpFieldData().get(parentClassName).get(fieldName).getSrgName(); } catch (Exception e) { LOGGER.warn( - "Could not lookup srg name for field '" + parentClassName + "." + fieldName + "'"); + "Could not lookup srg name for field '" + parentClassName + "." + fieldName + "'"); return null; } } - + @Nullable @Override public String getObfFieldName(String parentClassName, String fieldName) { @@ -175,24 +187,24 @@ public String getObfFieldName(String parentClassName, String fieldName) { return getMcpFieldData().get(parentClassName).get(fieldName).getObfName(); } catch (Exception e) { LOGGER.warn( - "Could not lookup obf name for field '" + parentClassName + "." + fieldName + "'"); + "Could not lookup obf name for field '" + parentClassName + "." + fieldName + "'"); return null; } } - + public Type translateMethodType(Type methodType) { Type[] translated = - translateTypes( - mcClasses, - Lists.asList(methodType.getReturnType(), methodType.getArgumentTypes()) - .toArray(new Type[] {})); + translateTypes( + mcClasses, + Lists.asList(methodType.getReturnType(), methodType.getArgumentTypes()) + .toArray(new Type[]{})); return Type.getMethodType(translated[0], Arrays.copyOfRange(translated, 1, translated.length)); } - + public Type translateFieldType(Type fieldType) { return translateTypes(mcClasses, fieldType)[0]; } - + private Type[] translateTypes(Map mapIn, Type... types) { int index = 0; Type[] translated = new Type[types.length]; @@ -200,7 +212,9 @@ private Type[] translateTypes(Map mapIn, Type... types) { switch (arg.getSort()) { case Type.ARRAY: // ignore primitive arrays - if (arg.getElementType().getSort() != Type.OBJECT) break; + if (arg.getElementType().getSort() != Type.OBJECT) { + break; + } case Type.OBJECT: String desc = arg.getDescriptor(); String heading = desc.substring(0, desc.indexOf('L') + 1); @@ -215,99 +229,102 @@ private Type[] translateTypes(Map mapIn, Type... types) { } return translated; } - + private Map> getConvertedMap( - Map> mapIn, Function getNameFunction) { + Map> mapIn, Function getNameFunction) { Map> mapOut = Maps.newHashMap(); mapIn - .entrySet() - .forEach( - entry -> { - String realName = getMcpClassName(entry.getKey()); - if (!Strings.isNullOrEmpty(realName)) { - Map subMap = Maps.newHashMap(); - entry - .getValue() - .entrySet() - .forEach( - subEntry -> { - String key = getNameFunction.apply(subEntry.getKey()); - String value = getNameFunction.apply(subEntry.getValue()); - subMap.put(isObfuscated() ? value : key, isObfuscated() ? key : value); - }); - mapOut.put(realName, Collections.unmodifiableMap(subMap)); - } - }); + .entrySet() + .forEach( + entry -> { + String realName = getMcpClassName(entry.getKey()); + if (!Strings.isNullOrEmpty(realName)) { + Map subMap = Maps.newHashMap(); + entry + .getValue() + .entrySet() + .forEach( + subEntry -> { + String key = getNameFunction.apply(subEntry.getKey()); + String value = getNameFunction.apply(subEntry.getValue()); + subMap.put(isObfuscated() ? value : key, isObfuscated() ? key : value); + }); + mapOut.put(realName, Collections.unmodifiableMap(subMap)); + } + }); return mapOut; } - + private static Map> buildMcpTypeData( - final CsvFile csvFile, - final Map> mcpMappings, - final Map> runtimeMappings, - NamingFunction mcpNameFunction) { + final CsvFile csvFile, + final Map> mcpMappings, + final Map> runtimeMappings, + NamingFunction mcpNameFunction) { final Map> output = Maps.newHashMap(); // parse over all classes mcpMappings - .entrySet() - .forEach( - parentClassEntry -> { - final Map typeDataMap = Maps.newHashMap(); - // lookup the class in the runtime type map - final Map runtimeClass = - runtimeMappings.get(parentClassEntry.getKey().getFullyQualifiedSrgName()); - if (!Objects.isNull(runtimeClass)) { - // parse over all the methods inside the class - parentClassEntry - .getValue() - .forEach( - data -> { - String srgName = data.getSrgName(); - String obfName = runtimeClass.get(srgName); - // get the mcp name (if it exists) - CsvData csvData = csvFile.getCsvDataForKey(srgName); - String mcpName = !Objects.isNull(csvData) ? csvData.getMcpName() : null; - McpTypeData typeData = new McpTypeData(mcpName, srgName, obfName); - // add srg to type data conversion - typeDataMap.put(srgName, typeData); - // add mcp name to type data (if the mcp name exists) - if (!Strings.isNullOrEmpty(mcpName)) - typeDataMap.put(mcpNameFunction.apply(csvData, data), typeData); - }); - } - // class = {mcpTypeName=typeData} - output.put( - parentClassEntry.getKey().getFullyQualifiedSrgName(), - Collections.unmodifiableMap(typeDataMap)); - }); + .entrySet() + .forEach( + parentClassEntry -> { + final Map typeDataMap = Maps.newHashMap(); + // lookup the class in the runtime type map + final Map runtimeClass = + runtimeMappings.get(parentClassEntry.getKey().getFullyQualifiedSrgName()); + if (!Objects.isNull(runtimeClass)) { + // parse over all the methods inside the class + parentClassEntry + .getValue() + .forEach( + data -> { + String srgName = data.getSrgName(); + String obfName = runtimeClass.get(srgName); + // get the mcp name (if it exists) + CsvData csvData = csvFile.getCsvDataForKey(srgName); + String mcpName = !Objects.isNull(csvData) ? csvData.getMcpName() : null; + McpTypeData typeData = new McpTypeData(mcpName, srgName, obfName); + // add srg to type data conversion + typeDataMap.put(srgName, typeData); + // add mcp name to type data (if the mcp name exists) + if (!Strings.isNullOrEmpty(mcpName)) { + typeDataMap.put(mcpNameFunction.apply(csvData, data), typeData); + } + }); + } + // class = {mcpTypeName=typeData} + output.put( + parentClassEntry.getKey().getFullyQualifiedSrgName(), + Collections.unmodifiableMap(typeDataMap)); + }); return Collections.unmodifiableMap(output); } - + public static class McpTypeData { + private final String mcpName; private final String srgName; private final String obfName; - + public McpTypeData(String mcpName, String srgName, String obfName) { this.mcpName = mcpName; this.srgName = srgName; this.obfName = obfName; } - + public String getMcpName() { return mcpName; } - + public String getSrgName() { return srgName; } - + public String getObfName() { return obfName; } } - + private interface NamingFunction { + String apply(CsvData csvData, E data); } } diff --git a/src/main/java/com/matt/forgehax/asm/utils/transforming/ClassPatchLoader.java b/src/main/java/com/matt/forgehax/asm/utils/transforming/ClassPatchLoader.java deleted file mode 100644 index 6593e0a15..000000000 --- a/src/main/java/com/matt/forgehax/asm/utils/transforming/ClassPatchLoader.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.matt.forgehax.asm.utils.transforming; - -import com.matt.forgehax.util.classloader.AbstractClassLoader; -import java.lang.annotation.Annotation; -import javax.annotation.Nullable; - -/** Created on 2/13/2018 by fr1kin */ -public class ClassPatchLoader extends AbstractClassLoader { - private static final ClassPatchLoader INSTANCE = new ClassPatchLoader(); - - public static ClassPatchLoader getInstance() { - return INSTANCE; - } - - // - // - // - - @Nullable - @Override - public Class getInheritedClass() { - return ClassTransformer.class; - } - - @Nullable - @Override - public Class getAnnotationClass() { - return RegisterClassPatch.class; - } -} diff --git a/src/main/java/com/matt/forgehax/asm/utils/transforming/ClassTransformer.java b/src/main/java/com/matt/forgehax/asm/utils/transforming/ClassTransformer.java index 52fc95dec..1ea180b1f 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/transforming/ClassTransformer.java +++ b/src/main/java/com/matt/forgehax/asm/utils/transforming/ClassTransformer.java @@ -10,7 +10,6 @@ import com.matt.forgehax.asm.utils.asmtype.ASMClass; import com.matt.forgehax.asm.utils.environment.RuntimeState; import com.matt.forgehax.asm.utils.environment.State; -import com.matt.forgehax.mcversion.MCVersionChecker; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.List; @@ -20,17 +19,17 @@ import org.objectweb.asm.tree.MethodNode; public abstract class ClassTransformer - implements ASMCommon, TypesMc, Opcodes, ASMHelper.MagicOpcodes { + implements ASMCommon, TypesMc, Opcodes, ASMHelper.MagicOpcodes { + private final ASMClass transformingClass; private final List methodTransformers = Lists.newArrayList(); - + public ClassTransformer(ASMClass clazz) { this.transformingClass = clazz; for (Class c : getClass().getDeclaredClasses()) { try { if (c.isAnnotationPresent(RegisterMethodTransformer.class) - && MethodTransformer.class.isAssignableFrom(c) - && MCVersionChecker.checkVersion(c)) { + && MethodTransformer.class.isAssignableFrom(c)) { Constructor constructor; try { constructor = c.getDeclaredConstructor(getClass()); @@ -50,7 +49,7 @@ public ClassTransformer(ASMClass clazz) { } } } - + /** * This method will return the class obfuscation state. * @@ -59,62 +58,65 @@ public ClassTransformer(ASMClass clazz) { public State getClassObfuscationState() { return RuntimeState.getDefaultState(); } - + public void registerMethodPatch(MethodTransformer transformer) { methodTransformers.add(transformer); } - + public ASMClass getTransformingClass() { return transformingClass; } - + public String getTransformingClassName() { return transformingClass.getName(); } - + public final void transform(final ClassNode node) { RuntimeState.setState(getClassObfuscationState()); try { - for (final MethodNode methodNode : node.methods) + for (final MethodNode methodNode : node.methods) { methodTransformers - .stream() - .filter( - t -> - Objects.equals(t.getMethod().getRuntimeName(), methodNode.name) - && Objects.equals(t.getMethod().getRuntimeDescriptor(), methodNode.desc)) - .forEach( - t -> - t.getTasks() - .forEach( - task -> { - try { - task.getMethod().invoke(t, methodNode); - // if we have gotten this far the transformation should have been - // successful - StringBuilder builder = new StringBuilder(); - builder.append("Successfully transformed the task \""); - builder.append(task.getDescription()); - builder.append("\" for "); - builder.append(getTransformingClassName()); - builder.append("::"); - builder.append(t.getMethod().getName()); - LOGGER.info(builder.toString()); - } catch (Throwable e) { - if (e instanceof InvocationTargetException) e = e.getCause(); - StringBuilder builder = new StringBuilder(); - builder.append(e.getClass().getSimpleName()); // exception name - builder.append(" thrown from "); - builder.append(getTransformingClassName()); - builder.append("::"); - builder.append(t.getMethod().getName()); - builder.append(" for the task with the description \""); - builder.append(task.getDescription()); - builder.append("\": "); - builder.append(e.getMessage()); - LOGGER.error(builder.toString()); - printStackTrace(e); - } - })); + .stream() + .filter( + t -> + Objects.equals(t.getMethod().getRuntimeName(), methodNode.name) + && Objects.equals(t.getMethod().getRuntimeDescriptor(), methodNode.desc)) + .forEach( + t -> + t.getTasks() + .forEach( + task -> { + try { + task.getMethod().invoke(t, methodNode); + // if we have gotten this far the transformation should have been + // successful + StringBuilder builder = new StringBuilder(); + builder.append("Successfully transformed the task \""); + builder.append(task.getDescription()); + builder.append("\" for "); + builder.append(getTransformingClassName()); + builder.append("::"); + builder.append(t.getMethod().getName()); + LOGGER.info(builder.toString()); + } catch (Throwable e) { + if (e instanceof InvocationTargetException) { + e = e.getCause(); + } + StringBuilder builder = new StringBuilder(); + builder.append(e.getClass().getSimpleName()); // exception name + builder.append(" thrown from "); + builder.append(getTransformingClassName()); + builder.append("::"); + builder.append(t.getMethod().getName()); + builder.append(" for the task with the description \""); + builder.append(task.getDescription()); + builder.append("\": "); + builder.append(e.getMessage()); + LOGGER.error(builder.toString()); + printStackTrace(e); + } + })); + } } finally { RuntimeState.releaseState(); } diff --git a/src/main/java/com/matt/forgehax/asm/utils/transforming/Inject.java b/src/main/java/com/matt/forgehax/asm/utils/transforming/Inject.java index 6aeaf2a83..c71016a6f 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/transforming/Inject.java +++ b/src/main/java/com/matt/forgehax/asm/utils/transforming/Inject.java @@ -5,11 +5,14 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** Created on 5/2/2017 by fr1kin */ +/** + * Created on 5/2/2017 by fr1kin + */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Inject { + String description() default "empty"; - + InjectPriority priority() default InjectPriority.DEFAULT; } diff --git a/src/main/java/com/matt/forgehax/asm/utils/transforming/InjectPriority.java b/src/main/java/com/matt/forgehax/asm/utils/transforming/InjectPriority.java index 170b72c1e..07ad18d96 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/transforming/InjectPriority.java +++ b/src/main/java/com/matt/forgehax/asm/utils/transforming/InjectPriority.java @@ -1,6 +1,8 @@ package com.matt.forgehax.asm.utils.transforming; -/** Created on 5/4/2017 by fr1kin */ +/** + * Created on 5/4/2017 by fr1kin + */ public enum InjectPriority { HIGHEST, HIGH, diff --git a/src/main/java/com/matt/forgehax/asm/utils/transforming/MethodTransformer.java b/src/main/java/com/matt/forgehax/asm/utils/transforming/MethodTransformer.java index 3a88657a6..129ef5de8 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/transforming/MethodTransformer.java +++ b/src/main/java/com/matt/forgehax/asm/utils/transforming/MethodTransformer.java @@ -4,29 +4,33 @@ import com.matt.forgehax.asm.ASMCommon; import com.matt.forgehax.asm.utils.ASMStackLogger; import com.matt.forgehax.asm.utils.asmtype.ASMMethod; -import com.matt.forgehax.mcversion.MCVersionChecker; import java.lang.reflect.Method; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Objects; import joptsimple.internal.Strings; import org.objectweb.asm.tree.MethodNode; -/** Created on 5/2/2017 by fr1kin */ +/** + * Created on 5/2/2017 by fr1kin + */ public abstract class MethodTransformer implements ASMCommon { + private final Collection tasks = Queues.newPriorityQueue(); - + public MethodTransformer() { for (Method m : getClass().getDeclaredMethods()) { try { m.setAccessible(true); if (m.isAnnotationPresent(Inject.class) - && m.getParameterCount() > 0 - && MethodNode.class.equals(m.getParameterTypes()[0]) - && MCVersionChecker.checkVersion(m)) { + && m.getParameterCount() > 0 + && MethodNode.class.equals(m.getParameterTypes()[0])) { tasks.add( - new TaskElement( - m, - m.getAnnotation(Inject.class).description(), - m.getAnnotation(Inject.class).priority())); + new TaskElement( + m, + m.getAnnotation(Inject.class).description(), + m.getAnnotation(Inject.class).priority())); } } catch (Exception e) { LOGGER.error(e.getMessage()); @@ -34,27 +38,28 @@ public MethodTransformer() { } } } - + public final Collection getTasks() { return Collections.unmodifiableCollection(tasks); } - + public abstract ASMMethod getMethod(); - + @Override public boolean equals(Object obj) { return obj instanceof MethodTransformer - && Objects.equals(getMethod(), ((MethodTransformer) obj).getMethod()); + && Objects.equals(getMethod(), ((MethodTransformer) obj).getMethod()); } - + @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("MethodTransformer ["); builder.append(getMethod() != null ? getMethod().toString() : "null"); builder.append("] "); - if (tasks.isEmpty()) builder.append("No transform tasks"); - else { + if (tasks.isEmpty()) { + builder.append("No transform tasks"); + } else { builder.append("Found "); builder.append(tasks.size()); builder.append(" transform tasks: "); @@ -65,40 +70,43 @@ public String toString() { if (!Strings.isNullOrEmpty(desc)) { builder.append(desc); } - if (it.hasNext()) builder.append(", "); + if (it.hasNext()) { + builder.append(", "); + } } } return builder.toString(); } - + public static class TaskElement implements Comparable { + private final Method method; private final String description; private final InjectPriority priority; - + public TaskElement(Method method, String description, InjectPriority priority) { this.method = method; this.description = description; this.priority = priority; } - + public Method getMethod() { return method; } - + public String getDescription() { return description; } - + public InjectPriority getPriority() { return priority; } - + @Override public int compareTo(TaskElement o) { return priority.compareTo(o.priority); } - + @Override public boolean equals(Object obj) { return obj instanceof TaskElement && method.equals(((TaskElement) obj).method); diff --git a/src/main/java/com/matt/forgehax/asm/utils/transforming/RegisterClassPatch.java b/src/main/java/com/matt/forgehax/asm/utils/transforming/RegisterClassPatch.java index 23158fa2f..a89e9245f 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/transforming/RegisterClassPatch.java +++ b/src/main/java/com/matt/forgehax/asm/utils/transforming/RegisterClassPatch.java @@ -1,4 +1,8 @@ package com.matt.forgehax.asm.utils.transforming; -/** Created on 2/13/2018 by fr1kin */ -public @interface RegisterClassPatch {} +/** + * Created on 2/13/2018 by fr1kin + */ +public @interface RegisterClassPatch { + +} diff --git a/src/main/java/com/matt/forgehax/asm/utils/transforming/RegisterMethodTransformer.java b/src/main/java/com/matt/forgehax/asm/utils/transforming/RegisterMethodTransformer.java index f0ec1085b..af570d526 100644 --- a/src/main/java/com/matt/forgehax/asm/utils/transforming/RegisterMethodTransformer.java +++ b/src/main/java/com/matt/forgehax/asm/utils/transforming/RegisterMethodTransformer.java @@ -5,9 +5,12 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** Created on 5/2/2017 by fr1kin */ +/** + * Created on 5/2/2017 by fr1kin + */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface RegisterMethodTransformer { + String description() default "empty"; } diff --git a/src/main/java/com/matt/forgehax/events/ChatMessageEvent.java b/src/main/java/com/matt/forgehax/events/ChatMessageEvent.java index aaf95a67f..4907125f4 100644 --- a/src/main/java/com/matt/forgehax/events/ChatMessageEvent.java +++ b/src/main/java/com/matt/forgehax/events/ChatMessageEvent.java @@ -5,43 +5,46 @@ import javax.annotation.Nullable; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 7/18/2017 by fr1kin */ +/** + * Created on 7/18/2017 by fr1kin + */ public class ChatMessageEvent extends Event { + public static ChatMessageEvent newPublicChat(PlayerInfo playerInfo, String message) { return new ChatMessageEvent(playerInfo, message, null); } - + public static ChatMessageEvent newPrivateChat( - PlayerInfo sender, PlayerInfo receiver, String message) { + PlayerInfo sender, PlayerInfo receiver, String message) { return new ChatMessageEvent(sender, message, receiver); } - + private final PlayerInfo sender; private final String message; - + // for private messages only // null when is a public message private final PlayerInfo receiver; - + public ChatMessageEvent(PlayerInfo sender, String message, PlayerInfo receiver) { this.sender = sender; this.message = Strings.nullToEmpty(message); this.receiver = receiver; } - + public PlayerInfo getSender() { return sender; } - + public String getMessage() { return message; } - + @Nullable public PlayerInfo getReceiver() { return receiver; } - + public boolean isWhispering() { return receiver != null; } diff --git a/src/main/java/com/matt/forgehax/events/EntityAddedEvent.java b/src/main/java/com/matt/forgehax/events/EntityAddedEvent.java index 2fbb8551a..cd92c3b6b 100644 --- a/src/main/java/com/matt/forgehax/events/EntityAddedEvent.java +++ b/src/main/java/com/matt/forgehax/events/EntityAddedEvent.java @@ -4,6 +4,7 @@ import net.minecraftforge.event.entity.EntityEvent; public class EntityAddedEvent extends EntityEvent { + public EntityAddedEvent(Entity entity) { super(entity); } diff --git a/src/main/java/com/matt/forgehax/events/EntityRemovedEvent.java b/src/main/java/com/matt/forgehax/events/EntityRemovedEvent.java index 8cfdf86c6..dc0f5b966 100644 --- a/src/main/java/com/matt/forgehax/events/EntityRemovedEvent.java +++ b/src/main/java/com/matt/forgehax/events/EntityRemovedEvent.java @@ -4,6 +4,7 @@ import net.minecraftforge.event.entity.EntityEvent; public class EntityRemovedEvent extends EntityEvent { + public EntityRemovedEvent(Entity entity) { super(entity); } diff --git a/src/main/java/com/matt/forgehax/events/ForgeHaxEvent.java b/src/main/java/com/matt/forgehax/events/ForgeHaxEvent.java index e6bbe3e81..820666152 100644 --- a/src/main/java/com/matt/forgehax/events/ForgeHaxEvent.java +++ b/src/main/java/com/matt/forgehax/events/ForgeHaxEvent.java @@ -3,6 +3,7 @@ import net.minecraftforge.fml.common.eventhandler.Event; public class ForgeHaxEvent extends Event { + public enum Type { /** * For when eating food @@ -10,16 +11,16 @@ public enum Type { EATING_SELECT_FOOD, EATING_START, EATING_STOP, - + ; } - + private final Type type; - + public ForgeHaxEvent(Type type) { this.type = type; } - + public Type getType() { return type; } diff --git a/src/main/java/com/matt/forgehax/events/LocalPlayerUpdateEvent.java b/src/main/java/com/matt/forgehax/events/LocalPlayerUpdateEvent.java index a99b79547..2112147c1 100644 --- a/src/main/java/com/matt/forgehax/events/LocalPlayerUpdateEvent.java +++ b/src/main/java/com/matt/forgehax/events/LocalPlayerUpdateEvent.java @@ -4,6 +4,7 @@ import net.minecraftforge.event.entity.living.LivingEvent; public class LocalPlayerUpdateEvent extends LivingEvent { + public LocalPlayerUpdateEvent(EntityLivingBase e) { super(e); } diff --git a/src/main/java/com/matt/forgehax/events/PlayerConnectEvent.java b/src/main/java/com/matt/forgehax/events/PlayerConnectEvent.java index 5826989e8..18cb44405 100644 --- a/src/main/java/com/matt/forgehax/events/PlayerConnectEvent.java +++ b/src/main/java/com/matt/forgehax/events/PlayerConnectEvent.java @@ -5,32 +5,37 @@ import java.util.Objects; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 7/18/2017 by fr1kin */ +/** + * Created on 7/18/2017 by fr1kin + */ public class PlayerConnectEvent extends Event { + private final PlayerInfo playerInfo; private final GameProfile profile; - + public PlayerConnectEvent(PlayerInfo playerInfo, GameProfile profile) { Objects.requireNonNull(profile); this.playerInfo = playerInfo; this.profile = profile; } - + public PlayerInfo getPlayerInfo() { return playerInfo; } - + public GameProfile getProfile() { return profile; } - + public static class Join extends PlayerConnectEvent { + public Join(PlayerInfo playerInfo, GameProfile profile) { super(playerInfo, profile); } } - + public static class Leave extends PlayerConnectEvent { + public Leave(PlayerInfo playerInfo, GameProfile profile) { super(playerInfo, profile); } diff --git a/src/main/java/com/matt/forgehax/events/Render2DEvent.java b/src/main/java/com/matt/forgehax/events/Render2DEvent.java index d2b90a4fe..185846860 100644 --- a/src/main/java/com/matt/forgehax/events/Render2DEvent.java +++ b/src/main/java/com/matt/forgehax/events/Render2DEvent.java @@ -6,28 +6,31 @@ import net.minecraft.client.gui.ScaledResolution; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 9/2/2017 by fr1kin */ +/** + * Created on 9/2/2017 by fr1kin + */ public class Render2DEvent extends Event { + private final ScaledResolution resolution = new ScaledResolution(MC); private final SurfaceBuilder surfaceBuilder = new SurfaceBuilder(); private final float partialTicks; - + public Render2DEvent(float partialTicks) { this.partialTicks = partialTicks; } - + public float getPartialTicks() { return partialTicks; } - + public double getScreenWidth() { return resolution.getScaledWidth_double(); } - + public double getScreenHeight() { return resolution.getScaledHeight_double(); } - + public SurfaceBuilder getSurfaceBuilder() { return surfaceBuilder; } diff --git a/src/main/java/com/matt/forgehax/events/RenderEvent.java b/src/main/java/com/matt/forgehax/events/RenderEvent.java index a19047912..878856817 100644 --- a/src/main/java/com/matt/forgehax/events/RenderEvent.java +++ b/src/main/java/com/matt/forgehax/events/RenderEvent.java @@ -1,42 +1,45 @@ package com.matt.forgehax.events; -import com.github.lunatrius.core.client.renderer.unique.GeometryTessellator; +import com.matt.forgehax.util.tesselation.GeometryTessellator; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.Vec3d; import net.minecraftforge.fml.common.eventhandler.Event; -/** Created on 5/5/2017 by fr1kin */ +/** + * Created on 5/5/2017 by fr1kin + */ public class RenderEvent extends Event { + private final GeometryTessellator tessellator; private final Vec3d renderPos; private final double partialTicks; - + public RenderEvent(GeometryTessellator tessellator, Vec3d renderPos, double partialTicks) { this.tessellator = tessellator; this.renderPos = renderPos; this.partialTicks = partialTicks; } - + public GeometryTessellator getTessellator() { return tessellator; } - + public BufferBuilder getBuffer() { return tessellator.getBuffer(); } - + public Vec3d getRenderPos() { return renderPos; } - + public void setTranslation(Vec3d translation) { getBuffer().setTranslation(-translation.x, -translation.y, -translation.z); } - + public void resetTranslation() { setTranslation(renderPos); } - + public double getPartialTicks() { return partialTicks; } diff --git a/src/main/java/com/matt/forgehax/events/WorldChangeEvent.java b/src/main/java/com/matt/forgehax/events/WorldChangeEvent.java index 62cc54917..4efd8d7f8 100644 --- a/src/main/java/com/matt/forgehax/events/WorldChangeEvent.java +++ b/src/main/java/com/matt/forgehax/events/WorldChangeEvent.java @@ -3,12 +3,15 @@ import net.minecraft.world.World; import net.minecraftforge.event.world.WorldEvent; -/** Created on 5/29/2017 by fr1kin */ +/** + * Created on 5/29/2017 by fr1kin + */ public class WorldChangeEvent extends WorldEvent { + public WorldChangeEvent(World world) { super(world); } - + public boolean isWorldNull() { return getWorld() == null; } diff --git a/src/main/java/com/matt/forgehax/events/listeners/WorldListener.java b/src/main/java/com/matt/forgehax/events/listeners/WorldListener.java index 307df54ee..7ead187c8 100644 --- a/src/main/java/com/matt/forgehax/events/listeners/WorldListener.java +++ b/src/main/java/com/matt/forgehax/events/listeners/WorldListener.java @@ -13,54 +13,62 @@ import net.minecraftforge.common.MinecraftForge; public class WorldListener implements IWorldEventListener { + @Override public void notifyBlockUpdate( - World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) {} + World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) { + } @Override - public void notifyLightSet(BlockPos pos) {} + public void notifyLightSet(BlockPos pos) { + } @Override - public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {} + public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) { + } @Override public void playSoundToAllNearExcept( - EntityPlayer player, - SoundEvent soundIn, - SoundCategory category, - double x, - double y, - double z, - float volume, - float pitch) {} + EntityPlayer player, + SoundEvent soundIn, + SoundCategory category, + double x, + double y, + double z, + float volume, + float pitch) { + } @Override - public void playRecord(SoundEvent soundIn, BlockPos pos) {} + public void playRecord(SoundEvent soundIn, BlockPos pos) { + } @Override public void spawnParticle( - int particleID, - boolean ignoreRange, - double xCoord, - double yCoord, - double zCoord, - double xSpeed, - double ySpeed, - double zSpeed, - int... parameters) {} + int particleID, + boolean ignoreRange, + double xCoord, + double yCoord, + double zCoord, + double xSpeed, + double ySpeed, + double zSpeed, + int... parameters) { + } @Override public void spawnParticle( - int p_190570_1_, - boolean p_190570_2_, - boolean p_190570_3_, - double p_190570_4_, - double p_190570_6_, - double p_190570_8_, - double p_190570_10_, - double p_190570_12_, - double p_190570_14_, - int... p_190570_16_) {} + int p_190570_1_, + boolean p_190570_2_, + boolean p_190570_3_, + double p_190570_4_, + double p_190570_6_, + double p_190570_8_, + double p_190570_10_, + double p_190570_12_, + double p_190570_14_, + int... p_190570_16_) { + } @Override public void onEntityAdded(Entity entityIn) { @@ -73,11 +81,14 @@ public void onEntityRemoved(Entity entityIn) { } @Override - public void broadcastSound(int soundID, BlockPos pos, int data) {} + public void broadcastSound(int soundID, BlockPos pos, int data) { + } @Override - public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) {} + public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) { + } @Override - public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {} + public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) { + } } diff --git a/src/main/java/com/matt/forgehax/gui/ClickGui.java b/src/main/java/com/matt/forgehax/gui/ClickGui.java index 9100672d1..9c77fef95 100644 --- a/src/main/java/com/matt/forgehax/gui/ClickGui.java +++ b/src/main/java/com/matt/forgehax/gui/ClickGui.java @@ -12,7 +12,9 @@ import net.minecraft.client.gui.ScaledResolution; import org.lwjgl.input.Mouse; -/** Created by Babbaj on 9/5/2017. */ +/** + * Created by Babbaj on 9/5/2017. + */ public class ClickGui extends GuiScreen implements Globals { private static ClickGui INSTANCE; @@ -43,9 +45,9 @@ private ClickGui() { // TODO: improve this a bit maybe for (int i = 0; i < windowList.size(); i++) { int x = - (i + 1) * scaledRes.getScaledWidth() / (windowList.size() + 1) - - windowList.get(i).width / 2 - - 10; + (i + 1) * scaledRes.getScaledWidth() / (windowList.size() + 1) + - windowList.get(i).width / 2 + - 10; int y = scaledRes.getScaledHeight() / 15; windowList.get(i).setPosition(x, y); } @@ -62,14 +64,16 @@ public boolean doesGuiPauseGame() { public void moveWindowToTop(GuiWindow window) { if (windowList.remove(window)) // if it wasnt already in the list dont add it - windowList.add(window); + { + windowList.add(window); + } } public boolean isMouseInWindow(int mouseX, int mouseY, GuiWindow window) { return mouseX > window.posX - && mouseX < window.bottomX - && mouseY > window.headerY - && mouseY < window.bottomY; + && mouseX < window.bottomX + && mouseY > window.headerY + && mouseY < window.bottomY; } public void drawScreen(int mouseX, int mouseY, float partialTicks) { @@ -118,7 +122,7 @@ public void handleMouseInput() throws IOException { int scale = scaledRes.getScaleFactor(); for (GuiWindow window : Lists.reverse(windowList)) { if (isMouseInWindow( - Mouse.getEventX() / scale, (MC.displayHeight - Mouse.getEventY()) / scale, window)) { + Mouse.getEventX() / scale, (MC.displayHeight - Mouse.getEventY()) / scale, window)) { window.handleMouseInput(); break; } diff --git a/src/main/java/com/matt/forgehax/gui/elements/GuiButton.java b/src/main/java/com/matt/forgehax/gui/elements/GuiButton.java index 4f5c1e3cb..76d7798bf 100644 --- a/src/main/java/com/matt/forgehax/gui/elements/GuiButton.java +++ b/src/main/java/com/matt/forgehax/gui/elements/GuiButton.java @@ -1,15 +1,17 @@ package com.matt.forgehax.gui.elements; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Color; import com.matt.forgehax.util.mod.BaseMod; -/** Created by Babbaj on 9/5/2017. */ +/** + * Created by Babbaj on 9/5/2017. + */ public class GuiButton { private final BaseMod mod; - public static final int COLOR_ENABLED = Utils.toRGBA(65, 65, 65, 200); - public static final int COLOR_DISABLED = Utils.toRGBA(100, 100, 100, 150); + private static final int COLOR_ENABLED = Color.of(65, 65, 65, 200).toBuffer(); + private static final int COLOR_DISABLED = Color.of(100, 100, 100, 150).toBuffer(); public int width; public static final int height = 15; @@ -30,8 +32,11 @@ public boolean isModEnabled() { } public void toggleMod() { - if (!mod.isEnabled()) mod.enable(); - else mod.disable(); + if (!mod.isEnabled()) { + mod.enable(); + } else { + mod.disable(); + } } public String getName() { diff --git a/src/main/java/com/matt/forgehax/gui/elements/GuiElement.java b/src/main/java/com/matt/forgehax/gui/elements/GuiElement.java index d72dbb480..ddc5df74a 100644 --- a/src/main/java/com/matt/forgehax/gui/elements/GuiElement.java +++ b/src/main/java/com/matt/forgehax/gui/elements/GuiElement.java @@ -4,8 +4,11 @@ import com.matt.forgehax.util.command.Setting; import java.io.IOException; -/** Created by Babbaj on 9/6/2017. */ +/** + * Created by Babbaj on 9/6/2017. + */ public class GuiElement { + public GuiWindowSetting parentWindow; public int width, height; // width and height of the element @@ -18,12 +21,15 @@ public GuiElement(Setting settingIn, GuiWindowSetting parent) { this.parentWindow = parent; this.setting = settingIn; } - - public void mouseClicked(int x, int y, int state) {} - - public void mouseReleased(int x, int y, int state) {} - - public void keyTyped(char typedChar, int keyCode) throws IOException {} + + public void mouseClicked(int x, int y, int state) { + } + + public void mouseReleased(int x, int y, int state) { + } + + public void keyTyped(char typedChar, int keyCode) throws IOException { + } public void draw(int mouseX, int mouseY) { this.x = getPosX() + this.subX + 1; @@ -40,8 +46,8 @@ public int getPosY() { public boolean isMouseInElement(int mouseX, int mouseY) { return mouseX > this.x - && mouseX < this.x + width - && mouseY > this.y - && mouseY < this.y + height; + && mouseX < this.x + width + && mouseY > this.y + && mouseY < this.y + height; } } diff --git a/src/main/java/com/matt/forgehax/gui/elements/GuiEnum.java b/src/main/java/com/matt/forgehax/gui/elements/GuiEnum.java index 7ee3b88a8..4205118ab 100644 --- a/src/main/java/com/matt/forgehax/gui/elements/GuiEnum.java +++ b/src/main/java/com/matt/forgehax/gui/elements/GuiEnum.java @@ -1,6 +1,8 @@ package com.matt.forgehax.gui.elements; -/** Created by Babbaj on 9/6/2017. */ +/** + * Created by Babbaj on 9/6/2017. + */ /*public class GuiEnum extends GuiElement { // TODO: drop down thing diff --git a/src/main/java/com/matt/forgehax/gui/elements/GuiTextInput.java b/src/main/java/com/matt/forgehax/gui/elements/GuiTextInput.java index a21a780d2..0ec94c953 100644 --- a/src/main/java/com/matt/forgehax/gui/elements/GuiTextInput.java +++ b/src/main/java/com/matt/forgehax/gui/elements/GuiTextInput.java @@ -3,7 +3,7 @@ import static com.matt.forgehax.Globals.MC; import com.matt.forgehax.gui.windows.GuiWindowSetting; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.command.Setting; import com.matt.forgehax.util.draw.SurfaceHelper; import java.io.IOException; @@ -11,7 +11,9 @@ import net.minecraft.util.text.TextComponentString; import org.lwjgl.input.Keyboard; -/** Created by Babbaj on 9/15/2017. */ +/** + * Created by Babbaj on 9/15/2017. + */ public class GuiTextInput extends GuiElement { private final int blinkSpeed = 30; // how often to blink the thing @@ -70,21 +72,23 @@ public void keyTyped(char typedChar, int keyCode) throws IOException { public void draw(int mouseX, int mouseY) { super.draw(x, y); - SurfaceHelper.drawRect(x, y, width - 2, height, Utils.Colors.WHITE); - SurfaceHelper.drawOutlinedRect(x, y, width - 2, height, Utils.Colors.BLACK); + SurfaceHelper.drawRect(x, y, width - 2, height, Colors.WHITE.toBuffer()); + SurfaceHelper.drawOutlinedRect(x, y, width - 2, height, Colors.BLACK.toBuffer()); if (ticks % blinkSpeed * 2 > blinkSpeed && isActive) { int width = getBlinkWidth(); // SurfaceHelper.drawLine(x+width+1, y+2,x+width+1, y+height-2, Utils.Colors.BLACK); } - SurfaceHelper.drawText(getInputString(), x + 1, y + 2, Utils.Colors.BLACK); + SurfaceHelper.drawText(getInputString(), x + 1, y + 2, Colors.BLACK.toBuffer()); ticks++; } private int getBlinkWidth() { - if (input.length() > 0) + if (input.length() > 0) { return SurfaceHelper.getTextWidth(input.substring(0, selectedIndex + 1)); - else return 0; + } else { + return 0; + } } private String getInputString() { diff --git a/src/main/java/com/matt/forgehax/gui/elements/GuiToggle.java b/src/main/java/com/matt/forgehax/gui/elements/GuiToggle.java index 3cd778194..01124dbc8 100644 --- a/src/main/java/com/matt/forgehax/gui/elements/GuiToggle.java +++ b/src/main/java/com/matt/forgehax/gui/elements/GuiToggle.java @@ -1,6 +1,8 @@ package com.matt.forgehax.gui.elements; -/** Created by Babbaj on 9/5/2017. */ +/** + * Created by Babbaj on 9/5/2017. + */ /*public class GuiToggle extends GuiElement { public GuiToggle(Setting settingIn) { diff --git a/src/main/java/com/matt/forgehax/gui/windows/GuiWindow.java b/src/main/java/com/matt/forgehax/gui/windows/GuiWindow.java index 99eb7db74..58abc061f 100644 --- a/src/main/java/com/matt/forgehax/gui/windows/GuiWindow.java +++ b/src/main/java/com/matt/forgehax/gui/windows/GuiWindow.java @@ -1,35 +1,39 @@ package com.matt.forgehax.gui.windows; import static com.matt.forgehax.Globals.MC; +import static com.matt.forgehax.util.color.Colors.GRAY; +import static com.matt.forgehax.util.color.Colors.WHITE; import com.matt.forgehax.gui.ClickGui; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Color; import com.matt.forgehax.util.draw.SurfaceHelper; import java.io.IOException; import net.minecraft.client.gui.ScaledResolution; -/** Created by Babbaj on 9/5/2017. */ +/** + * Created by Babbaj on 9/5/2017. + */ public abstract class GuiWindow { public boolean isHidden; // whether or not not to show everything below the header - public String title; + private String title; public int posX, headerY, windowY; public int bottomX, bottomY; // coords of where the window is being dragged from - public int dragX, dragY; + private int dragX, dragY; private boolean dragging; final int maxHeight = - (int) - (ClickGui.scaledRes.getScaledHeight() - * 0.8); // a window can only take up 80% of the height of the window + (int) + (ClickGui.scaledRes.getScaledHeight() + * 0.8); // a window can only take up 80% of the height of the window public int width, height; // width of the window - public GuiWindow(String titleIn) { + GuiWindow(String titleIn) { this.title = titleIn; width = SurfaceHelper.getTextWidth(title) + 15; } @@ -39,17 +43,21 @@ public void setPosition(int x, int y) { this.headerY = y; } - public String getTitle() { + private String getTitle() { return title; } - public boolean isMouseInHeader(int mouseX, int mouseY) { + boolean isMouseInHeader(int mouseX, int mouseY) { return (mouseX > posX && mouseX < posX + width && mouseY > headerY && mouseY < headerY + 20); } - - /** 0 == Left Click 1 == Right Click 2 == Middle Click */ + + /** + * 0 == Left Click 1 == Right Click 2 == Middle Click + */ public void mouseClicked(int mouseX, int mouseY, int state) { - if (state != 0) return; + if (state != 0) { + return; + } if (isMouseInHeader(mouseX, mouseY)) { dragging = true; @@ -79,16 +87,17 @@ public void drawWindow(int mouseX, int mouseY) { drawHeader(); windowY = headerY + 21; SurfaceHelper.drawOutlinedRectShaded( - posX, windowY, width, height, Utils.toRGBA(130, 130, 130, 255), 80, 3); + posX, windowY, width, height, GRAY.toBuffer(), 80, 3); } - + public void drawTooltip(int mouseX, int mouseY) {} public void drawHeader() { // draw the title of the window SurfaceHelper.drawOutlinedRectShaded( - posX, headerY, width, 20, Utils.toRGBA(150, 150, 150, 255), 50, 5); + posX, headerY, width, 20, + Color.of(150, 150, 150, 255).toBuffer(), 50, 5); SurfaceHelper.drawTextShadowCentered( - getTitle(), posX + width / 2f, headerY + 10, Utils.toRGBA(255, 255, 255, 255)); + getTitle(), posX + width / 2f, headerY + 10, WHITE.toBuffer()); } } diff --git a/src/main/java/com/matt/forgehax/gui/windows/GuiWindowMod.java b/src/main/java/com/matt/forgehax/gui/windows/GuiWindowMod.java index 7f5fb9e95..13e7b188f 100644 --- a/src/main/java/com/matt/forgehax/gui/windows/GuiWindowMod.java +++ b/src/main/java/com/matt/forgehax/gui/windows/GuiWindowMod.java @@ -1,45 +1,45 @@ package com.matt.forgehax.gui.windows; +import static com.matt.forgehax.Globals.MC; +import static com.matt.forgehax.Helper.getModManager; + import com.matt.forgehax.gui.ClickGui; import com.matt.forgehax.gui.elements.GuiButton; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Color; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.draw.SurfaceHelper; import com.matt.forgehax.util.mod.BaseMod; import com.matt.forgehax.util.mod.Category; -import net.minecraft.util.math.MathHelper; -import org.lwjgl.input.Mouse; -import org.lwjgl.opengl.GL11; - import java.io.IOException; import java.util.ArrayList; import java.util.List; - -import static com.matt.forgehax.Globals.MC; -import static com.matt.forgehax.Helper.getModManager; +import net.minecraft.util.math.MathHelper; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; /** * Created by Babbaj on 9/5/2017. */ public class GuiWindowMod extends GuiWindow { - + public List buttonList = new ArrayList<>(); - + /** * The button list y coord needs to be offset to move them up or down the window 0 = natural state * anything above 0 means the button list has moved up and the user has scrolled down */ private int buttonListOffset; - + public Category category; - + // public int windowY; // Y value of the modlist - 20 pixels lower than the header Y - + public GuiWindowMod(Category categoryIn) { super(categoryIn.getPrettyName()); category = categoryIn; addModsToButtonList(); } - + private void addModsToButtonList() { int maxWidth = 0; int newHeight = 0; @@ -47,62 +47,71 @@ private void addModsToButtonList() { if (mod.getModCategory().equals(category) && !mod.isHidden()) { GuiButton moduleButton = new GuiButton(mod); buttonList.add(moduleButton); - + newHeight += GuiButton.height + 1; - + String name = moduleButton.getName(); int width = SurfaceHelper.getTextWidth(name); - if (width > maxWidth) maxWidth = width; + if (width > maxWidth) { + maxWidth = width; + } } } height = Math.min(maxHeight, newHeight + 3); width = maxWidth + 15; // set the width of window to the width of the longest mod name } - + private void drawModTooltip(BaseMod mod, int xScaled, int yScaled) { int scale = ClickGui.scaledRes.getScaleFactor(); - + String modName = mod.getModName(); String modDescription = mod.getModDescription(); int offset = 2; int tooltipX = xScaled / scale + offset; int tooltipY = yScaled / scale + offset; int padding = 2; - int tooltipWidth = Math.max(SurfaceHelper.getTextWidth(modName), SurfaceHelper.getTextWidth(modDescription)) / scale + padding * 2; + int tooltipWidth = + Math.max(SurfaceHelper.getTextWidth(modName), SurfaceHelper.getTextWidth(modDescription)) + / scale + padding * 2; int lineHeight = SurfaceHelper.getTextHeight() / scale; int lineSpacing = 2; int tooltipHeight = lineHeight * 2 + lineSpacing + padding * 2; - - if ((tooltipX + tooltipWidth) * scale > ClickGui.scaledRes.getScaledWidth()) + + if ((tooltipX + tooltipWidth) * scale > ClickGui.scaledRes.getScaledWidth()) { tooltipX -= tooltipWidth + offset * 2; - - if ((tooltipY + tooltipHeight) * scale > ClickGui.scaledRes.getScaledHeight()) + } + + if ((tooltipY + tooltipHeight) * scale > ClickGui.scaledRes.getScaledHeight()) { tooltipY -= tooltipHeight + offset * 2; - - SurfaceHelper.drawRect( - tooltipX * scale, tooltipY * scale + 1, tooltipWidth * scale, tooltipHeight * scale - 2, - Utils.toRGBA(50, 50, 50, 255) - ); - - SurfaceHelper.drawRect( - tooltipX * scale + 1, tooltipY * scale, tooltipWidth * scale - 2, tooltipHeight * scale, - Utils.toRGBA(50, 50, 50, 255) - ); - - SurfaceHelper.drawTextShadow(modName, (tooltipX + padding) * scale, (tooltipY + padding) * scale, 0xFFFFFF); - SurfaceHelper.drawTextShadow(modDescription, (tooltipX + padding) * scale, (tooltipY + padding + lineHeight + lineSpacing) * scale, 0xAAAAAA); + } + + final int col = Color.of(50, 50, 50, 255).toBuffer(); + + SurfaceHelper.drawRect(tooltipX * scale, tooltipY * scale + 1, + tooltipWidth * scale, tooltipHeight * scale - 2, + col); + + SurfaceHelper.drawRect(tooltipX * scale + 1, tooltipY * scale, + tooltipWidth * scale - 2, tooltipHeight * scale, + col); + + SurfaceHelper + .drawTextShadow(modName, (tooltipX + padding) * scale, (tooltipY + padding) * scale, + 0xFFFFFF); + SurfaceHelper.drawTextShadow(modDescription, (tooltipX + padding) * scale, + (tooltipY + padding + lineHeight + lineSpacing) * scale, 0xAAAAAA); } - + public void drawWindow(int mouseX, int mouseY) { super.drawWindow(mouseX, mouseY); windowY = headerY + 22; - + SurfaceHelper.drawOutlinedRectShaded( - posX, windowY, width, height, Utils.toRGBA(130, 130, 130, 255), 80, 3); + posX, windowY, width, height, Colors.GRAY.toBuffer(), 80, 3); int buttonY = windowY - buttonListOffset + 2; - + int scale = ClickGui.scaledRes.getScaleFactor(); - + GL11.glPushMatrix(); int scissorY = MC.displayHeight - (scale * windowY + scale * height - 3); GL11.glScissor(scale * posX, scissorY, scale * width, scale * height - 8); @@ -110,60 +119,65 @@ public void drawWindow(int mouseX, int mouseY) { for (GuiButton button : buttonList) { SurfaceHelper.drawRect(posX + 2, buttonY, width - 4, GuiButton.height, button.getColor()); SurfaceHelper.drawTextShadowCentered( - button.getName(), - (posX + 2) + width / 2f, - buttonY + GuiButton.height / 2f, - Utils.toRGBA(255, 255, 255, 255)); + button.getName(), + (posX + 2) + width / 2f, + buttonY + GuiButton.height / 2f, + Colors.WHITE.toBuffer()); button.setCoords(posX + 2, buttonY); buttonY += GuiButton.height + 1; } GL11.glDisable(GL11.GL_SCISSOR_TEST); GL11.glPopMatrix(); - + // update variables bottomX = posX + width; // set the coords of the bottom right corner for mouse coord testing bottomY = windowY + height; } - + @Override public void drawTooltip(int mouseX, int mouseY) { int scale = ClickGui.scaledRes.getScaleFactor(); - + if (mouseX >= posX && mouseX < bottomX && - mouseY >= windowY + (5 / scale) && mouseY < bottomY - (5 / scale)) + mouseY >= windowY + (5 / scale) && mouseY < bottomY - (5 / scale)) { for (GuiButton button : buttonList) { if (mouseX > button.x && mouseX < (button.x + width) && - mouseY > button.y && mouseY < (button.y + GuiButton.height)) { + mouseY > button.y && mouseY < (button.y + GuiButton.height)) { drawModTooltip(button.getMod(), mouseX, mouseY); break; } } + } } - + public void mouseClicked(int x, int y, int state) { super.mouseClicked(x, y, state); for (GuiButton button : buttonList) { if (x > button.x - && x < (button.x + width) - && y > button.y - && y < (button.y + GuiButton.height) - && !isMouseInHeader(x, y)) { + && x < (button.x + width) + && y > button.y + && y < (button.y + GuiButton.height) + && !isMouseInHeader(x, y)) { button.toggleMod(); break; } } } - + public void handleMouseInput() throws IOException { int i = Mouse.getEventDWheel(); - + i = MathHelper.clamp(i, -1, 1); buttonListOffset -= i * 10; - - if (buttonListOffset < 0) buttonListOffset = 0; // dont scroll up if its already at the top - + + if (buttonListOffset < 0) { + buttonListOffset = 0; // dont scroll up if its already at the top + } + int lowestButtonY = (GuiButton.height + 1) * buttonList.size() + windowY; int lowestAllowedOffset = lowestButtonY - height - windowY + 3; - if (lowestButtonY - buttonListOffset < bottomY) buttonListOffset = lowestAllowedOffset; + if (lowestButtonY - buttonListOffset < bottomY) { + buttonListOffset = lowestAllowedOffset; + } } } diff --git a/src/main/java/com/matt/forgehax/gui/windows/GuiWindowSetting.java b/src/main/java/com/matt/forgehax/gui/windows/GuiWindowSetting.java index ce161773c..89ba89b7d 100644 --- a/src/main/java/com/matt/forgehax/gui/windows/GuiWindowSetting.java +++ b/src/main/java/com/matt/forgehax/gui/windows/GuiWindowSetting.java @@ -8,11 +8,13 @@ import java.util.ArrayList; import java.util.List; -/** Created by Babbaj on 9/5/2017. */ +/** + * Created by Babbaj on 9/5/2017. + */ public class GuiWindowSetting extends GuiWindow { public List inputList = - new ArrayList<>(); // list of toggles, sliders, text inputs, etc. + new ArrayList<>(); // list of toggles, sliders, text inputs, etc. private BaseMod mod; diff --git a/src/main/java/com/matt/forgehax/mcversion/IncompatibleMCVersionException.java b/src/main/java/com/matt/forgehax/mcversion/IncompatibleMCVersionException.java deleted file mode 100644 index 4ff0dab9b..000000000 --- a/src/main/java/com/matt/forgehax/mcversion/IncompatibleMCVersionException.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.matt.forgehax.mcversion; - -/** Created on 5/29/2017 by fr1kin */ -public class IncompatibleMCVersionException extends Exception { - public IncompatibleMCVersionException(String msg) { - super(msg); - } -} diff --git a/src/main/java/com/matt/forgehax/mcversion/MCVersionChecker.java b/src/main/java/com/matt/forgehax/mcversion/MCVersionChecker.java deleted file mode 100644 index 9cc96e00c..000000000 --- a/src/main/java/com/matt/forgehax/mcversion/MCVersionChecker.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.matt.forgehax.mcversion; - -import java.lang.reflect.AnnotatedElement; -import java.util.Objects; -import net.minecraftforge.common.ForgeVersion; - -/** Created on 5/29/2017 by fr1kin */ -public class MCVersionChecker { - public static String getMcVersion() { - return ForgeVersion.mcVersion; - } - - private static boolean checkVersion(MCVersions mcVersions) { - if (mcVersions != null) { - for (String version : mcVersions.value()) - if (Objects.equals(getMcVersion(), version)) return true; - return false; - } else - return true; // if it isn't marked with MCVersions just assume its compatible with the current - // version - } - - public static boolean checkVersion(AnnotatedElement element) { - return checkVersion(element.getAnnotation(MCVersions.class)); - } - - public static void requireValidVersion(AnnotatedElement element) - throws IncompatibleMCVersionException { - if (!checkVersion(element)) - throw new IncompatibleMCVersionException( - String.format("Incompatible with current Minecraft version %s", getMcVersion())); - } -} diff --git a/src/main/java/com/matt/forgehax/mcversion/MCVersions.java b/src/main/java/com/matt/forgehax/mcversion/MCVersions.java deleted file mode 100644 index f08189239..000000000 --- a/src/main/java/com/matt/forgehax/mcversion/MCVersions.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.matt.forgehax.mcversion; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Created on 5/29/2017 by fr1kin */ -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) -@Retention(RetentionPolicy.RUNTIME) -public @interface MCVersions { - String[] value() default {}; -} diff --git a/src/main/java/com/matt/forgehax/mods/ActiveModList.java b/src/main/java/com/matt/forgehax/mods/ActiveModList.java index 068033ad7..a433d6ac2 100644 --- a/src/main/java/com/matt/forgehax/mods/ActiveModList.java +++ b/src/main/java/com/matt/forgehax/mods/ActiveModList.java @@ -3,7 +3,7 @@ import static com.matt.forgehax.Helper.getModManager; import com.matt.forgehax.mods.services.TickRateService; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.command.Setting; import com.matt.forgehax.util.draw.SurfaceHelper; import com.matt.forgehax.util.mod.BaseMod; @@ -18,62 +18,63 @@ @RegisterMod public class ActiveModList extends ToggleMod { + private final Setting tps_meter = - getCommandStub() - .builders() - .newSettingBuilder() - .name("tps-meter") - .description("Shows the server tps") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("tps-meter") + .description("Shows the server tps") + .defaultTo(true) + .build(); + private final Setting debug = - getCommandStub() - .builders() - .newSettingBuilder() - .name("debug") - .description("Disables debug text on mods that have it") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("debug") + .description("Disables debug text on mods that have it") + .defaultTo(false) + .build(); + private final Setting factor = - getCommandStub() - .builders() - .newSettingBuilder() - .name("factor") - .description("Splitting up the tick rate data") - .defaultTo(25) - .min(1) - .max(100) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("factor") + .description("Splitting up the tick rate data") + .defaultTo(25) + .min(1) + .max(100) + .build(); + private final Setting showLag = - getCommandStub() - .builders() - .newSettingBuilder() - .name("showLag") - .description("Shows lag time since last tick") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("showLag") + .description("Shows lag time since last tick") + .defaultTo(true) + .build(); + private final Setting sortMode = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("sorting") - .description("Sorting mode") - .defaultTo(SortMode.ALPHABETICAL) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("sorting") + .description("Sorting mode") + .defaultTo(SortMode.ALPHABETICAL) + .build(); + public ActiveModList() { super(Category.RENDER, "ActiveMods", true, "Shows list of all active mods"); } - + @Override public boolean isHidden() { return true; } - + private String generateTickRateText() { StringBuilder builder = new StringBuilder("Tick-rate: "); TickRateService.TickRateData data = TickRateService.getTickData(); @@ -88,7 +89,9 @@ private String generateTickRateText() { builder.append(" ("); builder.append(data.getSampleSize()); builder.append(")"); - if (sections > 0) builder.append(", "); + if (sections > 0) { + builder.append(", "); + } } if (sections > 0) { for (int i = sections; i > 0; i--) { @@ -98,55 +101,58 @@ private String generateTickRateText() { builder.append(" ("); builder.append(at); builder.append(")"); - if ((i - 1) != 0) builder.append(", "); + if ((i - 1) != 0) { + builder.append(", "); + } } } } - + if (showLag.get()) { long lastTickMs = TickRateService.getInstance().getLastTimeDiff(); - + if (lastTickMs < 1000) { builder.append(", 0.0s"); } else { builder.append(String.format(", %01.1fs", ((float) (lastTickMs - 1000)) / 1000)); } } - + return builder.toString(); } - + @SubscribeEvent public void onRenderScreen(RenderGameOverlayEvent.Text event) { int posX = 1; final AtomicInteger posY = new AtomicInteger(1); if (tps_meter.get()) { - SurfaceHelper.drawTextShadow(generateTickRateText(), posX, posY.get(), Utils.Colors.WHITE); + SurfaceHelper + .drawTextShadow(generateTickRateText(), posX, posY.get(), Colors.WHITE.toBuffer()); posY.addAndGet(SurfaceHelper.getTextHeight() + 1); } - + if (MC.currentScreen instanceof GuiChat || MC.gameSettings.showDebugInfo) { long enabledMods = getModManager() - .getMods() - .stream() - .filter(BaseMod::isEnabled) - .filter(mod -> !mod.isHidden()) - .count(); + .getMods() + .stream() + .filter(BaseMod::isEnabled) + .filter(mod -> !mod.isHidden()) + .count(); SurfaceHelper.drawTextShadow(enabledMods + " mods enabled", - posX, posY.get(), Utils.Colors.WHITE); + posX, posY.get(), Colors.WHITE.toBuffer()); } else { getModManager() - .getMods() - .stream() - .filter(BaseMod::isEnabled) - .filter(mod -> !mod.isHidden()) - .map(mod -> debug.get() ? mod.getDebugDisplayText() : mod.getDisplayText()) - .sorted(sortMode.get().getComparator()) - .forEach( - name -> { - SurfaceHelper.drawTextShadow(">" + name, posX, posY.get(), Utils.Colors.WHITE); - posY.addAndGet(SurfaceHelper.getTextHeight() + 1); - }); + .getMods() + .stream() + .filter(BaseMod::isEnabled) + .filter(mod -> !mod.isHidden()) + .map(mod -> debug.get() ? mod.getDebugDisplayText() : mod.getDisplayText()) + .sorted(sortMode.get().getComparator()) + .forEach( + name -> { + SurfaceHelper.drawTextShadow(">" + name, posX, posY.get(), Colors.WHITE.toBuffer()); + posY.addAndGet(SurfaceHelper.getTextHeight() + 1); + }); } /* posY += (Render2DUtils.getTextHeight() + 1) * 2; @@ -154,17 +160,17 @@ public void onRenderScreen(RenderGameOverlayEvent.Text event) { posY += Render2DUtils.getTextHeight() + 1; Render2DUtils.drawTextShadow(String.format("Yaw: %.4f", MC.thePlayer.rotationYaw), posX, posY, Utils.toRGBA(255, 255, 255, 255));*/ } - + private enum SortMode { ALPHABETICAL((o1, o2) -> 0), // mod list is already sorted alphabetically LENGTH(Comparator.comparingInt(SurfaceHelper::getTextWidth).reversed()); - + private final Comparator comparator; - + public Comparator getComparator() { return this.comparator; } - + SortMode(Comparator comparatorIn) { this.comparator = comparatorIn; } diff --git a/src/main/java/com/matt/forgehax/mods/Aimbot.java b/src/main/java/com/matt/forgehax/mods/Aimbot.java index ca0a83673..9c2b38d85 100644 --- a/src/main/java/com/matt/forgehax/mods/Aimbot.java +++ b/src/main/java/com/matt/forgehax/mods/Aimbot.java @@ -27,223 +27,230 @@ @RegisterMod public class Aimbot extends ToggleMod implements PositionRotationManager.MovementUpdateListener { + private static Entity target = null; - + public static void setTarget(Entity target) { Aimbot.target = target; } - + public static Entity getTarget() { return target; } - + enum Selector { CROSSHAIR, DISTANCE, } - + private final Setting silent = - getCommandStub() - .builders() - .newSettingBuilder() - .name("silent") - .description("Wont look at target when aiming") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("silent") + .description("Wont look at target when aiming") + .defaultTo(true) + .build(); + private final Setting auto_attack = - getCommandStub() - .builders() - .newSettingBuilder() - .name("auto-attack") - .description("Automatically attack when target found") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("auto-attack") + .description("Automatically attack when target found") + .defaultTo(true) + .build(); + private final Setting hold_target = - getCommandStub() - .builders() - .newSettingBuilder() - .name("hold-target") - .description("Keep first caught target until it becomes no longer valid") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("hold-target") + .description("Keep first caught target until it becomes no longer valid") + .defaultTo(false) + .build(); + private final Setting vis_check = - getCommandStub() - .builders() - .newSettingBuilder() - .name("trace") - .description("Check if the target is visible before acquiring") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("trace") + .description("Check if the target is visible before acquiring") + .defaultTo(false) + .build(); + private final Setting target_players = - getCommandStub() - .builders() - .newSettingBuilder() - .name("target-players") - .description("Target players") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("target-players") + .description("Target players") + .defaultTo(true) + .build(); + private final Setting target_mobs_hostile = - getCommandStub() - .builders() - .newSettingBuilder() - .name("target-hostile-mobs") - .description("Target hostile mobs") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("target-hostile-mobs") + .description("Target hostile mobs") + .defaultTo(true) + .build(); + private final Setting target_mobs_friendly = - getCommandStub() - .builders() - .newSettingBuilder() - .name("target-friendly-mobs") - .description("Target friendly mobs") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("target-friendly-mobs") + .description("Target friendly mobs") + .defaultTo(false) + .build(); + private final Setting lag_compensation = - getCommandStub() - .builders() - .newSettingBuilder() - .name("lag-compensation") - .description("Compensate for server lag") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("lag-compensation") + .description("Compensate for server lag") + .defaultTo(true) + .build(); + private final Setting fov = - getCommandStub() - .builders() - .newSettingBuilder() - .name("fov") - .description("Aimbot field of view") - .defaultTo(180) - .min(0) - .max(180) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("fov") + .description("Aimbot field of view") + .defaultTo(180) + .min(0) + .max(180) + .build(); + private final Setting range = - getCommandStub() - .builders() - .newSettingBuilder() - .name("range") - .description("Aimbot range") - .defaultTo(4.5D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("range") + .description("Aimbot range") + .defaultTo(4.5D) + .build(); + private final Setting cooldown_percent = - getCommandStub() - .builders() - .newSettingBuilder() - .name("cooldown_percent") - .description("Minimum cooldown percent for next strike") - .defaultTo(100F) - .min(0F) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("cooldown_percent") + .description("Minimum cooldown percent for next strike") + .defaultTo(100F) + .min(0F) + .build(); + private final Setting projectile_aimbot = - getCommandStub() - .builders() - .newSettingBuilder() - .name("proj-aimbot") - .description("Projectile aimbot") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("proj-aimbot") + .description("Projectile aimbot") + .defaultTo(true) + .build(); + private final Setting projectile_auto_attack = - getCommandStub() - .builders() - .newSettingBuilder() - .name("proj-auto-attack") - .description("Automatically attack when target found for projectile weapons") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("proj-auto-attack") + .description("Automatically attack when target found for projectile weapons") + .defaultTo(true) + .build(); + private final Setting projectile_trace_check = - getCommandStub() - .builders() - .newSettingBuilder() - .name("projectile-trace") - .description("Check the trace of each target if holding a weapon that fires a projectile") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("projectile-trace") + .description("Check the trace of each target if holding a weapon that fires a projectile") + .defaultTo(true) + .build(); + private final Setting projectile_range = - getCommandStub() - .builders() - .newSettingBuilder() - .name("projectile-range") - .description("Projectile aimbot range") - .defaultTo(100D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("projectile-range") + .description("Projectile aimbot range") + .defaultTo(100D) + .build(); + private final Setting selector = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("selector") - .description("The method used to select a target from a group") - .defaultTo(Selector.CROSSHAIR) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("selector") + .description("The method used to select a target from a group") + .defaultTo(Selector.CROSSHAIR) + .build(); + public Aimbot() { super(Category.COMBAT, "Aimbot", false, "Automatically attack entities and players"); } - + private double getLagComp() { if (lag_compensation.get()) { return -(20.D - TickRateService.getTickData().getPoint().getAverage()); - } else return 0.D; + } else { + return 0.D; + } } - + private boolean canAttack(EntityPlayer localPlayer, Entity target) { final float cdRatio = cooldown_percent.get() / 100F; - final float cdOffset = cdRatio <= 1F ? 0F : -(localPlayer.getCooldownPeriod()*(cdRatio-1F)); + final float cdOffset = cdRatio <= 1F ? 0F : -(localPlayer.getCooldownPeriod() * (cdRatio - 1F)); return localPlayer.getCooledAttackStrength((float) getLagComp() + cdOffset) - >= (Math.min(1F, cdRatio)) - && (auto_attack.get() || Bindings.attack.getBinding().isKeyDown()); // need to work on this + >= (Math.min(1F, cdRatio)) + && (auto_attack.get() || Bindings.attack.getBinding().isKeyDown()); // need to work on this } - + private Projectile getHeldProjectile() { return Projectile.getProjectileByItemStack(getLocalPlayer().getHeldItem(EnumHand.MAIN_HAND)); } - + private boolean isHoldingProjectileItem() { return !getHeldProjectile().isNull(); } - + private boolean isProjectileAimbotActivated() { return projectile_aimbot.get() && isHoldingProjectileItem(); } - + private boolean isVisible(Entity target) { if (isProjectileAimbotActivated() && projectile_trace_check.get()) { return getHeldProjectile().canHitEntity(EntityUtils.getEyePos(getLocalPlayer()), target); - } else return !vis_check.get() || getLocalPlayer().canEntityBeSeen(target); + } else { + return !vis_check.get() || getLocalPlayer().canEntityBeSeen(target); + } } - + private Vec3d getAttackPosition(Entity entity) { return EntityUtils.getInterpolatedPos(entity, 1).addVector(0, entity.getEyeHeight() / 2, 0); } - - /** Check if the entity is a valid target to acquire */ + + /** + * Check if the entity is a valid target to acquire + */ private boolean filterTarget(Vec3d pos, Vec3d viewNormal, Angle angles, Entity entity) { final Vec3d tpos = getAttackPosition(entity); return Optional.of(entity) - .filter(EntityUtils::isLiving) - .filter(EntityUtils::isAlive) - .filter(EntityUtils::isValidEntity) - .filter(ent -> !ent.equals(getLocalPlayer())) - .filter(this::isFiltered) - .filter(ent -> isInRange(tpos, pos)) - .filter(ent -> isInFov(angles, tpos.subtract(pos))) - .filter(this::isVisible) - .isPresent(); + .filter(EntityUtils::isLiving) + .filter(EntityUtils::isAlive) + .filter(EntityUtils::isValidEntity) + .filter(ent -> !ent.equals(getLocalPlayer())) + .filter(this::isFiltered) + .filter(ent -> isInRange(tpos, pos)) + .filter(ent -> isInFov(angles, tpos.subtract(pos))) + .filter(this::isVisible) + .isPresent(); } - + private boolean isFiltered(Entity entity) { switch (EntityUtils.getRelationship(entity)) { case PLAYER: @@ -258,84 +265,89 @@ private boolean isFiltered(Entity entity) { return false; } } - + private boolean isInRange(Vec3d from, Vec3d to) { double dist = isProjectileAimbotActivated() ? projectile_range.get() : range.get(); return dist <= 0 || from.distanceTo(to) <= dist; } - + private boolean isInFov(Angle angle, Vec3d pos) { double fov = this.fov.get(); - if (fov >= 180) return true; - else { + if (fov >= 180) { + return true; + } else { Angle look = AngleHelper.getAngleFacingInDegrees(pos); Angle diff = angle.sub(look.getPitch(), look.getYaw()).normalize(); return Math.abs(diff.getPitch()) <= fov && Math.abs(diff.getYaw()) <= fov; } } - + private double selecting( - final Vec3d pos, final Vec3d viewNormal, final Angle angles, final Entity entity) { + final Vec3d pos, final Vec3d viewNormal, final Angle angles, final Entity entity) { switch (selector.get()) { case DISTANCE: return getAttackPosition(entity).subtract(pos).lengthSquared(); case CROSSHAIR: default: return getAttackPosition(entity) - .subtract(pos) - .normalize() - .subtract(viewNormal) - .lengthSquared(); + .subtract(pos) + .normalize() + .subtract(viewNormal) + .lengthSquared(); } } - + private Entity findTarget(final Vec3d pos, final Vec3d viewNormal, final Angle angles) { return getWorld() - .loadedEntityList - .stream() - .filter(entity -> filterTarget(pos, viewNormal, angles, entity)) - .min(Comparator.comparingDouble(entity -> selecting(pos, viewNormal, angles, entity))) - .orElse(null); + .loadedEntityList + .stream() + .filter(entity -> filterTarget(pos, viewNormal, angles, entity)) + .min(Comparator.comparingDouble(entity -> selecting(pos, viewNormal, angles, entity))) + .orElse(null); } - + @Override protected void onEnabled() { PositionRotationManager.getManager().register(this, PriorityEnum.HIGHEST); } - + @Override public void onDisabled() { PositionRotationManager.getManager().unregister(this); } - + @Override public void onLocalPlayerMovementUpdate(RotationState.Local state) { Vec3d pos = EntityUtils.getEyePos(getLocalPlayer()); Vec3d look = getLocalPlayer().getLookVec(); Angle angles = AngleHelper.getAngleFacingInDegrees(look); - + Entity t = getTarget(); if (!hold_target.get() - || t == null - || !filterTarget(pos, look.normalize(), angles, getTarget())) + || t == null + || !filterTarget(pos, look.normalize(), angles, getTarget())) { setTarget(t = findTarget(pos, look.normalize(), angles)); - - if (t == null) return; - + } + + if (t == null) { + return; + } + final Entity tar = t; Projectile projectile = getHeldProjectile(); - + if (projectile.isNull() || !projectile_aimbot.get()) { // melee aimbot Angle va = Utils.getLookAtAngles(t).normalize(); state.setViewAngles(va, silent.get()); - - if (canAttack(getLocalPlayer(), tar)) + + if (canAttack(getLocalPlayer(), tar)) { state.invokeLater( - rs -> { - getPlayerController().attackEntity(getLocalPlayer(), tar); - getLocalPlayer().swingArm(EnumHand.MAIN_HAND); - }); + rs -> { + getPlayerController().attackEntity(getLocalPlayer(), tar); + getLocalPlayer().swingArm(EnumHand.MAIN_HAND); + }); + } } } } diff --git a/src/main/java/com/matt/forgehax/mods/AntiAfkMod.java b/src/main/java/com/matt/forgehax/mods/AntiAfkMod.java index 9c1a04be1..0942b913c 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiAfkMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiAfkMod.java @@ -1,6 +1,9 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getModManager; +import static com.matt.forgehax.Helper.getNetworkManager; +import static com.matt.forgehax.Helper.getWorld; import com.google.common.collect.Lists; import com.matt.forgehax.asm.ForgeHaxHooks; @@ -40,152 +43,155 @@ @RegisterMod public class AntiAfkMod extends ToggleMod { + private final Setting delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("delay") - .description("Delay time (in MS) between tasks") - .defaultTo(10_000L) - .min(0L) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("delay") + .description("Delay time (in MS) between tasks") + .defaultTo(10_000L) + .min(0L) + .build(); private final Setting runtime = - getCommandStub() - .builders() - .newSettingBuilder() - .name("runtime") - .description("Time to run each task") - .defaultTo(5_000L) - .min(0L) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("runtime") + .description("Time to run each task") + .defaultTo(5_000L) + .min(0L) + .build(); private final Setting silent = - getCommandStub() - .builders() - .newSettingBuilder() - .name("silent") - .description("Make most afk tasks execute without disrupting the players view") - .defaultTo(false) - .changed(cb -> TaskEnum.setSilent(cb.getTo())) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("silent") + .description("Make most afk tasks execute without disrupting the players view") + .defaultTo(false) + .changed(cb -> TaskEnum.setSilent(cb.getTo())) + .build(); + private final Setting swing = - getCommandStub() - .builders() - .newSettingBuilder() - .name("swing") - .description("Swing the players arm") - .defaultTo(true) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("swing") + .description("Swing the players arm") + .defaultTo(true) + .build(); private final Setting walk = - getCommandStub() - .builders() - .newSettingBuilder() - .name("walk") - .description("Walk in different directions") - .defaultTo(false) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("walk") + .description("Walk in different directions") + .defaultTo(false) + .build(); private final Setting spin = - getCommandStub() - .builders() - .newSettingBuilder() - .name("spin") - .description("Spin the players view") - .defaultTo(false) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("spin") + .description("Spin the players view") + .defaultTo(false) + .build(); private final Setting mine = - getCommandStub() - .builders() - .newSettingBuilder() - .name("mine") - .description( - "Place and break a block that is in the players inventory. Only runs if the player has a block that can break in 1 hit and be placed under the player.") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("mine") + .description( + "Place and break a block that is in the players inventory. Only runs if the player has a block that can break in 1 hit and be placed under the player.") + .defaultTo(false) + .build(); + private final SimpleTimer timer = new SimpleTimer(); private final AtomicBoolean ranStop = new AtomicBoolean(false); - + private TaskEnum task = TaskEnum.NONE; - + public AntiAfkMod() { super(Category.PLAYER, "AntiAFK", false, "Swing arm to prevent being afk kicked"); - + TaskEnum.SWING.setParentSetting(swing); TaskEnum.WALK.setParentSetting(walk); TaskEnum.SPIN.setParentSetting(spin); TaskEnum.MINE.setParentSetting(mine); } - + private TaskEnum getTask() { return task; } - + private void setTask(TaskEnum task) { this.task = task; } - + private boolean isTaskRunning() { return !getTask().equals(TaskEnum.NONE); } - + private List getNextTask() { return TaskEnum.ALL - .stream() - .filter(IAFKTask::isRunnable) - .filter(TaskEnum::isEnabled) - .collect(Collectors.toList()); + .stream() + .filter(IAFKTask::isRunnable) + .filter(TaskEnum::isEnabled) + .collect(Collectors.toList()); } - + private void reset() { timer.reset(); ranStop.set(false); getTask().onStop(); setTask(TaskEnum.NONE); } - + @Override protected void onLoad() { TaskEnum.setSilent(silent.get()); } - + @Override public String getDebugDisplayText() { return super.getDebugDisplayText() - + " " - + String.format( - "[%s | %s | next = %s]", - getTask().name(), - isTaskRunning() ? "Running" : "Waiting", - isTaskRunning() - ? (SimpleTimer.toFormattedTime(Math.max(runtime.get() - timer.getTimeElapsed(), 0))) - : (SimpleTimer.toFormattedTime(Math.max(delay.get() - timer.getTimeElapsed(), 0)))); + + " " + + String.format( + "[%s | %s | next = %s]", + getTask().name(), + isTaskRunning() ? "Running" : "Waiting", + isTaskRunning() + ? (SimpleTimer.toFormattedTime(Math.max(runtime.get() - timer.getTimeElapsed(), 0))) + : (SimpleTimer.toFormattedTime(Math.max(delay.get() - timer.getTimeElapsed(), 0)))); } - + @SubscribeEvent public void onKeyboardInput(InputEvent.KeyInputEvent event) { reset(); } - + @SubscribeEvent public void onMouseEvent(InputEvent.MouseInputEvent event) { reset(); } - + @SubscribeEvent public void onDisconnect(FMLNetworkEvent.ClientDisconnectionFromServerEvent event) { reset(); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { - if (!timer.isStarted()) timer.start(); // start timer if it hasn't already - + if (!timer.isStarted()) { + timer.start(); // start timer if it hasn't already + } + if (!isTaskRunning()) { if (timer.hasTimeElapsed(delay.get())) { List next = getNextTask(); if (!next.isEmpty()) { // wait again to check if the task is valid setTask( - next.get(ThreadLocalRandom.current().nextInt(next.size()))); // select a random task + next.get(ThreadLocalRandom.current().nextInt(next.size()))); // select a random task getTask().onStart(); } timer.start(); @@ -194,11 +200,14 @@ public void onUpdate(LocalPlayerUpdateEvent event) { if (timer.hasTimeElapsed(runtime.get())) { boolean prev = ranStop.get(); if (ranStop.compareAndSet(false, true)) // only run once - getTask().onStop(); - + { + getTask().onStop(); + } + if (getTask().isRunning()) { - if (prev == ranStop.get()) + if (prev == ranStop.get()) { getTask().onTick(); // only run if this task did not execute onStop() on the same tick + } } else { setTask(TaskEnum.NONE); ranStop.set(false); @@ -209,18 +218,21 @@ public void onUpdate(LocalPlayerUpdateEvent event) { } } } - + enum TaskEnum implements IAFKTask { NONE { @Override - public void onTick() {} - + public void onTick() { + } + @Override - public void onStart() {} - + public void onStart() { + } + @Override - public void onStop() {} - + public void onStop() { + } + @Override public boolean isRunnable() { return false; @@ -228,11 +240,13 @@ public boolean isRunnable() { }, SWING { @Override - public void onTick() {} - + public void onTick() { + } + @Override - public void onStart() {} - + public void onStart() { + } + @Override public void onStop() { swingHand(); @@ -240,41 +254,43 @@ public void onStop() { }, WALK { static final int DEGREES = 45; - + double angle = 0; - + @Override public void onTick() { Bindings.forward.setPressed(true); // TODO: reimplement view angle setting } - + @Override public void onStart() { ForgeHaxHooks.isSafeWalkActivated = true; Bindings.forward.bind(); - + Vec3d eye = EntityUtils.getEyePos(getLocalPlayer()); - + List yaws = Lists.newArrayList(); - for (int i = 0; i < (360 / DEGREES); ++i) yaws.add((i * DEGREES) - 180.D); + for (int i = 0; i < (360 / DEGREES); ++i) { + yaws.add((i * DEGREES) - 180.D); + } Collections.shuffle(yaws); - + double lastDistance = -1.D; for (double y : yaws) { double[] cc = Angle.degrees(0.f, (float) y).getForwardVector(); Vec3d target = eye.add(new Vec3d(cc[0], cc[1], cc[2]).normalize().scale(64)); - + RayTraceResult result = getWorld().rayTraceBlocks(eye, target, false, true, false); double distance = result == null ? 64.D : eye.distanceTo(result.hitVec); if ((distance >= 1.D || lastDistance == -1.D) - && (distance > lastDistance || Math.random() < 0.20D)) { + && (distance > lastDistance || Math.random() < 0.20D)) { angle = y; lastDistance = distance; } } } - + @Override public void onStop() { Bindings.forward.setPressed(false); @@ -283,29 +299,29 @@ public void onStop() { getLocalPlayer().motionY = 0.D; getLocalPlayer().motionZ = 0.D; getModManager() - .get(SafeWalkMod.class) - .ifPresent(mod -> ForgeHaxHooks.isSafeWalkActivated = mod.isEnabled()); + .get(SafeWalkMod.class) + .ifPresent(mod -> ForgeHaxHooks.isSafeWalkActivated = mod.isEnabled()); } }, SPIN { float ang = 0.f; - double p, y; - + double p,y; + @Override public void onTick() { setViewAngles( - MathHelper.clamp( - getLocalPlayer().rotationPitch + MathHelper.cos(ang += 0.1f), -90.f, 90.f), - getLocalPlayer().rotationYaw + 1.8f); + MathHelper.clamp( + getLocalPlayer().rotationPitch + MathHelper.cos(ang += 0.1f), -90.f, 90.f), + getLocalPlayer().rotationYaw + 1.8f); } - + @Override public void onStart() { ang = 0.f; p = getLocalPlayer().rotationPitch; y = getLocalPlayer().rotationYaw; } - + @Override public void onStop() { setViewAngles(p, y); @@ -313,177 +329,187 @@ public void onStop() { }, MINE { static final int MULTIPLIER = 2; - + final SimpleTimer halting = new SimpleTimer(); - + int counter = 0; double p; - + RayTraceResult getTraceBelow() { // TODO: fix the trace so i dont have to do witchcraft in // getBlockBelow() Vec3d eyes = EntityUtils.getEyePos(getLocalPlayer()); return getWorld() - .rayTraceBlocks( - eyes, - eyes.addVector(0, -MC.playerController.getBlockReachDistance(), 0), - false, - false, - false); + .rayTraceBlocks( + eyes, + eyes.addVector(0, -MC.playerController.getBlockReachDistance(), 0), + false, + false, + false); } - + BlockPos getBlockBelow() { RayTraceResult tr = getTraceBelow(); return tr == null - ? BlockPos.ORIGIN - : (getWorld() - .getBlockState(tr.getBlockPos().add(0, 1, 0)) - .getBlock() - .equals(Blocks.REDSTONE_WIRE) - ? tr.getBlockPos().add(0, 1, 0) - : tr.getBlockPos()); + ? BlockPos.ORIGIN + : (getWorld() + .getBlockState(tr.getBlockPos().add(0, 1, 0)) + .getBlock() + .equals(Blocks.REDSTONE_WIRE) + ? tr.getBlockPos().add(0, 1, 0) + : tr.getBlockPos()); } - + boolean isPlaced() { return getWorld().getBlockState(getBlockBelow()).getBlock().equals(Blocks.REDSTONE_WIRE); } - + @Override public void onTick() { if (counter++ % (TPS * MULTIPLIER) == 0) { if (isPlaced()) { getNetworkManager() - .sendPacket( - new CPacketPlayerDigging( - CPacketPlayerDigging.Action.START_DESTROY_BLOCK, - getBlockBelow(), - EnumFacing.UP)); + .sendPacket( + new CPacketPlayerDigging( + CPacketPlayerDigging.Action.START_DESTROY_BLOCK, + getBlockBelow(), + EnumFacing.UP)); swingHand(); return; } - + LocalPlayerInventory.InvItem item = - LocalPlayerInventory.getHotbarInventory() - .stream() - .filter(itm -> itm.getItemStack().getItem() instanceof ItemRedstone) - .findAny() - .orElse(LocalPlayerInventory.InvItem.EMPTY); - - if (item.isNull()) return; - + LocalPlayerInventory.getHotbarInventory() + .stream() + .filter(itm -> itm.getItemStack().getItem() instanceof ItemRedstone) + .findAny() + .orElse(LocalPlayerInventory.InvItem.EMPTY); + + if (item.isNull()) { + return; + } + RayTraceResult result = getTraceBelow(); - - if (result == null) return; - - if (!Blocks.REDSTONE_WIRE.canPlaceBlockAt(getWorld(), result.getBlockPos())) + + if (result == null) { + return; + } + + if (!Blocks.REDSTONE_WIRE.canPlaceBlockAt(getWorld(), result.getBlockPos())) { return; // can't place block - + } + ResetFunction func = LocalPlayerInventory.setSelected(item); LocalPlayerInventory.syncSelected(); - + getNetworkManager() - .sendPacket( - new CPacketPlayerTryUseItemOnBlock( - result.getBlockPos(), - EnumFacing.UP, - EnumHand.MAIN_HAND, - (float) (result.hitVec.x - result.getBlockPos().getX()), - (float) (result.hitVec.y - result.getBlockPos().getY()), - (float) (result.hitVec.z - result.getBlockPos().getZ()))); + .sendPacket( + new CPacketPlayerTryUseItemOnBlock( + result.getBlockPos(), + EnumFacing.UP, + EnumHand.MAIN_HAND, + (float) (result.hitVec.x - result.getBlockPos().getX()), + (float) (result.hitVec.y - result.getBlockPos().getY()), + (float) (result.hitVec.z - result.getBlockPos().getZ()))); swingHand(); - + func.revert(); } } - + @Override public void onStart() { halting.reset(); counter = TPS * MULTIPLIER - 1; // start by placing the block p = getLocalPlayer().rotationPitch; - + BlockPos pos = getBlockBelow(); Vec3d look = new Vec3d(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D); Angle va = Utils.getLookAtAngles(look); setViewAngles(va.getPitch(), va.getYaw()); } - + @Override public void onStop() { halting.start(); } - + @Override public boolean isRunnable() { return LocalPlayerInventory.getHotbarInventory() - .stream() - .anyMatch(item -> item.getItemStack().getItem() instanceof ItemRedstone) - && (Blocks.REDSTONE_WIRE.canPlaceBlockAt(getWorld(), getBlockBelow()) || isPlaced()); + .stream() + .anyMatch(item -> item.getItemStack().getItem() instanceof ItemRedstone) + && (Blocks.REDSTONE_WIRE.canPlaceBlockAt(getWorld(), getBlockBelow()) || isPlaced()); // return false; // disabled until functional } - + @Override public boolean isRunning() { return (!halting.isStarted() || !halting.hasTimeElapsed(5_000)) && isPlaced(); } }, ; - + Setting parentSetting; - - TaskEnum() {} - + + TaskEnum() { + } + public void setParentSetting(Setting parentSetting) { this.parentSetting = parentSetting; } - + public boolean isEnabled() { Objects.requireNonNull(parentSetting, "Setting must be set for all tasks in enum"); return parentSetting.get(); } - + // // // - + static final int TPS = 20; static boolean silent = false; - + static void swingHand() { - if (silent) getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); - else getLocalPlayer().swingArm(EnumHand.MAIN_HAND); + if (silent) { + getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); + } else { + getLocalPlayer().swingArm(EnumHand.MAIN_HAND); + } } - + static void setViewAngles(double p, double y) { /* if(silent) getNetworkManager().sendPacket(new CPacketPlayer.Rotation((float)p, (float)y, getLocalPlayer().onGround)); else LocalPlayerUtils.setViewAngles(p, y);*/ - + // TODO: view angle stuff } - + public static void setSilent(boolean silent) { TaskEnum.silent = silent; } - + // // - + public static final EnumSet ALL = EnumSet.allOf(TaskEnum.class); } - + interface IAFKTask { + void onTick(); - + void onStart(); - + void onStop(); - + default boolean isRunnable() { return true; } - + default boolean isRunning() { return false; } diff --git a/src/main/java/com/matt/forgehax/mods/AntiBatsMod.java b/src/main/java/com/matt/forgehax/mods/AntiBatsMod.java index 33122f77c..6480531e5 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiBatsMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiBatsMod.java @@ -17,52 +17,55 @@ @RegisterMod public class AntiBatsMod extends ToggleMod { + private static final MobType BATS_MOBTYPE = - new MobType() { - @Override - protected PriorityEnum getPriority() { - return PriorityEnum.LOW; - } - - @Override - public boolean isMobType(Entity entity) { - return entity instanceof EntityBat; - } - - @Override - protected MobTypeEnum getMobTypeUnchecked(Entity entity) { - return MobTypeEnum.INVALID; - } - }; - + new MobType() { + @Override + protected PriorityEnum getPriority() { + return PriorityEnum.LOW; + } + + @Override + public boolean isMobType(Entity entity) { + return entity instanceof EntityBat; + } + + @Override + protected MobTypeEnum getMobTypeUnchecked(Entity entity) { + return MobTypeEnum.INVALID; + } + }; + public AntiBatsMod() { super(Category.RENDER, "AntiBats", false, "666 KILL BATS 666"); } - + @Override public void onEnabled() { MobTypeRegistry.register(BATS_MOBTYPE); EntityUtils.isBatsDisabled = true; } - + @Override public void onDisabled() { MobTypeRegistry.unregister(BATS_MOBTYPE); EntityUtils.isBatsDisabled = false; } - + @SubscribeEvent public void onRenderLiving(RenderLivingEvent.Pre event) { - if (event.getEntity() instanceof EntityBat) event.setCanceled(true); + if (event.getEntity() instanceof EntityBat) { + event.setCanceled(true); + } } - + @SubscribeEvent public void onPlaySound(PlaySoundAtEntityEvent event) { if (event.getSound().equals(SoundEvents.ENTITY_BAT_AMBIENT) - || event.getSound().equals(SoundEvents.ENTITY_BAT_DEATH) - || event.getSound().equals(SoundEvents.ENTITY_BAT_HURT) - || event.getSound().equals(SoundEvents.ENTITY_BAT_LOOP) - || event.getSound().equals(SoundEvents.ENTITY_BAT_TAKEOFF)) { + || event.getSound().equals(SoundEvents.ENTITY_BAT_DEATH) + || event.getSound().equals(SoundEvents.ENTITY_BAT_HURT) + || event.getSound().equals(SoundEvents.ENTITY_BAT_LOOP) + || event.getSound().equals(SoundEvents.ENTITY_BAT_TAKEOFF)) { event.setVolume(0.f); event.setPitch(0.f); event.setCanceled(true); diff --git a/src/main/java/com/matt/forgehax/mods/AntiEffectsMod.java b/src/main/java/com/matt/forgehax/mods/AntiEffectsMod.java index 6667d2caf..45bbe7549 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiEffectsMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiEffectsMod.java @@ -12,19 +12,20 @@ @RegisterMod public class AntiEffectsMod extends ToggleMod { + public final Setting no_particles = - getCommandStub() - .builders() - .newSettingBuilder() - .name("no_particles") - .description("Stops the particle effect from rendering on other entities") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("no_particles") + .description("Stops the particle effect from rendering on other entities") + .defaultTo(true) + .build(); + public AntiEffectsMod() { super(Category.RENDER, "AntiPotionEffects", false, "Removes potion effects"); } - + @SubscribeEvent public void onLivingUpdate(LivingEvent.LivingUpdateEvent event) { EntityLivingBase living = event.getEntityLiving(); diff --git a/src/main/java/com/matt/forgehax/mods/AntiFireMod.java b/src/main/java/com/matt/forgehax/mods/AntiFireMod.java index 65b302be6..5a4461234 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiFireMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiFireMod.java @@ -16,35 +16,39 @@ @RegisterMod public class AntiFireMod extends ToggleMod { + public AntiFireMod() { super(Category.PLAYER, "AntiFire", false, "Removes fire"); } - + private final Setting collisions = - getCommandStub() - .builders() - .newSettingBuilder() - .name("collisions") - .description("Give fire collision boxes") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("collisions") + .description("Give fire collision boxes") + .defaultTo(false) + .build(); + @SubscribeEvent public void onAddCollisionBox(AddCollisionBoxToListEvent event) { - if (!collisions.get()) return; - + if (!collisions.get()) { + return; + } + if (Helper.getLocalPlayer() != null) { AxisAlignedBB bb = new AxisAlignedBB(event.getPos()).expand(0, 0.1D, 0); - if (event.getBlock() == Blocks.FIRE && isAbovePlayer(event.getPos()) && event.getEntityBox().intersects(bb)) { + if (event.getBlock() == Blocks.FIRE && isAbovePlayer(event.getPos()) && event.getEntityBox() + .intersects(bb)) { event.getCollidingBoxes().add(bb); } } } - + private boolean isAbovePlayer(BlockPos pos) { return pos.getY() >= getLocalPlayer().posY; } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { event.getEntityLiving().extinguish(); diff --git a/src/main/java/com/matt/forgehax/mods/AntiFogMod.java b/src/main/java/com/matt/forgehax/mods/AntiFogMod.java index 5d695eac8..a97cc3718 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiFogMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiFogMod.java @@ -8,16 +8,17 @@ @RegisterMod public class AntiFogMod extends ToggleMod { + public AntiFogMod() { super(Category.WORLD, "AntiFog", false, "Removes fog"); } - + @SubscribeEvent public void onFogDensity(EntityViewRenderEvent.FogDensity event) { event.setDensity(0); event.setCanceled(true); } - + @SubscribeEvent public void onFogColor(EntityViewRenderEvent.FogColors event) { event.setRed(55); diff --git a/src/main/java/com/matt/forgehax/mods/AntiHeldItemChangeMod.java b/src/main/java/com/matt/forgehax/mods/AntiHeldItemChangeMod.java index 9f5ad7438..5b24f638a 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiHeldItemChangeMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiHeldItemChangeMod.java @@ -12,29 +12,32 @@ import net.minecraft.network.play.server.SPacketSetSlot; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created by Babbaj on 9/1/2017. */ +/** + * Created by Babbaj on 9/1/2017. + */ @RegisterMod public class AntiHeldItemChangeMod extends ToggleMod { + public AntiHeldItemChangeMod() { super( - Category.PLAYER, - "AntiHeldItemChange", - false, - "prevents the server from changing selected hotbar slot"); + Category.PLAYER, + "AntiHeldItemChange", + false, + "prevents the server from changing selected hotbar slot"); } - + @SubscribeEvent public void onPacketReceived(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketSetSlot && getLocalPlayer() != null) { int currentSlot = getLocalPlayer().inventory.currentItem; - + if (((SPacketSetSlot) event.getPacket()).getSlot() != currentSlot) { getNetworkManager() - .sendPacket( - new CPacketHeldItemChange(currentSlot)); // set server's slot back to our slot + .sendPacket( + new CPacketHeldItemChange(currentSlot)); // set server's slot back to our slot FastReflection.Methods.KeyBinding_unPress.invoke( - MC.gameSettings.keyBindUseItem); // likely will eating so stop right clicking - + MC.gameSettings.keyBindUseItem); // likely will eating so stop right clicking + event.setCanceled(true); } } diff --git a/src/main/java/com/matt/forgehax/mods/AntiHurtCamMod.java b/src/main/java/com/matt/forgehax/mods/AntiHurtCamMod.java index 1790dfb80..cfbe6f5df 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiHurtCamMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiHurtCamMod.java @@ -8,10 +8,11 @@ @RegisterMod public class AntiHurtCamMod extends ToggleMod { + public AntiHurtCamMod() { super(Category.PLAYER, "AntiHurtcam", false, "Removes hurt camera effect"); } - + @SubscribeEvent public void onHurtCamEffect(HurtCamEffectEvent event) { event.setCanceled(true); diff --git a/src/main/java/com/matt/forgehax/mods/AntiKnockbackMod.java b/src/main/java/com/matt/forgehax/mods/AntiKnockbackMod.java index 91a05868c..84b44fb8b 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiKnockbackMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiKnockbackMod.java @@ -25,118 +25,121 @@ @RegisterMod public class AntiKnockbackMod extends ToggleMod { + private final Setting multiplier_x = - getCommandStub() - .builders() - .newSettingBuilder() - .name("x-multiplier") - .description("Multiplier for X axis") - .defaultTo(0.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("x-multiplier") + .description("Multiplier for X axis") + .defaultTo(0.D) + .build(); + private final Setting multiplier_y = - getCommandStub() - .builders() - .newSettingBuilder() - .name("y-multiplier") - .description("Multiplier for Y axis") - .defaultTo(0.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("y-multiplier") + .description("Multiplier for Y axis") + .defaultTo(0.D) + .build(); + private final Setting multiplier_z = - getCommandStub() - .builders() - .newSettingBuilder() - .name("z-multiplier") - .description("Multiplier for Z axis") - .defaultTo(0.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("z-multiplier") + .description("Multiplier for Z axis") + .defaultTo(0.D) + .build(); + private final Setting explosions = - getCommandStub() - .builders() - .newSettingBuilder() - .name("explosions") - .description("Disable velocity from SPacketExplosion") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("explosions") + .description("Disable velocity from SPacketExplosion") + .defaultTo(true) + .build(); + private final Setting velocity = - getCommandStub() - .builders() - .newSettingBuilder() - .name("velocity") - .description("Disable velocity from SPacketEntityVelocity") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("velocity") + .description("Disable velocity from SPacketEntityVelocity") + .defaultTo(true) + .build(); + private final Setting fishhook = - getCommandStub() - .builders() - .newSettingBuilder() - .name("fishhook") - .description("Disable velocity from a fishhook") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("fishhook") + .description("Disable velocity from a fishhook") + .defaultTo(true) + .build(); + private final Setting water = - getCommandStub() - .builders() - .newSettingBuilder() - .name("water") - .description("Disable velocity from flowing water") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("water") + .description("Disable velocity from flowing water") + .defaultTo(true) + .build(); + private final Setting push = - getCommandStub() - .builders() - .newSettingBuilder() - .name("push") - .description("Disable velocity from entity pushing") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("push") + .description("Disable velocity from entity pushing") + .defaultTo(true) + .build(); + private final Setting blocks = - getCommandStub() - .builders() - .newSettingBuilder() - .name("blocks") - .description("Disable velocity from block pushing") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("blocks") + .description("Disable velocity from block pushing") + .defaultTo(true) + .build(); + private final Setting slipping = - getCommandStub() - .builders() - .newSettingBuilder() - .name("slipping") - .description("Disable velocity from ice slipping") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("slipping") + .description("Disable velocity from ice slipping") + .defaultTo(true) + .build(); + public AntiKnockbackMod() { super(Category.COMBAT, "AntiKnockback", false, "Removes knockback movement"); } - + private Vec3d getMultiplier() { return new Vec3d(multiplier_x.get(), multiplier_y.get(), multiplier_z.get()); } - + private Vec3d getPacketMotion(Packet packet) { - if (packet instanceof SPacketExplosion) + if (packet instanceof SPacketExplosion) { return new Vec3d( - FastReflection.Fields.SPacketExplosion_motionX.get(packet), - FastReflection.Fields.SPacketExplosion_motionY.get(packet), - FastReflection.Fields.SPacketExplosion_motionZ.get(packet)); - else if (packet instanceof SPacketEntityVelocity) + FastReflection.Fields.SPacketExplosion_motionX.get(packet), + FastReflection.Fields.SPacketExplosion_motionY.get(packet), + FastReflection.Fields.SPacketExplosion_motionZ.get(packet)); + } else if (packet instanceof SPacketEntityVelocity) { return new Vec3d( - FastReflection.Fields.SPacketEntityVelocity_motionX.get(packet), - FastReflection.Fields.SPacketEntityVelocity_motionY.get(packet), - FastReflection.Fields.SPacketEntityVelocity_motionZ.get(packet)); - else throw new IllegalArgumentException(); + FastReflection.Fields.SPacketEntityVelocity_motionX.get(packet), + FastReflection.Fields.SPacketEntityVelocity_motionY.get(packet), + FastReflection.Fields.SPacketEntityVelocity_motionZ.get(packet)); + } else { + throw new IllegalArgumentException(); + } } - + private void setPacketMotion(Packet packet, Vec3d in) { if (packet instanceof SPacketExplosion) { FastReflection.Fields.SPacketExplosion_motionX.set(packet, (float) in.x); @@ -146,87 +149,101 @@ private void setPacketMotion(Packet packet, Vec3d in) { FastReflection.Fields.SPacketEntityVelocity_motionX.set(packet, (int) Math.round(in.x)); FastReflection.Fields.SPacketEntityVelocity_motionY.set(packet, (int) Math.round(in.y)); FastReflection.Fields.SPacketEntityVelocity_motionZ.set(packet, (int) Math.round(in.z)); - } else throw new IllegalArgumentException(); + } else { + throw new IllegalArgumentException(); + } } - + private void addEntityVelocity(Entity in, Vec3d velocity) { in.motionX += velocity.x; in.motionY += velocity.y; in.motionZ += velocity.z; } - - /** Stops TNT and knockback velocity */ + + /** + * Stops TNT and knockback velocity + */ @SubscribeEvent public void onPacketRecieved(PacketEvent.Incoming.Pre event) { - if (getLocalPlayer() == null || getWorld() == null) return; - else if (explosions.get() && event.getPacket() instanceof SPacketExplosion) { + if (getLocalPlayer() == null || getWorld() == null) { + return; + } else if (explosions.get() && event.getPacket() instanceof SPacketExplosion) { Vec3d multiplier = getMultiplier(); Vec3d motion = getPacketMotion(event.getPacket()); setPacketMotion(event.getPacket(), VectorUtils.multiplyBy(motion, multiplier)); } else if (velocity.get() && event.getPacket() instanceof SPacketEntityVelocity) { if (((SPacketEntityVelocity) event.getPacket()).getEntityID() - == getLocalPlayer().getEntityId()) { + == getLocalPlayer().getEntityId()) { Vec3d multiplier = getMultiplier(); - if (multiplier.lengthSquared() > 0.D) + if (multiplier.lengthSquared() > 0.D) { setPacketMotion( - event.getPacket(), - VectorUtils.multiplyBy(getPacketMotion(event.getPacket()), multiplier)); - else event.setCanceled(true); + event.getPacket(), + VectorUtils.multiplyBy(getPacketMotion(event.getPacket()), multiplier)); + } else { + event.setCanceled(true); + } } } else if (fishhook.get() && event.getPacket() instanceof SPacketEntityStatus) { // CREDITS TO 0x22 // fuck you popbob for making me need this SPacketEntityStatus packet = (SPacketEntityStatus) event.getPacket(); switch (packet.getOpCode()) { - case 31: - { - Entity offender = packet.getEntity(getWorld()); - if (offender instanceof EntityFishHook) { - EntityFishHook hook = (EntityFishHook) offender; - if (getLocalPlayer().equals(hook.caughtEntity)) event.setCanceled(true); + case 31: { + Entity offender = packet.getEntity(getWorld()); + if (offender instanceof EntityFishHook) { + EntityFishHook hook = (EntityFishHook) offender; + if (getLocalPlayer().equals(hook.caughtEntity)) { + event.setCanceled(true); } - break; } + break; + } default: break; } } } - - /** Stops velocity from water */ + + /** + * Stops velocity from water + */ @SubscribeEvent public void onWaterMovementEvent(WaterMovementEvent event) { if (water.get() && getLocalPlayer() != null && getLocalPlayer().equals(event.getEntity())) { addEntityVelocity( - event.getEntity(), - VectorUtils.multiplyBy(event.getMoveDir().normalize().scale(0.014D), getMultiplier())); + event.getEntity(), + VectorUtils.multiplyBy(event.getMoveDir().normalize().scale(0.014D), getMultiplier())); event.setCanceled(true); } } - - /** Stops velocity from collision */ + + /** + * Stops velocity from collision + */ @SubscribeEvent public void onApplyCollisionMotion(ApplyCollisionMotionEvent event) { if (push.get() && getLocalPlayer() != null && getLocalPlayer().equals(event.getEntity())) { addEntityVelocity( - event.getEntity(), - VectorUtils.multiplyBy( - new Vec3d(event.getMotionX(), event.getMotionY(), event.getMotionZ()), - getMultiplier())); + event.getEntity(), + VectorUtils.multiplyBy( + new Vec3d(event.getMotionX(), event.getMotionY(), event.getMotionZ()), + getMultiplier())); event.setCanceled(true); } } - + @SubscribeEvent public void onPushOutOfBlocks(PushOutOfBlocksEvent event) { - if (blocks.get()) event.setCanceled(true); + if (blocks.get()) { + event.setCanceled(true); + } } - + @SubscribeEvent public void onBlockSlip(EntityBlockSlipApplyEvent event) { if (slipping.get() - && getLocalPlayer() != null - && getLocalPlayer().equals(event.getEntityLivingBase())) { + && getLocalPlayer() != null + && getLocalPlayer().equals(event.getEntityLivingBase())) { event.setSlipperiness(0.6f); } } diff --git a/src/main/java/com/matt/forgehax/mods/AntiLevitationMod.java b/src/main/java/com/matt/forgehax/mods/AntiLevitationMod.java index 417eaf5c9..30e607464 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiLevitationMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiLevitationMod.java @@ -9,13 +9,16 @@ import net.minecraft.potion.Potion; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 11/28/2016 by fr1kin */ +/** + * Created on 11/28/2016 by fr1kin + */ @RegisterMod public class AntiLevitationMod extends ToggleMod { + public AntiLevitationMod() { super(Category.PLAYER, "AntiLevitation", false, "No levitation"); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { if (getLocalPlayer().isPotionActive(Potion.getPotionFromResourceLocation("levitation"))) { diff --git a/src/main/java/com/matt/forgehax/mods/AntiOverlayMod.java b/src/main/java/com/matt/forgehax/mods/AntiOverlayMod.java index ea581dbf0..fe91a962c 100644 --- a/src/main/java/com/matt/forgehax/mods/AntiOverlayMod.java +++ b/src/main/java/com/matt/forgehax/mods/AntiOverlayMod.java @@ -15,37 +15,43 @@ @RegisterMod public class AntiOverlayMod extends ToggleMod { + public AntiOverlayMod() { super(Category.PLAYER, "AntiOverlay", false, "Removes screen overlays"); } - - /** Disables water/lava fog */ + + /** + * Disables water/lava fog + */ @SubscribeEvent public void onFogRender(EntityViewRenderEvent.FogDensity event) { if (event.getState().getMaterial().equals(Material.WATER) - || event.getState().getMaterial().equals(Material.LAVA)) { + || event.getState().getMaterial().equals(Material.LAVA)) { event.setDensity(0); event.setCanceled(true); } } - - /** Disables screen overlays */ + + /** + * Disables screen overlays + */ @SubscribeEvent public void onRenderBlockOverlay(RenderBlockOverlayEvent event) { event.setCanceled(true); } - + @SubscribeEvent public void onRenderGameOverlay(RenderGameOverlayEvent event) { if (event.getType().equals(RenderGameOverlayEvent.ElementType.HELMET) - || event.getType().equals(RenderGameOverlayEvent.ElementType.PORTAL)) + || event.getType().equals(RenderGameOverlayEvent.ElementType.PORTAL)) { event.setCanceled(true); + } } - + @SubscribeEvent public void onRender(RenderEvent event) { ItemStack item = FastReflection.Fields.EntityRenderer_itemActivationItem.get(MC.entityRenderer); - + if (item != null && item.getItem() == Items.TOTEM_OF_UNDYING) { FastReflection.Fields.EntityRenderer_itemActivationItem.set(MC.entityRenderer, null); } diff --git a/src/main/java/com/matt/forgehax/mods/AutoArmorMod.java b/src/main/java/com/matt/forgehax/mods/AutoArmorMod.java deleted file mode 100644 index 4ff68f0dc..000000000 --- a/src/main/java/com/matt/forgehax/mods/AutoArmorMod.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.matt.forgehax.mods; - -import com.matt.forgehax.util.mod.Category; -import com.matt.forgehax.util.mod.ToggleMod; - -public class AutoArmorMod extends ToggleMod { - public AutoArmorMod() { - super(Category.COMBAT, "AutoArmor", false, "Automatically put on armor"); - } -} diff --git a/src/main/java/com/matt/forgehax/mods/AutoBucketFallMod.java b/src/main/java/com/matt/forgehax/mods/AutoBucketFallMod.java index 767b3803e..84e048afb 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoBucketFallMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoBucketFallMod.java @@ -1,7 +1,10 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.*; -import static com.matt.forgehax.util.entity.EntityUtils.*; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getNetworkManager; +import static com.matt.forgehax.Helper.getWorld; +import static com.matt.forgehax.util.entity.EntityUtils.isAboveWater; +import static com.matt.forgehax.util.entity.EntityUtils.isInWater; import static net.minecraft.util.math.RayTraceResult.Type; import com.matt.forgehax.util.command.Setting; @@ -19,102 +22,113 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; -/** Created by Babbaj on 9/4/2017. TODO: check all 4 collision box corners */ +/** + * Created by Babbaj on 9/4/2017. TODO: check all 4 collision box corners + */ @RegisterMod public class AutoBucketFallMod extends ToggleMod { + public AutoBucketFallMod() { super(Category.PLAYER, "AutoBucket", false, "Automatically place bucket to reset fall damage"); } - + public final Setting preHeight = - getCommandStub() - .builders() - .newSettingBuilder() - .name("PreHeight") - .description("how far below to check before preparing") - .defaultTo(10D) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("PreHeight") + .description("how far below to check before preparing") + .defaultTo(10D) + .build(); public final Setting settingFallHeight = - getCommandStub() - .builders() - .newSettingBuilder() - .name("height") - .description("minimum fall distance to work") - .defaultTo(15D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("height") + .description("minimum fall distance to work") + .defaultTo(15D) + .build(); + private ItemStack WATER_BUCKET = new ItemStack(Items.WATER_BUCKET); - + @SubscribeEvent public void onClientTick(TickEvent.ClientTickEvent event) { if (getLocalPlayer() == null - || getLocalPlayer().fallDistance < settingFallHeight.getAsDouble() - || !getLocalPlayer().inventory.hasItemStack(WATER_BUCKET) - || isInWater(getLocalPlayer()) - || isAboveWater(getLocalPlayer())) return; - + || getLocalPlayer().fallDistance < settingFallHeight.getAsDouble() + || !getLocalPlayer().inventory.hasItemStack(WATER_BUCKET) + || isInWater(getLocalPlayer()) + || isAboveWater(getLocalPlayer())) { + return; + } + Vec3d playerPos = getLocalPlayer().getPositionVector(); Vec3d rayTraceBucket = new Vec3d(playerPos.x, playerPos.y - 5, playerPos.z); Vec3d rayTracePre = - new Vec3d( - playerPos.x, - playerPos.y - preHeight.getAsDouble(), - playerPos.z); // find the ground before the player is ready to water bucket - + new Vec3d( + playerPos.x, + playerPos.y - preHeight.getAsDouble(), + playerPos.z); // find the ground before the player is ready to water bucket + RayTraceResult result = MC.world.rayTraceBlocks(playerPos, rayTraceBucket, true); RayTraceResult resultPre = MC.world.rayTraceBlocks(playerPos, rayTracePre, true); - + if (resultPre != null - && resultPre.typeOfHit.equals(Type.BLOCK) - && !(getWorld().getBlockState(resultPre.getBlockPos()).getBlock() - instanceof BlockLiquid)) { // set the pitch early to not get cucked by ncp + && resultPre.typeOfHit.equals(Type.BLOCK) + && !(getWorld().getBlockState(resultPre.getBlockPos()).getBlock() + instanceof BlockLiquid)) { // set the pitch early to not get cucked by ncp getLocalPlayer().prevRotationPitch = 90f; getLocalPlayer().rotationPitch = 90f; - + int bucketSlot = findBucketHotbar(); - if (bucketSlot == -1) bucketSlot = findBucketInv(); + if (bucketSlot == -1) { + bucketSlot = findBucketInv(); + } if (bucketSlot > 8) { swap( - bucketSlot, - getLocalPlayer().inventory.currentItem); // move bucket from inventory to hotbar + bucketSlot, + getLocalPlayer().inventory.currentItem); // move bucket from inventory to hotbar } else { MC.player.inventory.currentItem = bucketSlot; } } - + if (result != null - && result.typeOfHit.equals(Type.BLOCK) - && !(getWorld().getBlockState(result.getBlockPos()).getBlock() instanceof BlockLiquid)) { + && result.typeOfHit.equals(Type.BLOCK) + && !(getWorld().getBlockState(result.getBlockPos()).getBlock() instanceof BlockLiquid)) { getNetworkManager() - .sendPacket( - new CPacketPlayer.Rotation( - getLocalPlayer().rotationYaw, - 90, - getLocalPlayer().onGround)); // probably unnecessary but doing it anyways + .sendPacket( + new CPacketPlayer.Rotation( + getLocalPlayer().rotationYaw, + 90, + getLocalPlayer().onGround)); // probably unnecessary but doing it anyways getLocalPlayer().prevRotationPitch = 90f; getLocalPlayer().rotationPitch = 90f; - + // printMessage("Attempted to place water bucket"); MC.playerController.processRightClick(getLocalPlayer(), getWorld(), EnumHand.MAIN_HAND); } } - + private int findBucketInv() { return getLocalPlayer().inventory.getSlotFor(WATER_BUCKET); // find bucket in entire inventory } - + private int findBucketHotbar() { for (int i = 0; i < 9; i++) // iterate through hotbar slots - if (getLocalPlayer().inventory.getStackInSlot(i).getItem() == Items.WATER_BUCKET) return i; + { + if (getLocalPlayer().inventory.getStackInSlot(i).getItem() == Items.WATER_BUCKET) { + return i; + } + } return -1; } - + private void swap(final int slot, final int hotbarNum) { MC.playerController.windowClick( - getLocalPlayer().inventoryContainer.windowId, - slot, - hotbarNum, - ClickType.SWAP, - getLocalPlayer()); + getLocalPlayer().inventoryContainer.windowId, + slot, + hotbarNum, + ClickType.SWAP, + getLocalPlayer()); } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoCrystalMod.java b/src/main/java/com/matt/forgehax/mods/AutoCrystalMod.java index bd0dd8908..3ddcfa332 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoCrystalMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoCrystalMod.java @@ -1,6 +1,8 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getNetworkManager; +import static com.matt.forgehax.Helper.getWorld; import com.matt.forgehax.events.LocalPlayerUpdateEvent; import com.matt.forgehax.util.SimpleTimer; @@ -19,121 +21,126 @@ import net.minecraft.util.math.Vec3d; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 3/12/2018 by exkerbinator */ +/** + * Created on 3/12/2018 by exkerbinator + */ @RegisterMod public class AutoCrystalMod extends ToggleMod { + public final Setting maxDistance = - getCommandStub() - .builders() - .newSettingBuilder() - .name("maxDistance") - .description("maximum distance to detonate crystals") - .defaultTo(3f) - .min(0f) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("maxDistance") + .description("maximum distance to detonate crystals") + .defaultTo(3f) + .min(0f) + .build(); + public final Setting minDistance = - getCommandStub() - .builders() - .newSettingBuilder() - .name("minDistance") - .description("minimum distance to detonate crystals") - .defaultTo(0f) - .min(0f) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("minDistance") + .description("minimum distance to detonate crystals") + .defaultTo(0f) + .min(0f) + .build(); + public final Setting minHeight = - getCommandStub() - .builders() - .newSettingBuilder() - .name("minHeight") - .description("detonate crystals with a relative y coord greater than this value") - .defaultTo(-5f) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("minHeight") + .description("detonate crystals with a relative y coord greater than this value") + .defaultTo(-5f) + .build(); + public final Setting delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("delay") - .description("delay between detonations in ms") - .defaultTo(10) - .min(0) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("delay") + .description("delay between detonations in ms") + .defaultTo(10) + .min(0) + .build(); + public final Setting checkEnemy = - getCommandStub() - .builders() - .newSettingBuilder() - .name("checkEnemy") - .description("only detonate crystals close to enemy players") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("checkEnemy") + .description("only detonate crystals close to enemy players") + .defaultTo(true) + .build(); + public final Setting maxEnemyDistance = - getCommandStub() - .builders() - .newSettingBuilder() - .name("maxEnemyDistance") - .description("maximum distance from crystal to enemy") - .defaultTo(10f) - .min(0f) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("maxEnemyDistance") + .description("maximum distance from crystal to enemy") + .defaultTo(10f) + .min(0f) + .build(); + public AutoCrystalMod() { super(Category.COMBAT, "AutoCrystal", false, "Automatically detonates nearby end crystals"); } - + private SimpleTimer timer = new SimpleTimer(); - + @Override public void onEnabled() { timer.start(); } - + private Predicate playerWithinDistance(float dist) { return k -> getLocalPlayer().getDistanceSq(k) < dist * dist; } - + private boolean enemyWithinDistance(Entity e, float dist) { Vec3d delta = new Vec3d(dist, dist, dist); AxisAlignedBB bb = - new AxisAlignedBB(e.getPositionVector().subtract(delta), e.getPositionVector().add(delta)); + new AxisAlignedBB(e.getPositionVector().subtract(delta), e.getPositionVector().add(delta)); return getWorld() - .getEntitiesWithinAABB(EntityPlayer.class, bb) - .stream() - .filter(p -> !p.isEntityEqual(getLocalPlayer())) - .anyMatch(p -> e.getDistanceSq(p) < dist * dist); + .getEntitiesWithinAABB(EntityPlayer.class, bb) + .stream() + .filter(p -> !p.isEntityEqual(getLocalPlayer())) + .anyMatch(p -> e.getDistanceSq(p) < dist * dist); } - + @SubscribeEvent public void onTick(LocalPlayerUpdateEvent event) { if (getWorld() != null && getLocalPlayer() != null) { // Short-circuit if the timer check will fail - if (!timer.hasTimeElapsed(delay.get())) return; - + if (!timer.hasTimeElapsed(delay.get())) { + return; + } + Vec3d delta = new Vec3d(maxDistance.get(), maxDistance.get(), maxDistance.get()); AxisAlignedBB bb = - new AxisAlignedBB( - getLocalPlayer().getPositionVector().subtract(delta), - getLocalPlayer().getPositionVector().add(delta)); + new AxisAlignedBB( + getLocalPlayer().getPositionVector().subtract(delta), + getLocalPlayer().getPositionVector().add(delta)); getWorld() - .getEntitiesWithinAABB(EntityEnderCrystal.class, bb) - .stream() - // Re-check timer, since it may have been reset in a previous iteration - .filter(__ -> timer.hasTimeElapsed(delay.get())) - .filter( - e -> - e.getPosition().getY() - getLocalPlayer().getPosition().getY() >= minHeight.get()) - .filter(playerWithinDistance(maxDistance.get())) - .filter(playerWithinDistance(minDistance.get()).negate()) - .filter(e -> !checkEnemy.get() || enemyWithinDistance(e, maxEnemyDistance.get())) - .forEach( - e -> { - getNetworkManager().sendPacket(new CPacketUseEntity(e)); - getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); - timer.start(); - }); + .getEntitiesWithinAABB(EntityEnderCrystal.class, bb) + .stream() + // Re-check timer, since it may have been reset in a previous iteration + .filter(__ -> timer.hasTimeElapsed(delay.get())) + .filter( + e -> + e.getPosition().getY() - getLocalPlayer().getPosition().getY() >= minHeight.get()) + .filter(playerWithinDistance(maxDistance.get())) + .filter(playerWithinDistance(minDistance.get()).negate()) + .filter(e -> !checkEnemy.get() || enemyWithinDistance(e, maxEnemyDistance.get())) + .forEach( + e -> { + getNetworkManager().sendPacket(new CPacketUseEntity(e)); + getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); + timer.start(); + }); } } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoEatMod.java b/src/main/java/com/matt/forgehax/mods/AutoEatMod.java index 61a16fd56..9ef65cef3 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoEatMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoEatMod.java @@ -4,7 +4,6 @@ import static com.matt.forgehax.Helper.getPlayerController; import static com.matt.forgehax.Helper.getWorld; -import com.google.common.base.Predicates; import com.google.common.collect.Streams; import com.matt.forgehax.asm.events.ItemStoppedUsedEvent; import com.matt.forgehax.asm.reflection.FastReflection.Fields; @@ -33,106 +32,111 @@ @RegisterMod public class AutoEatMod extends ToggleMod { + private static final List BAD_POTIONS = - Streams.stream(Potion.REGISTRY).filter(Potion::isBadEffect).collect(Collectors.toList()); - + Streams.stream(Potion.REGISTRY).filter(Potion::isBadEffect).collect(Collectors.toList()); + enum Sorting { POINTS, SATURATION, RATIO, ; } - + private final Setting sorting = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("sorting") - .description("Method used to find best food item to use") - .defaultTo(Sorting.RATIO) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("sorting") + .description("Method used to find best food item to use") + .defaultTo(Sorting.RATIO) + .build(); + private final Setting fail_safe_multiplier = - getCommandStub() - .builders() - .newSettingBuilder() - .name("fail-safe-multiplier") - .description("Will attempt to eat again after use ticks * multiplier has elapsed. Set to 0 to disable") - .defaultTo(10) - .min(0) - .max(20) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("fail-safe-multiplier") + .description( + "Will attempt to eat again after use ticks * multiplier has elapsed. Set to 0 to disable") + .defaultTo(10) + .min(0) + .max(20) + .build(); + private final Setting select_wait = - getCommandStub() - .builders() - .newSettingBuilder() - .name("select-wait") - .description("Number of ticks to wait before starting to eat a food item after switching to it in the hotbar.") - .defaultTo(10) - .min(0) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("select-wait") + .description( + "Number of ticks to wait before starting to eat a food item after switching to it in the hotbar.") + .defaultTo(10) + .min(0) + .build(); + private ItemFood food = null; private boolean eating = false; private int eatingTicks = 0; private int selectedTicks = 0; private int lastHotbarIndex = -1; - + public AutoEatMod() { super(Category.PLAYER, "AutoEat", false, "Auto eats when you get hungry"); } - + private void reset() { - if(eatingTicks > 0) MC.addScheduledTask(() -> MinecraftForge.EVENT_BUS.post(new ForgeHaxEvent(Type.EATING_STOP))); + if (eatingTicks > 0) { + MC.addScheduledTask(() -> MinecraftForge.EVENT_BUS.post(new ForgeHaxEvent(Type.EATING_STOP))); + } food = null; eating = false; eatingTicks = 0; selectedTicks = 0; } - + private boolean isFoodItem(InvItem inv) { return inv.getItem() instanceof ItemFood; } - + private boolean isFishFood(InvItem inv) { return inv.getItem() instanceof ItemFishFood; } - + private ItemFood toFood(InvItem inv) { return (ItemFood) inv.getItem(); } - + private ItemFishFood toFishFood(InvItem inv) { return (ItemFishFood) inv.getItem(); } - + private boolean isGoodFood(InvItem inv) { PotionEffect pe = Fields.ItemFood_potionId.get(inv.getItem()); return pe == null || isFishFood(inv) - ? !FishType.PUFFERFISH.equals(FishType.byItemStack(inv.getItemStack())) - : BAD_POTIONS.stream().filter(Potion::isBadEffect).noneMatch(pe.getPotion()::equals); + ? !FishType.PUFFERFISH.equals(FishType.byItemStack(inv.getItemStack())) + : BAD_POTIONS.stream().filter(Potion::isBadEffect).noneMatch(pe.getPotion()::equals); } - + private int getHealAmount(InvItem inv) { return toFood(inv).getHealAmount(inv.getItemStack()); } - + private double getSaturationAmount(InvItem inv) { return toFood(inv).getSaturationModifier(inv.getItemStack()); } - + private int getHealthLevel(InvItem inv) { return Math.min(getLocalPlayer().getFoodStats().getFoodLevel() + getHealAmount(inv), 20); } - + private double getSaturationLevel(InvItem inv) { return Math.min( - getLocalPlayer().getFoodStats().getSaturationLevel() - + getHealAmount(inv) * getSaturationAmount(inv) * 2.D, - 20.D); + getLocalPlayer().getFoodStats().getSaturationLevel() + + getHealAmount(inv) * getSaturationAmount(inv) * 2.D, + 20.D); } - + private double getPreferenceValue(InvItem inv) { switch (sorting.get()) { case POINTS: @@ -144,96 +148,107 @@ private double getPreferenceValue(InvItem inv) { return (getHealAmount(inv) * getSaturationAmount(inv) * 2.D) / getHealAmount(inv); } } - + private boolean shouldEat(InvItem inv) { return getLocalPlayer().getFoodStats().getFoodLevel() + getHealAmount(inv) < 20; } - + private boolean checkFailsafe() { - return (fail_safe_multiplier.get() == 0 || eatingTicks < food.itemUseDuration * fail_safe_multiplier.get()); + return (fail_safe_multiplier.get() == 0 + || eatingTicks < food.itemUseDuration * fail_safe_multiplier.get()); } - + @Override protected void onEnabled() { reset(); selectedTicks = 0; lastHotbarIndex = -1; } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { - if (getLocalPlayer().isCreative()) return; - + if (getLocalPlayer().isCreative()) { + return; + } + int currentSelected = LocalPlayerInventory.getSelected().getIndex(); - + boolean wasEating = eating; eating = false; - + LocalPlayerInventory.getHotbarInventory() - .stream() - .filter(InvItem::nonEmpty) - .filter(this::isFoodItem) - .filter(this::isGoodFood) - .max( - Comparator.comparingDouble(this::getPreferenceValue) - .thenComparing(LocalPlayerInventory::getHotbarDistance)) - .filter(this::shouldEat) - .ifPresent( - best -> { - food = (ItemFood) best.getItem(); - - LocalPlayerInventory.setSelected(best, ticks -> !eating); - - eating = true; - - if(!checkFailsafe()) { - reset(); - eating = true; - return; - } - - if(currentSelected != best.getIndex()) { - MinecraftForge.EVENT_BUS.post(new ForgeHaxEvent(Type.EATING_SELECT_FOOD)); - lastHotbarIndex = best.getIndex(); - selectedTicks = 0; - } - - if(selectedTicks > select_wait.get()) { - if(!wasEating) MinecraftForge.EVENT_BUS.post(new ForgeHaxEvent(Type.EATING_START)); - - Fields.Minecraft_rightClickDelayTimer.set(MC, 4); - getPlayerController().processRightClick(getLocalPlayer(), getWorld(), EnumHand.MAIN_HAND); - - ++eatingTicks; - } - }); - - if(lastHotbarIndex != -1) { - if(lastHotbarIndex == LocalPlayerInventory.getSelected().getIndex()) + .stream() + .filter(InvItem::nonEmpty) + .filter(this::isFoodItem) + .filter(this::isGoodFood) + .max( + Comparator.comparingDouble(this::getPreferenceValue) + .thenComparing(LocalPlayerInventory::getHotbarDistance)) + .filter(this::shouldEat) + .ifPresent( + best -> { + food = (ItemFood) best.getItem(); + + LocalPlayerInventory.setSelected(best, ticks -> !eating); + + eating = true; + + if (!checkFailsafe()) { + reset(); + eating = true; + return; + } + + if (currentSelected != best.getIndex()) { + MinecraftForge.EVENT_BUS.post(new ForgeHaxEvent(Type.EATING_SELECT_FOOD)); + lastHotbarIndex = best.getIndex(); + selectedTicks = 0; + } + + if (selectedTicks > select_wait.get()) { + if (!wasEating) { + MinecraftForge.EVENT_BUS.post(new ForgeHaxEvent(Type.EATING_START)); + } + + Fields.Minecraft_rightClickDelayTimer.set(MC, 4); + getPlayerController() + .processRightClick(getLocalPlayer(), getWorld(), EnumHand.MAIN_HAND); + + ++eatingTicks; + } + }); + + if (lastHotbarIndex != -1) { + if (lastHotbarIndex == LocalPlayerInventory.getSelected().getIndex()) { selectedTicks++; - else + } else { selectedTicks = 0; + } } - + lastHotbarIndex = LocalPlayerInventory.getSelected().getIndex(); - - if (wasEating && !eating) reset(); + + if (wasEating && !eating) { + reset(); + } } - + @SubscribeEvent public void onStopUse(ItemStoppedUsedEvent event) { if (food != null && eating && eatingTicks > 0) { - if (checkFailsafe()) + if (checkFailsafe()) { event.setCanceled(true); - else + } else { reset(); + } } } - + @SubscribeEvent(priority = EventPriority.HIGHEST) public void onGuiOpened(GuiOpenEvent event) { // process keys and mouse input even if this gui is open - if (eating && getWorld() != null && getLocalPlayer() != null && event.getGui() != null) + if (eating && getWorld() != null && getLocalPlayer() != null && event.getGui() != null) { event.getGui().allowUserInput = true; + } } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoElytra.java b/src/main/java/com/matt/forgehax/mods/AutoElytra.java index f31ab3da1..b72519b05 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoElytra.java +++ b/src/main/java/com/matt/forgehax/mods/AutoElytra.java @@ -3,8 +3,11 @@ import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; -/** Created on 8/17/2017 by fr1kin */ +/** + * Created on 8/17/2017 by fr1kin + */ public class AutoElytra extends ToggleMod { + public AutoElytra() { super(Category.PLAYER, "AutoElytra", false, "Automatically deploy elytra"); } diff --git a/src/main/java/com/matt/forgehax/mods/AutoFishMod.java b/src/main/java/com/matt/forgehax/mods/AutoFishMod.java index 0e64c6024..5158bbbb8 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoFishMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoFishMod.java @@ -19,92 +19,97 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.InputEvent; -/** Created on 9/2/2016 by fr1kin */ +/** + * Created on 9/2/2016 by fr1kin + */ @RegisterMod public class AutoFishMod extends ToggleMod { + private int ticksCastDelay = 0; private int ticksHookDeployed = 0; - + private boolean previouslyHadRodEquipped = false; - + public final Setting casting_delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("casting_delay") - .description("Number of ticks to wait after casting the rod to attempt a recast") - .defaultTo(20) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("casting_delay") + .description("Number of ticks to wait after casting the rod to attempt a recast") + .defaultTo(20) + .build(); + public final Setting max_sound_distance = - getCommandStub() - .builders() - .newSettingBuilder() - .name("max_sound_distance") - .description( - "Maximum distance between the splash sound and hook entity allowed (set to 0 to disable this feature)") - .defaultTo(2.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("max_sound_distance") + .description( + "Maximum distance between the splash sound and hook entity allowed (set to 0 to disable this feature)") + .defaultTo(2.D) + .build(); + public final Setting fail_safe_time = - getCommandStub() - .builders() - .newSettingBuilder() - .name("fail_safe_time") - .description( - "Maximum amount of time (in ticks) allowed until the hook is pulled in (set to 0 to disable this feature)") - .defaultTo(600) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("fail_safe_time") + .description( + "Maximum amount of time (in ticks) allowed until the hook is pulled in (set to 0 to disable this feature)") + .defaultTo(600) + .build(); + public AutoFishMod() { super(Category.PLAYER, "AutoFish", false, "Auto fish"); } - + private boolean isCorrectSplashPacket(SPacketSoundEffect packet) { EntityPlayerSP me = getLocalPlayer(); return packet.getSound().equals(SoundEvents.ENTITY_BOBBER_SPLASH) - && (me != null - && me.fishEntity != null - && (max_sound_distance.get() == 0 - || // disables this check - (me.fishEntity - .getPositionVector() - .distanceTo(new Vec3d(packet.getX(), packet.getY(), packet.getZ())) - <= max_sound_distance.get()))); + && (me != null + && me.fishEntity != null + && (max_sound_distance.get() == 0 + || // disables this check + (me.fishEntity + .getPositionVector() + .distanceTo(new Vec3d(packet.getX(), packet.getY(), packet.getZ())) + <= max_sound_distance.get()))); } - + private void rightClick() { if (ticksCastDelay <= 0) { // to prevent the fishing rod from being spammed when in hand FastReflection.Methods.Minecraft_rightClickMouse.invoke(MC); ticksCastDelay = casting_delay.get(); } } - + private void resetLocals() { ticksCastDelay = 0; ticksHookDeployed = 0; previouslyHadRodEquipped = false; } - + @Override public void onEnabled() { resetLocals(); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { EntityPlayer me = getLocalPlayer(); ItemStack heldStack = me.getHeldItemMainhand(); - + // update tick delay if hook is deployed - if (ticksCastDelay > casting_delay.get()) + if (ticksCastDelay > casting_delay.get()) { ticksCastDelay = casting_delay.get(); // greater than current delay, set to the current delay - else if (ticksCastDelay > 0) --ticksCastDelay; - + } else if (ticksCastDelay > 0) { + --ticksCastDelay; + } + // check if player is holding a fishing rod if (heldStack != null - && // item not null (shouldn't be, but I am being safe) - heldStack.getItem() instanceof ItemFishingRod // item being held is a fishing rod + && // item not null (shouldn't be, but I am being safe) + heldStack.getItem() instanceof ItemFishingRod // item being held is a fishing rod ) { if (!previouslyHadRodEquipped) { ticksCastDelay = casting_delay.get(); @@ -115,22 +120,24 @@ public void onUpdate(LocalPlayerUpdateEvent event) { } else { // hook is deployed and rod was not previously equipped // increment the number of ticks that the hook entity has existed ++ticksHookDeployed; - + if (fail_safe_time.get() != 0 && (ticksHookDeployed > fail_safe_time.get())) { rightClick(); // reel in hook if the fail safe time has passed resetLocals(); } } - } else resetLocals(); + } else { + resetLocals(); + } } - + @SubscribeEvent public void onMouseEvent(InputEvent.MouseInputEvent event) { if (MC.gameSettings.keyBindUseItem.isKeyDown() && ticksHookDeployed > 0) { ticksCastDelay = casting_delay.get(); } } - + @SubscribeEvent public void onPacketIncoming(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketSoundEffect) { diff --git a/src/main/java/com/matt/forgehax/mods/AutoHotbarReplenish.java b/src/main/java/com/matt/forgehax/mods/AutoHotbarReplenish.java index 2ae61c4ee..395149b29 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoHotbarReplenish.java +++ b/src/main/java/com/matt/forgehax/mods/AutoHotbarReplenish.java @@ -21,168 +21,181 @@ @RegisterMod public class AutoHotbarReplenish extends ToggleMod { + private final Setting durability_threshold = - getCommandStub() - .builders() - .newSettingBuilder() - .name("durability-threshold") - .description("Will auto replace tools when they hit this damage value") - .defaultTo(5) - .min(0) - .max((int) Short.MAX_VALUE) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("durability-threshold") + .description("Will auto replace tools when they hit this damage value") + .defaultTo(5) + .min(0) + .max((int) Short.MAX_VALUE) + .build(); + private final Setting stack_threshold = - getCommandStub() - .builders() - .newSettingBuilder() - .name("stack-threshold") - .description("Will replace stacks when there only remains this many") - .defaultTo(10) - .min(1) - .max((int) Short.MAX_VALUE) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("stack-threshold") + .description("Will replace stacks when there only remains this many") + .defaultTo(10) + .min(1) + .max((int) Short.MAX_VALUE) + .build(); + private final Setting tick_delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("tick-delay") - .description( - "Number of ticks between each window click packet. 0 will have no limit and a negative value will send n packets per tick") - .defaultTo(1) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("tick-delay") + .description( + "Number of ticks between each window click packet. 0 will have no limit and a negative value will send n packets per tick") + .defaultTo(1) + .build(); + private TaskChain tasks = TaskChain.empty(); private long tickCount = 0; - + public AutoHotbarReplenish() { super( - Category.PLAYER, - "AutoHotbarReplenish", - false, - "Will replenish tools or block stacks automatically"); + Category.PLAYER, + "AutoHotbarReplenish", + false, + "Will replenish tools or block stacks automatically"); } - + private boolean processing(int index) { - if (tick_delay.get() == 0) return true; // process all - else if (tick_delay.get() < 0) + if (tick_delay.get() == 0) { + return true; // process all + } else if (tick_delay.get() < 0) { return index < Math.abs(tick_delay.get()); // process n tasks per tick - else return index == 0 && tickCount % tick_delay.get() == 0; + } else { + return index == 0 && tickCount % tick_delay.get() == 0; + } } - + private boolean isMonitoring(InvItem item) { return item.isItemDamageable() || item.isStackable(); } - + private boolean isAboveThreshold(InvItem item) { return item.isItemDamageable() - ? item.getDurability() > durability_threshold.get() - : item.getStackCount() > stack_threshold.get(); + ? item.getDurability() > durability_threshold.get() + : item.getStackCount() > stack_threshold.get(); } - + private int getDamageOrCount(InvItem item) { return item.isNull() - ? 0 - : item.isItemDamageable() ? item.getDurability() : item.getStackCount(); + ? 0 + : item.isItemDamageable() ? item.getDurability() : item.getStackCount(); } - + private void tryPlacingHeldItem() { InvItem holding = LocalPlayerInventory.getMouseHeld(); - + if (holding.isEmpty()) // all is good - return; - + { + return; + } + InvItem item; if (holding.isDamageable()) { item = - LocalPlayerInventory.getSlotStorageInventory() - .stream() - .filter(InvItem::isNull) - .findAny() - .orElse(InvItem.EMPTY); + LocalPlayerInventory.getSlotStorageInventory() + .stream() + .filter(InvItem::isNull) + .findAny() + .orElse(InvItem.EMPTY); } else { item = - LocalPlayerInventory.getSlotStorageInventory() - .stream() - .filter(inv -> inv.isNull() || holding.isItemsEqual(inv)) - .filter(inv -> inv.isNull() || !inv.isStackMaxed()) - .max(Comparator.comparing(InvItem::getStackCount)) - .orElse(InvItem.EMPTY); + LocalPlayerInventory.getSlotStorageInventory() + .stream() + .filter(inv -> inv.isNull() || holding.isItemsEqual(inv)) + .filter(inv -> inv.isNull() || !inv.isStackMaxed()) + .max(Comparator.comparing(InvItem::getStackCount)) + .orElse(InvItem.EMPTY); } - - if (item == InvItem.EMPTY) click(holding, 0, ClickType.PICKUP); - else { + + if (item == InvItem.EMPTY) { + click(holding, 0, ClickType.PICKUP); + } else { click(item, 0, ClickType.PICKUP); - if (LocalPlayerInventory.getMouseHeld().nonEmpty()) throw new RuntimeException(); + if (LocalPlayerInventory.getMouseHeld().nonEmpty()) { + throw new RuntimeException(); + } } } - + @Override protected void onDisabled() { MC.addScheduledTask( - () -> { - tasks = TaskChain.empty(); - tickCount = 0; - }); + () -> { + tasks = TaskChain.empty(); + tickCount = 0; + }); } - + @SubscribeEvent public void onTick(ClientTickEvent event) { - if (!Phase.START.equals(event.phase) || getLocalPlayer() == null) return; - + if (!Phase.START.equals(event.phase) || getLocalPlayer() == null) { + return; + } + // only process when a gui isn't opened by the player - if (MC.currentScreen != null) return; - + if (MC.currentScreen != null) { + return; + } + if (tasks.isEmpty()) { final List slots = LocalPlayerInventory.getSlotStorageInventory(); - + tasks = - LocalPlayerInventory.getHotbarInventory() - .stream() - .filter(InvItem::nonNull) - .filter(this::isMonitoring) - .filter(item -> !isAboveThreshold(item)) - .filter( - item -> + LocalPlayerInventory.getHotbarInventory() + .stream() + .filter(InvItem::nonNull) + .filter(this::isMonitoring) + .filter(item -> !isAboveThreshold(item)) + .filter( + item -> + slots + .stream() + .filter(this::isMonitoring) + .filter(inv -> !inv.isItemDamageable() || isAboveThreshold(inv)) + .anyMatch(item::isItemsEqual)) + .max(Comparator.comparingInt(LocalPlayerInventory::getHotbarDistance)) + .map( + hotbarItem -> + TaskChain.builder() + .then( + () -> { + // pick up item + + verifyHotbar(hotbarItem); + click( slots - .stream() - .filter(this::isMonitoring) - .filter(inv -> !inv.isItemDamageable() || isAboveThreshold(inv)) - .anyMatch(item::isItemsEqual)) - .max(Comparator.comparingInt(LocalPlayerInventory::getHotbarDistance)) - .map( - hotbarItem -> - TaskChain.builder() - .then( - () -> { - // pick up item - - verifyHotbar(hotbarItem); - click( - slots - .stream() - .filter(InvItem::nonNull) - .filter(this::isMonitoring) - .filter(hotbarItem::isItemsEqual) - .filter(inv -> !inv.isDamageable() || isAboveThreshold(inv)) - .max(Comparator.comparingInt(this::getDamageOrCount)) - .orElseThrow(RuntimeException::new), - 0, - ClickType.PICKUP); - }) - .then( - () -> { - // place item into hotbar - - verifyHotbar(hotbarItem); - click(hotbarItem, 0, ClickType.PICKUP); - }) - .then(this::tryPlacingHeldItem) - .build()) - .orElse(TaskChain.empty()); + .stream() + .filter(InvItem::nonNull) + .filter(this::isMonitoring) + .filter(hotbarItem::isItemsEqual) + .filter(inv -> !inv.isDamageable() || isAboveThreshold(inv)) + .max(Comparator.comparingInt(this::getDamageOrCount)) + .orElseThrow(RuntimeException::new), + 0, + ClickType.PICKUP); + }) + .then( + () -> { + // place item into hotbar + + verifyHotbar(hotbarItem); + click(hotbarItem, 0, ClickType.PICKUP); + }) + .then(this::tryPlacingHeldItem) + .build()) + .orElse(TaskChain.empty()); } - + // process the next click task int n = 0; while (processing(n++) && tasks.hasNext()) { @@ -192,45 +205,50 @@ public void onTick(ClientTickEvent event) { tasks = TaskChain.singleton(this::tryPlacingHeldItem); } } - + ++tickCount; } - + // // // - + private static void verifyHotbar(InvItem hotbarItem) { InvItem current = LocalPlayerInventory.getHotbarInventory().get(hotbarItem.getIndex()); - if (!hotbarItem.isItemsEqual(current)) throw new IllegalArgumentException(); + if (!hotbarItem.isItemsEqual(current)) { + throw new IllegalArgumentException(); + } } - - private static void verifyHeldItem(InvItem staticItem) {} - + + private static void verifyHeldItem(InvItem staticItem) { + } + private static void clickWindow( - int slotIdIn, int usedButtonIn, ClickType modeIn, ItemStack clickedItemIn) { + int slotIdIn, int usedButtonIn, ClickType modeIn, ItemStack clickedItemIn) { getNetworkManager() - .sendPacket( - new CPacketClickWindow( - 0, - slotIdIn, - usedButtonIn, - modeIn, - clickedItemIn, - LocalPlayerInventory.getOpenContainer() - .getNextTransactionID(LocalPlayerInventory.getInventory()))); + .sendPacket( + new CPacketClickWindow( + 0, + slotIdIn, + usedButtonIn, + modeIn, + clickedItemIn, + LocalPlayerInventory.getOpenContainer() + .getNextTransactionID(LocalPlayerInventory.getInventory()))); } - + private static ItemStack click(InvItem item, int usedButtonIn, ClickType modeIn) { - if (item.getIndex() == -1) throw new IllegalArgumentException(); + if (item.getIndex() == -1) { + throw new IllegalArgumentException(); + } ItemStack ret; clickWindow( - item.getSlotNumber(), - usedButtonIn, - modeIn, - ret = - LocalPlayerInventory.getOpenContainer() - .slotClick(item.getSlotNumber(), usedButtonIn, modeIn, getLocalPlayer())); + item.getSlotNumber(), + usedButtonIn, + modeIn, + ret = + LocalPlayerInventory.getOpenContainer() + .slotClick(item.getSlotNumber(), usedButtonIn, modeIn, getLocalPlayer())); return ret; } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoKey.java b/src/main/java/com/matt/forgehax/mods/AutoKey.java index f1a7fe6af..d8a973483 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoKey.java +++ b/src/main/java/com/matt/forgehax/mods/AutoKey.java @@ -10,146 +10,156 @@ import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.function.BiConsumer; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created by Babbaj on 1/30/2018. */ +/** + * Created by Babbaj on 1/30/2018. + */ @RegisterMod public class AutoKey extends ToggleMod { - + public AutoKey() { super(Category.PLAYER, "AutoKey", false, "Automatically click/press keys"); } - + private final Setting delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("delay") - .description("delay(ms) between clicks") - .defaultTo(500) // 500 ms - .min(0) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("delay") + .description("delay(ms) between clicks") + .defaultTo(500) // 500 ms + .min(0) + .build(); + private static Setting holdTime; // static to allow easy access from ClickMode - + { holdTime = - getCommandStub() - .builders() - .newSettingBuilder() - .name("holdTime") - .description("how long to hold button for tap") - .defaultTo(150) // approximate minimum for reliable key pressing - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("holdTime") + .description("how long to hold button for tap") + .defaultTo(150) // approximate minimum for reliable key pressing + .build(); } - + // TODO: make serializable and save as json private final Map activeKeys = new HashMap<>(); - + private long lastTimeMillis; - + @SubscribeEvent public void onPlayerUpdate(LocalPlayerUpdateEvent event) { final int lastClick = (int) (System.currentTimeMillis() - lastTimeMillis); - if (lastClick >= delay.get()) lastTimeMillis = System.currentTimeMillis(); - + if (lastClick >= delay.get()) { + lastTimeMillis = System.currentTimeMillis(); + } + activeKeys.forEach((key, mode) -> mode.apply(key, lastClick)); } - + @Override public void onLoad() { // add a key getCommandStub() - .builders() - .newCommandBuilder() - .name("addKey") - .description("add a key to the active key list - (ex: addKey \"jump\" \"hold\"") - .processor( - data -> { - data.requiredArguments(2); - KeyBindingHandler key = Bindings.getKey(data.getArgumentAsString(0)); - if (key == null) { - Helper.printMessage("Unknown key: %s", data.getArgumentAsString(0)); - return; - } - - String mode = data.getArgumentAsString(1); - ClickMode clickMode = - Arrays.stream(ClickMode.values()) - .filter(m -> m.toString().toLowerCase().contains(mode.toLowerCase())) - .findFirst() - .orElseGet( - () -> { - Helper.printMessage("Unknown mode, defaulting to tap"); - return ClickMode.TAP; - }); - activeKeys.put(key, clickMode); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("addKey") + .description("add a key to the active key list - (ex: addKey \"jump\" \"hold\"") + .processor( + data -> { + data.requiredArguments(2); + KeyBindingHandler key = Bindings.getKey(data.getArgumentAsString(0)); + if (key == null) { + Helper.printMessage("Unknown key: %s", data.getArgumentAsString(0)); + return; + } + + String mode = data.getArgumentAsString(1); + ClickMode clickMode = + Arrays.stream(ClickMode.values()) + .filter(m -> m.toString().toLowerCase().contains(mode.toLowerCase())) + .findFirst() + .orElseGet( + () -> { + Helper.printMessage("Unknown mode, defaulting to tap"); + return ClickMode.TAP; + }); + activeKeys.put(key, clickMode); + }) + .build(); + // remove all keys getCommandStub() - .builders() - .newCommandBuilder() - .name("clearKeys") - .description("clear all the active keys") - .processor( - data -> { - if (data.getArgumentCount() > 0) { - Helper.printMessage("Unexpected arguments!"); - return; - } - activeKeys.clear(); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("clearKeys") + .description("clear all the active keys") + .processor( + data -> { + if (data.getArgumentCount() > 0) { + Helper.printMessage("Unexpected arguments!"); + return; + } + activeKeys.clear(); + }) + .build(); + // remove a single key getCommandStub() - .builders() - .newCommandBuilder() - .name("clearKey") - .description("remove an active key - (ex: clearKey \"jump\"") - .processor( - data -> { - data.requiredArguments(1); - KeyBindingHandler key = Bindings.getKey(data.getArgumentAsString(0)); - ClickMode mode = activeKeys.remove(key); - if (mode != null) - Helper.printMessage("Removed key: %s", key.getBinding().getKeyDescription()); - else Helper.printMessage("Unknown key"); - }) - .build(); + .builders() + .newCommandBuilder() + .name("clearKey") + .description("remove an active key - (ex: clearKey \"jump\"") + .processor( + data -> { + data.requiredArguments(1); + KeyBindingHandler key = Bindings.getKey(data.getArgumentAsString(0)); + ClickMode mode = activeKeys.remove(key); + if (mode != null) { + Helper.printMessage("Removed key: %s", key.getBinding().getKeyDescription()); + } else { + Helper.printMessage("Unknown key"); + } + }) + .build(); } - + private static void incrementPressTime(KeyBindingHandler binding) { FastField field = FastReflection.Fields.Binding_pressTime; int currTime = field.get(binding.getBinding()); field.set(binding.getBinding(), currTime + 1); } - + private enum ClickMode { TAP( - (key, time) -> { - if (time < holdTime.getAsInteger()) { - incrementPressTime(key); - key.setPressed(true); - } else key.setPressed(false); - }), // hold key for at least 150ms - - HOLD( - (key, time) -> { + (key, time) -> { + if (time < holdTime.getAsInteger()) { incrementPressTime(key); key.setPressed(true); - }); // hold key forever - + } else { + key.setPressed(false); + } + }), // hold key for at least 150ms + + HOLD( + (key, time) -> { + incrementPressTime(key); + key.setPressed(true); + }); // hold key forever + BiConsumer clickAction; - + ClickMode(BiConsumer action) { this.clickAction = action; } - + public void apply(KeyBindingHandler key, int lastTime) { clickAction.accept(key, lastTime); } diff --git a/src/main/java/com/matt/forgehax/mods/AutoLog.java b/src/main/java/com/matt/forgehax/mods/AutoLog.java index 439a13d4c..962c83077 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoLog.java +++ b/src/main/java/com/matt/forgehax/mods/AutoLog.java @@ -17,64 +17,64 @@ @RegisterMod public class AutoLog extends ToggleMod { - + public AutoLog() { super(Category.COMBAT, "AutoLog", false, "automatically disconnect"); } - + public final Setting threshold = - getCommandStub() - .builders() - .newSettingBuilder() - .name("threshold") - .description("health to go down to to disconnect\"") - .defaultTo(0) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("threshold") + .description("health to go down to to disconnect\"") + .defaultTo(0) + .build(); public final Setting noTotem = - getCommandStub() - .builders() - .newSettingBuilder() - .name("NoTotem") - .description("disconnect if not holding a totem") - .defaultTo(false) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("NoTotem") + .description("disconnect if not holding a totem") + .defaultTo(false) + .build(); public final Setting disconnectOnNewPlayer = - getCommandStub() - .builders() - .newSettingBuilder() - .name("NewPlayer") - .description("Disconnect if a player enters render distance") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("NewPlayer") + .description("Disconnect if a player enters render distance") + .defaultTo(false) + .build(); + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { if (MC.player != null) { int health = (int) (MC.player.getHealth() + MC.player.getAbsorptionAmount()); if (health <= threshold.get() - || (noTotem.getAsBoolean() - && !((MC.player.getHeldItemOffhand().getItem() == Items.TOTEM_OF_UNDYING) - || MC.player.getHeldItemMainhand().getItem() == Items.TOTEM_OF_UNDYING))) { + || (noTotem.getAsBoolean() + && !((MC.player.getHeldItemOffhand().getItem() == Items.TOTEM_OF_UNDYING) + || MC.player.getHeldItemMainhand().getItem() == Items.TOTEM_OF_UNDYING))) { AutoReconnectMod.hasAutoLogged = true; getNetworkManager() - .closeChannel(new TextComponentString("Health too low (" + health + ")")); + .closeChannel(new TextComponentString("Health too low (" + health + ")")); disable(); } } } - + @SubscribeEvent public void onPacketRecieved(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketSpawnPlayer) { if (disconnectOnNewPlayer.getAsBoolean()) { AutoReconnectMod.hasAutoLogged = true; // dont automatically reconnect UUID id = ((SPacketSpawnPlayer) event.getPacket()).getUniqueId(); - + NetworkPlayerInfo info = MC.getConnection().getPlayerInfo(id); String name = info != null ? info.getGameProfile().getName() : "(Failed) " + id.toString(); - + getNetworkManager() - .closeChannel(new TextComponentString(name + " entered render distance")); + .closeChannel(new TextComponentString(name + " entered render distance")); disable(); } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoMend.java b/src/main/java/com/matt/forgehax/mods/AutoMend.java index 40691e093..32681829d 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoMend.java +++ b/src/main/java/com/matt/forgehax/mods/AutoMend.java @@ -16,48 +16,51 @@ @RegisterMod public class AutoMend extends ToggleMod { + public AutoMend() { super( - Category.PLAYER, - "AutoMend", - false, - "Automatically swap item in offhand with another valid item once its fully repaired"); + Category.PLAYER, + "AutoMend", + false, + "Automatically swap item in offhand with another valid item once its fully repaired"); } - + private boolean isMendable(InvItem item) { return item.isItemDamageable() - && EnchantmentHelper.getEnchantmentLevel(Enchantments.MENDING, item.getItemStack()) > 0; + && EnchantmentHelper.getEnchantmentLevel(Enchantments.MENDING, item.getItemStack()) > 0; } - + private boolean isDamaged(InvItem item) { return item.getItemStack().isItemDamaged(); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { - if (!(LocalPlayerInventory.getOpenContainer() instanceof ContainerPlayer)) return; - + if (!(LocalPlayerInventory.getOpenContainer() instanceof ContainerPlayer)) { + return; + } + InvItem current = LocalPlayerInventory.getSelected(); - + Optional.of(LocalPlayerInventory.getOffhand()) - .filter(this::isMendable) - .filter(item -> !isDamaged(item)) - .ifPresent( - offhand -> - LocalPlayerInventory.getSlotInventory() - .stream() - .filter(this::isMendable) - .filter(this::isDamaged) - .filter(inv -> inv.getIndex() != current.getIndex()) - .max(Comparator.comparingInt(InvItem::getDamage)) - .ifPresent( - inv -> { - // pick up - LocalPlayerInventory.sendWindowClick(inv, 0, ClickType.PICKUP); - // place in offhand - LocalPlayerInventory.sendWindowClick(offhand, 0, ClickType.PICKUP); - // place shovel back - LocalPlayerInventory.sendWindowClick(inv, 0, ClickType.PICKUP); - })); + .filter(this::isMendable) + .filter(item -> !isDamaged(item)) + .ifPresent( + offhand -> + LocalPlayerInventory.getSlotInventory() + .stream() + .filter(this::isMendable) + .filter(this::isDamaged) + .filter(inv -> inv.getIndex() != current.getIndex()) + .max(Comparator.comparingInt(InvItem::getDamage)) + .ifPresent( + inv -> { + // pick up + LocalPlayerInventory.sendWindowClick(inv, 0, ClickType.PICKUP); + // place in offhand + LocalPlayerInventory.sendWindowClick(offhand, 0, ClickType.PICKUP); + // place shovel back + LocalPlayerInventory.sendWindowClick(inv, 0, ClickType.PICKUP); + })); } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoMine.java b/src/main/java/com/matt/forgehax/mods/AutoMine.java index f78fffa7d..4e182c568 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoMine.java +++ b/src/main/java/com/matt/forgehax/mods/AutoMine.java @@ -18,68 +18,73 @@ @RegisterMod public class AutoMine extends ToggleMod { + private boolean pressed = false; - + public AutoMine() { super(Category.PLAYER, "AutoMine", false, "Auto mine blocks"); } - + private void setPressed(boolean state) { Bindings.attack.setPressed(state); pressed = state; } - + @Override protected void onEnabled() { Bindings.attack.bind(); } - + @Override protected void onDisabled() { setPressed(false); Bindings.attack.unbind(); } - + @SubscribeEvent public void onTick(TickEvent.ClientTickEvent event) { - if (getLocalPlayer() == null || getWorld() == null) return; - + if (getLocalPlayer() == null || getWorld() == null) { + return; + } + switch (event.phase) { - case START: - { - RayTraceResult tr = LocalPlayerUtils.getMouseOverBlockTrace(); - - if (tr == null) { - setPressed(false); - return; - } - - setPressed(true); - break; + case START: { + RayTraceResult tr = LocalPlayerUtils.getMouseOverBlockTrace(); + + if (tr == null) { + setPressed(false); + return; } + + setPressed(true); + break; + } case END: setPressed(false); break; } } - + @SubscribeEvent(priority = EventPriority.HIGHEST) public void onGuiOpened(GuiOpenEvent event) { // process keys and mouse input even if this gui is open - if (getWorld() != null && getLocalPlayer() != null && event.getGui() != null) + if (getWorld() != null && getLocalPlayer() != null && event.getGui() != null) { event.getGui().allowUserInput = true; + } } - + @SubscribeEvent public void onLeftClickCouterUpdate(LeftClickCounterUpdateEvent event) { // prevent the leftClickCounter from changing event.setCanceled(true); } - + @SubscribeEvent public void onBlockCounterUpdate(BlockControllerProcessEvent event) { // bug fix - left click is actually false after processing the key bindings // this will set that boolean to the correct value - if (pressed) event.setLeftClicked(true); + if (pressed) { + event.setLeftClicked(true); + } } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoPitch.java b/src/main/java/com/matt/forgehax/mods/AutoPitch.java index ef383b4fd..0dc5571b9 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoPitch.java +++ b/src/main/java/com/matt/forgehax/mods/AutoPitch.java @@ -6,9 +6,10 @@ @RegisterMod public class AutoPitch extends ToggleMod { + public AutoPitch() { super(Category.PLAYER, "AutoPitch", false, "Automatically sets pitch to best trajectory"); } - + // TODO: reimplement } diff --git a/src/main/java/com/matt/forgehax/mods/AutoPlace.java b/src/main/java/com/matt/forgehax/mods/AutoPlace.java index c787e2a67..c2d0a1231 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoPlace.java +++ b/src/main/java/com/matt/forgehax/mods/AutoPlace.java @@ -7,8 +7,6 @@ import static com.matt.forgehax.Helper.printInform; import static com.matt.forgehax.Helper.printWarning; -import com.github.lunatrius.core.client.renderer.unique.GeometryMasks; -import com.github.lunatrius.core.client.renderer.unique.GeometryTessellator; import com.google.common.base.MoreObjects; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -39,6 +37,8 @@ import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; import com.matt.forgehax.util.serialization.ISerializableJson; +import com.matt.forgehax.util.tesselation.GeometryMasks; +import com.matt.forgehax.util.tesselation.GeometryTessellator; import java.io.IOException; import java.util.Arrays; import java.util.Collection; @@ -78,6 +78,7 @@ @RegisterMod public class AutoPlace extends ToggleMod implements PositionRotationManager.MovementUpdateListener { + enum Stage { SELECT_BLOCKS, SELECT_REPLACEMENT, @@ -85,120 +86,120 @@ enum Stage { READY, ; } - + private final Options config = - getCommandStub() - .builders() - .newOptionsBuilder() - .name("config") - .description("Saved selection configs") - .factory(PlaceConfigEntry::new) - .supplier(Lists::newCopyOnWriteArrayList) - .build(); - + getCommandStub() + .builders() + .newOptionsBuilder() + .name("config") + .description("Saved selection configs") + .factory(PlaceConfigEntry::new) + .supplier(Lists::newCopyOnWriteArrayList) + .build(); + private final Options sides = - getCommandStub() - .builders() - .newOptionsBuilder() - .name("sides") - .description("Sides to place the blocks on") - .defaults(() -> Collections.singleton(new FacingEntry(EnumFacing.UP))) - .factory(FacingEntry::new) - .supplier(Lists::newCopyOnWriteArrayList) - .build(); - + getCommandStub() + .builders() + .newOptionsBuilder() + .name("sides") + .description("Sides to place the blocks on") + .defaults(() -> Collections.singleton(new FacingEntry(EnumFacing.UP))) + .factory(FacingEntry::new) + .supplier(Lists::newCopyOnWriteArrayList) + .build(); + private final Setting check_neighbors = - getCommandStub() - .builders() - .newSettingBuilder() - .name("check-neighbors") - .description("Will check the neighboring blocks to see if a block can be placed") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("check-neighbors") + .description("Will check the neighboring blocks to see if a block can be placed") + .defaultTo(false) + .build(); + private final Setting whitelist = - getCommandStub() - .builders() - .newSettingBuilder() - .name("whitelist") - .description("Makes the target list function as an inclusive list") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("whitelist") + .description("Makes the target list function as an inclusive list") + .defaultTo(true) + .build(); + private final Setting silent = - getCommandStub() - .builders() - .newSettingBuilder() - .name("silent") - .description("Client angles don't change") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("silent") + .description("Client angles don't change") + .defaultTo(true) + .build(); + private final Setting cooldown = - getCommandStub() - .builders() - .newSettingBuilder() - .name("cooldown") - .description( - "Block place delay to check_neighbors after placing a block. Set to 0 to disable") - .defaultTo(4) - .min(0) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("cooldown") + .description( + "Block place delay to check_neighbors after placing a block. Set to 0 to disable") + .defaultTo(4) + .min(0) + .build(); + private final Setting render = - getCommandStub() - .builders() - .newSettingBuilder() - .name("render") - .description("Show which blocks are currently visible and being targeted") - .defaultTo(false) - .changed( - cb -> { - if (cb.getTo()) { - this.renderingBlocks.clear(); - this.currentRenderingTarget = null; - } - }) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("render") + .description("Show which blocks are currently visible and being targeted") + .defaultTo(false) + .changed( + cb -> { + if (cb.getTo()) { + this.renderingBlocks.clear(); + this.currentRenderingTarget = null; + } + }) + .build(); + private final Setting client_angles = - getCommandStub() - .builders() - .newSettingBuilder() - .name("client-angles") - .description("Sort the blocks to break by the clients angle instead of the servers") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("client-angles") + .description("Sort the blocks to break by the clients angle instead of the servers") + .defaultTo(false) + .build(); + private final Set renderingBlocks = Sets.newConcurrentHashSet(); private BlockPos currentRenderingTarget = null; - + private final KeyBinding bindSelect = new KeyBinding("AutoPlace Selection", -100, "ForgeHax"); private final KeyBinding bindFinish = new KeyBinding("AutoPlace Finished", -98, "ForgeHax"); - + private final AtomicBoolean bindSelectToggle = new AtomicBoolean(false); private final AtomicBoolean bindFinishToggle = new AtomicBoolean(false); private final AtomicBoolean printToggle = new AtomicBoolean(false); private final AtomicBoolean resetToggle = new AtomicBoolean(false); - + private final List targets = Lists.newArrayList(); - + private ItemStack selectedItem = null; - + private Runnable resetTask = null; - + private Stage stage = Stage.SELECT_BLOCKS; - + public AutoPlace() { super(Category.PLAYER, "AutoPlace", false, "Automatically place blocks on top of other blocks"); - + this.bindSelect.setKeyConflictContext(BindingHelper.getEmptyKeyConflictContext()); this.bindFinish.setKeyConflictContext(BindingHelper.getEmptyKeyConflictContext()); - + ClientRegistry.registerKeyBinding(this.bindSelect); ClientRegistry.registerKeyBinding(this.bindFinish); } - + private void reset() { if (resetToggle.compareAndSet(true, false)) { targets.clear(); @@ -212,350 +213,337 @@ private void reset() { printInform("AutoPlace data has been reset."); } } - + private boolean isValidBlock(UniqueBlock info) { return whitelist.get() - ? targets.stream().anyMatch(info::equals) - : targets.stream().noneMatch(info::equals); + ? targets.stream().anyMatch(info::equals) + : targets.stream().noneMatch(info::equals); } - + private boolean isClickable(UniqueBlock info) { return sides - .stream() - .map(FacingEntry::getFacing) - .anyMatch(side -> BlockHelper.isBlockReplaceable(info.getPos().offset(side))); + .stream() + .map(FacingEntry::getFacing) + .anyMatch(side -> BlockHelper.isBlockReplaceable(info.getPos().offset(side))); } - + private EnumFacing getBestFacingMatch(final String input) { return Arrays.stream(EnumFacing.values()) - .filter(side -> side.getName2().toLowerCase().contains(input.toLowerCase())) - .min( - Comparator.comparing( - e -> e.getName2().toLowerCase(), - Comparator.comparingInt( - n -> StringUtils.getLevenshteinDistance(n, input.toLowerCase())) - .thenComparing(n -> n.startsWith(input)))) - .orElseGet( - () -> { - EnumFacing[] values = EnumFacing.values(); - try { - int index = Integer.valueOf(input); - return values[MathHelper.clamp(index, 0, values.length - 1)]; - } catch (NumberFormatException e) { - return values[0]; - } - }); + .filter(side -> side.getName2().toLowerCase().contains(input.toLowerCase())) + .min( + Comparator.comparing( + e -> e.getName2().toLowerCase(), + Comparator.comparingInt( + n -> StringUtils.getLevenshteinDistance(n, input.toLowerCase())) + .thenComparing(n -> n.startsWith(input)))) + .orElseGet( + () -> { + EnumFacing[] values = EnumFacing.values(); + try { + int index = Integer.valueOf(input); + return values[MathHelper.clamp(index, 0, values.length - 1)]; + } catch (NumberFormatException e) { + return values[0]; + } + }); } - + private void showInfo(String filter) { MC.addScheduledTask( - () -> { - if ("selected".startsWith(filter)) - printInform( - "Selected item %s", - this.selectedItem.getItem().getRegistryName().toString() - + "{" - + this.selectedItem.getMetadata() - + "}"); - - if ("targets".startsWith(filter)) - printInform( - "Targets: %s", - this.targets.stream().map(UniqueBlock::toString).collect(Collectors.joining(", "))); - - if ("sides".startsWith(filter)) - printInform( - "Sides: %s", - this.sides - .stream() - .map(FacingEntry::getFacing) - .map(EnumFacing::getName2) - .collect(Collectors.joining(", "))); - - if ("whitelist".startsWith(filter)) - printInform("Whitelist: %s", Boolean.toString(whitelist.get())); - - if ("check_neighbors".startsWith(filter)) - printInform("Check Neighbors: %s", Boolean.toString(check_neighbors.get())); - }); + () -> { + if ("selected".startsWith(filter)) { + printInform( + "Selected item %s", + this.selectedItem.getItem().getRegistryName().toString() + + "{" + + this.selectedItem.getMetadata() + + "}"); + } + + if ("targets".startsWith(filter)) { + printInform( + "Targets: %s", + this.targets.stream().map(UniqueBlock::toString).collect(Collectors.joining(", "))); + } + + if ("sides".startsWith(filter)) { + printInform( + "Sides: %s", + this.sides + .stream() + .map(FacingEntry::getFacing) + .map(EnumFacing::getName2) + .collect(Collectors.joining(", "))); + } + + if ("whitelist".startsWith(filter)) { + printInform("Whitelist: %s", Boolean.toString(whitelist.get())); + } + + if ("check_neighbors".startsWith(filter)) { + printInform("Check Neighbors: %s", Boolean.toString(check_neighbors.get())); + } + }); } - + @Override protected void onLoad() { getCommandStub() - .builders() - .newCommandBuilder() - .name("reset") - .description("Reset to the setup process") - .processor( - data -> { - resetToggle.set(true); - if (getLocalPlayer() == null && getWorld() == null) reset(); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("reset") + .description("Reset to the setup process") + .processor( + data -> { + resetToggle.set(true); + if (getLocalPlayer() == null && getWorld() == null) { + reset(); + } + }) + .build(); + getCommandStub() - .builders() - .newCommandBuilder() - .name("info") - .description("Print info about the mod") - .processor( - data -> { - String arg = data.getArgumentCount() > 1 ? data.getArgumentAsString(0) : ""; - showInfo(arg); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("info") + .description("Print info about the mod") + .processor( + data -> { + String arg = data.getArgumentCount() > 1 ? data.getArgumentAsString(0) : ""; + showInfo(arg); + }) + .build(); + sides - .builders() - .newCommandBuilder() - .name("add") - .description("Add side to the list") - .requiredArgs(1) - .processor( - data -> { - final String name = data.getArgumentAsString(0); - EnumFacing facing = getBestFacingMatch(name); - - if ("all".equalsIgnoreCase(name)) { - sides.addAll( - Arrays.stream(EnumFacing.values()) - .map(FacingEntry::new) - .filter(e -> !sides.contains(e)) - .collect(Collectors.toSet())); - data.write("Added all sides"); - data.markSuccess(); - sides.serializeAll(); - } else if (sides.get(facing) == null) { - sides.add(new FacingEntry(facing)); - data.write("Added side " + facing.getName2()); - data.markSuccess(); - sides.serializeAll(); - } else { - data.write(facing.getName2() + " already exists"); - data.markFailed(); - } - }) - .build(); - + .builders() + .newCommandBuilder() + .name("add") + .description("Add side to the list") + .requiredArgs(1) + .processor( + data -> { + final String name = data.getArgumentAsString(0); + EnumFacing facing = getBestFacingMatch(name); + + if ("all".equalsIgnoreCase(name)) { + sides.addAll( + Arrays.stream(EnumFacing.values()) + .map(FacingEntry::new) + .filter(e -> !sides.contains(e)) + .collect(Collectors.toSet())); + data.write("Added all sides"); + data.markSuccess(); + sides.serializeAll(); + } else if (sides.get(facing) == null) { + sides.add(new FacingEntry(facing)); + data.write("Added side " + facing.getName2()); + data.markSuccess(); + sides.serializeAll(); + } else { + data.write(facing.getName2() + " already exists"); + data.markFailed(); + } + }) + .build(); + sides - .builders() - .newCommandBuilder() - .name("remove") - .description("Remove side from the list") - .requiredArgs(1) - .processor( - data -> { - final String name = data.getArgumentAsString(0); - EnumFacing facing = getBestFacingMatch(name); - - if ("all".equalsIgnoreCase(name)) { - sides.clear(); - data.write("Removed all sides"); - data.markSuccess(); - sides.serializeAll(); - } else if (sides.remove(new FacingEntry(facing))) { - data.write("Removed side " + facing.getName2()); - data.markSuccess(); - sides.serializeAll(); - } else { - data.write(facing.getName2() + " doesn't exist"); - data.markFailed(); - } - }) - .build(); - + .builders() + .newCommandBuilder() + .name("remove") + .description("Remove side from the list") + .requiredArgs(1) + .processor( + data -> { + final String name = data.getArgumentAsString(0); + EnumFacing facing = getBestFacingMatch(name); + + if ("all".equalsIgnoreCase(name)) { + sides.clear(); + data.write("Removed all sides"); + data.markSuccess(); + sides.serializeAll(); + } else if (sides.remove(new FacingEntry(facing))) { + data.write("Removed side " + facing.getName2()); + data.markSuccess(); + sides.serializeAll(); + } else { + data.write(facing.getName2() + " doesn't exist"); + data.markFailed(); + } + }) + .build(); + sides - .builders() - .newCommandBuilder() - .name("list") - .description("List all the current added sides") - .processor( - data -> { - data.write( - "Sides: " - + sides - .stream() - .map(FacingEntry::getFacing) - .map(EnumFacing::getName2) - .collect(Collectors.joining(", "))); - data.markSuccess(); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("list") + .description("List all the current added sides") + .processor( + data -> { + data.write( + "Sides: " + + sides + .stream() + .map(FacingEntry::getFacing) + .map(EnumFacing::getName2) + .collect(Collectors.joining(", "))); + data.markSuccess(); + }) + .build(); + config - .builders() - .newCommandBuilder() - .name("save") - .description("Save current setup") - .requiredArgs(1) - .processor( - data -> { - String name = data.getArgumentAsString(0); - - if (config.get(name) == null) { - PlaceConfigEntry entry = new PlaceConfigEntry(name); - entry.setSides( - this.sides.stream().map(FacingEntry::getFacing).collect(Collectors.toSet())); - entry.setTargets(this.targets); - entry.setSelection(this.selectedItem); - entry.setWhitelist(this.whitelist.get()); - entry.setUse(this.check_neighbors.get()); - - config.add(entry); - config.serializeAll(); - data.write("Saved current config as " + name); - data.markSuccess(); - } else { - data.write(name + " is already in check_neighbors!"); - data.markFailed(); - } - }) - .build(); - + .builders() + .newCommandBuilder() + .name("save") + .description("Save current setup") + .requiredArgs(1) + .processor( + data -> { + String name = data.getArgumentAsString(0); + + if (config.get(name) == null) { + PlaceConfigEntry entry = new PlaceConfigEntry(name); + entry.setSides( + this.sides.stream().map(FacingEntry::getFacing).collect(Collectors.toSet())); + entry.setTargets(this.targets); + entry.setSelection(this.selectedItem); + entry.setWhitelist(this.whitelist.get()); + entry.setUse(this.check_neighbors.get()); + + config.add(entry); + config.serializeAll(); + data.write("Saved current config as " + name); + data.markSuccess(); + } else { + data.write(name + " is already in check_neighbors!"); + data.markFailed(); + } + }) + .build(); + config - .builders() - .newCommandBuilder() - .name("load") - .description("Load config") - .requiredArgs(1) - .processor( - data -> { - String name = data.getArgumentAsString(0); - - PlaceConfigEntry entry = config.get(name); - if (entry != null) { - data.write(name + " loaded"); - resetTask = - () -> { - this.targets.clear(); - this.targets.addAll(entry.getTargets()); - - this.sides.clear(); - this.sides.addAll( - entry - .getSides() - .stream() - .map(FacingEntry::new) - .collect(Collectors.toSet())); - - this.selectedItem = entry.getSelection(); - - this.whitelist.set(entry.isWhitelist()); - this.check_neighbors.set(entry.isUse()); - - this.stage = Stage.CONFIRM; - - this.getCommandStub().serializeAll(); - }; - this.resetToggle.set(true); - } else { - data.write(name + " doesn't exist!"); - data.markFailed(); - } - }) - .build(); - + .builders() + .newCommandBuilder() + .name("load") + .description("Load config") + .requiredArgs(1) + .processor( + data -> { + String name = data.getArgumentAsString(0); + + PlaceConfigEntry entry = config.get(name); + if (entry != null) { + data.write(name + " loaded"); + resetTask = + () -> { + this.targets.clear(); + this.targets.addAll(entry.getTargets()); + + this.sides.clear(); + this.sides.addAll( + entry + .getSides() + .stream() + .map(FacingEntry::new) + .collect(Collectors.toSet())); + + this.selectedItem = entry.getSelection(); + + this.whitelist.set(entry.isWhitelist()); + this.check_neighbors.set(entry.isUse()); + + this.stage = Stage.CONFIRM; + + this.getCommandStub().serializeAll(); + }; + this.resetToggle.set(true); + } else { + data.write(name + " doesn't exist!"); + data.markFailed(); + } + }) + .build(); + config - .builders() - .newCommandBuilder() - .name("delete") - .description("Delete a configuration") - .requiredArgs(1) - .processor( - data -> { - String name = data.getArgumentAsString(0); - - if (config.remove(new PlaceConfigEntry(name))) { - config.serializeAll(); - data.write("Deleted config " + name); - data.markSuccess(); - } else { - data.write(name + " doesn't exist!"); - data.markFailed(); - } - }) - .build(); - + .builders() + .newCommandBuilder() + .name("delete") + .description("Delete a configuration") + .requiredArgs(1) + .processor( + data -> { + String name = data.getArgumentAsString(0); + + if (config.remove(new PlaceConfigEntry(name))) { + config.serializeAll(); + data.write("Deleted config " + name); + data.markSuccess(); + } else { + data.write(name + " doesn't exist!"); + data.markFailed(); + } + }) + .build(); + config - .builders() - .newCommandBuilder() - .name("list") - .description("List all the current configs") - .processor( - data -> { - data.write( - "Configs: " - + config - .stream() - .map(PlaceConfigEntry::getName) - .collect(Collectors.joining(", "))); - data.markSuccess(); - }) - .build(); + .builders() + .newCommandBuilder() + .name("list") + .description("List all the current configs") + .processor( + data -> { + data.write( + "Configs: " + + config + .stream() + .map(PlaceConfigEntry::getName) + .collect(Collectors.joining(", "))); + data.markSuccess(); + }) + .build(); } - + @Override protected void onEnabled() { PositionRotationManager.getManager().register(this); } - + @Override protected void onDisabled() { PositionRotationManager.getManager().unregister(this); printToggle.set(false); } - + @SubscribeEvent public void onRender(RenderEvent event) { - if (!render.get() || MC.getRenderViewEntity() == null) return; - + if (!render.get() || MC.getRenderViewEntity() == null) { + return; + } + GlStateManager.pushMatrix(); - + GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); GlStateManager.disableAlpha(); GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); GlStateManager.shadeModel(GL11.GL_SMOOTH); GlStateManager.disableDepth(); - + final GeometryTessellator tessellator = event.getTessellator(); final BufferBuilder builder = tessellator.getBuffer(); - + tessellator.beginLines(); tessellator.setTranslation(0, 0, 0); - + renderingBlocks.forEach( - pos -> { - IBlockState state = getWorld().getBlockState(pos); - AxisAlignedBB bb = state.getBoundingBox(getWorld(), pos); - tessellator.setTranslation( - (double) pos.getX() - event.getRenderPos().x, - (double) pos.getY() - event.getRenderPos().y, - (double) pos.getZ() - event.getRenderPos().z); - GeometryTessellator.drawLines( - builder, - bb.minX, - bb.minY, - bb.minZ, - bb.maxX, - bb.maxY, - bb.maxZ, - GeometryMasks.Line.ALL, - Colors.GREEN.setAlpha(150).toBuffer()); - }); - - // poz - final BlockPos current = this.currentRenderingTarget; - - if (current != null) { - IBlockState state = getWorld().getBlockState(current); - AxisAlignedBB bb = state.getBoundingBox(getWorld(), current); - tessellator.setTranslation( - (double) current.getX() - event.getRenderPos().x, - (double) current.getY() - event.getRenderPos().y, - (double) current.getZ() - event.getRenderPos().z); - GeometryTessellator.drawLines( + pos -> { + IBlockState state = getWorld().getBlockState(pos); + AxisAlignedBB bb = state.getBoundingBox(getWorld(), pos); + tessellator.setTranslation( + (double) pos.getX() - event.getRenderPos().x, + (double) pos.getY() - event.getRenderPos().y, + (double) pos.getZ() - event.getRenderPos().z); + GeometryTessellator.drawLines( builder, bb.minX, bb.minY, @@ -564,134 +552,155 @@ public void onRender(RenderEvent event) { bb.maxY, bb.maxZ, GeometryMasks.Line.ALL, - Colors.RED.setAlpha(150).toBuffer()); + Colors.GREEN.setAlpha(150).toBuffer()); + }); + + // poz + final BlockPos current = this.currentRenderingTarget; + + if (current != null) { + IBlockState state = getWorld().getBlockState(current); + AxisAlignedBB bb = state.getBoundingBox(getWorld(), current); + tessellator.setTranslation( + (double) current.getX() - event.getRenderPos().x, + (double) current.getY() - event.getRenderPos().y, + (double) current.getZ() - event.getRenderPos().z); + GeometryTessellator.drawLines( + builder, + bb.minX, + bb.minY, + bb.minZ, + bb.maxX, + bb.maxY, + bb.maxZ, + GeometryMasks.Line.ALL, + Colors.RED.setAlpha(150).toBuffer()); } - + tessellator.draw(); tessellator.setTranslation(0, 0, 0); - + GlStateManager.shadeModel(GL11.GL_FLAT); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); GlStateManager.enableTexture2D(); GlStateManager.enableDepth(); GlStateManager.enableCull(); - + GL11.glDisable(GL11.GL_LINE_SMOOTH); GlStateManager.popMatrix(); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { reset(); - + switch (stage) { - case SELECT_BLOCKS: - { - if (printToggle.compareAndSet(false, true)) { - targets.clear(); - printInform("Select blocks by pressing %s", BindingHelper.getIndexName(bindSelect)); - printInform("Finish this stage by pressing %s", BindingHelper.getIndexName(bindFinish)); + case SELECT_BLOCKS: { + if (printToggle.compareAndSet(false, true)) { + targets.clear(); + printInform("Select blocks by pressing %s", BindingHelper.getIndexName(bindSelect)); + printInform("Finish this stage by pressing %s", BindingHelper.getIndexName(bindFinish)); + } + + if (bindSelect.isKeyDown() && bindSelectToggle.compareAndSet(false, true)) { + RayTraceResult tr = LocalPlayerUtils.getMouseOverBlockTrace(); + if (tr == null) { + return; } - - if (bindSelect.isKeyDown() && bindSelectToggle.compareAndSet(false, true)) { - RayTraceResult tr = LocalPlayerUtils.getMouseOverBlockTrace(); - if (tr == null) return; - - UniqueBlock info = BlockHelper.newUniqueBlock(tr.getBlockPos()); - - if (info.isInvalid()) { - printWarning("Invalid block %s", info.toString()); - return; - } - - if (!targets.contains(info)) { - printInform("Added block %s", info.toString()); - targets.add(info); - } else { - printInform("Removed block %s", info.toString()); - targets.remove(info); - } - } else if (!bindSelect.isKeyDown()) { - bindSelectToggle.set(false); + + UniqueBlock info = BlockHelper.newUniqueBlock(tr.getBlockPos()); + + if (info.isInvalid()) { + printWarning("Invalid block %s", info.toString()); + return; } - - if (bindFinish.isKeyDown() && bindFinishToggle.compareAndSet(false, true)) { - if (targets.isEmpty()) { - printWarning("No items have been selected yet!"); - } else { - stage = Stage.SELECT_REPLACEMENT; - printToggle.set(false); - } - } else if (!bindFinish.isKeyDown()) { - bindFinishToggle.set(false); + + if (!targets.contains(info)) { + printInform("Added block %s", info.toString()); + targets.add(info); + } else { + printInform("Removed block %s", info.toString()); + targets.remove(info); } - break; + } else if (!bindSelect.isKeyDown()) { + bindSelectToggle.set(false); } - case SELECT_REPLACEMENT: - { - if (printToggle.compareAndSet(false, true)) - printInform( - "Hover over the block in your hot bar you want to place and press %s to select", - BindingHelper.getIndexName(bindSelect)); - - if (bindSelect.isKeyDown() && bindSelectToggle.compareAndSet(false, true)) { - InvItem selected = LocalPlayerInventory.getSelected(); - - if (selected.isNull()) { - printWarning("No item selected!"); - return; - } - - this.selectedItem = - new ItemStack(selected.getItem(), 1, selected.getItemStack().getMetadata()); - - printInform( - "Selected item %s", - this.selectedItem.getItem().getRegistryName().toString() - + "{" - + this.selectedItem.getMetadata() - + "}"); - - stage = Stage.CONFIRM; + + if (bindFinish.isKeyDown() && bindFinishToggle.compareAndSet(false, true)) { + if (targets.isEmpty()) { + printWarning("No items have been selected yet!"); + } else { + stage = Stage.SELECT_REPLACEMENT; printToggle.set(false); - } else if (!bindSelect.isKeyDown()) { - bindSelectToggle.set(false); } - break; + } else if (!bindFinish.isKeyDown()) { + bindFinishToggle.set(false); } - case CONFIRM: - { - if (printToggle.compareAndSet(false, true)) { - printInform( - "Press %s to begin, or '.%s info' to set the current settings", - BindingHelper.getIndexName(bindFinish), getModName()); - } - - if (bindFinish.isKeyDown() - && selectedItem != null - && bindFinishToggle.compareAndSet(false, true)) { - printInform("Block place process started"); - printInform("Type '.%s reset' to restart the process", getModName()); - stage = Stage.READY; - } else if (!bindFinish.isKeyDown()) { - bindFinishToggle.set(false); - } - break; + break; + } + case SELECT_REPLACEMENT: { + if (printToggle.compareAndSet(false, true)) { + printInform( + "Hover over the block in your hot bar you want to place and press %s to select", + BindingHelper.getIndexName(bindSelect)); } - case READY: - { - if (bindFinish.isKeyDown() && bindFinishToggle.compareAndSet(false, true)) { - printInform("Block place process paused"); - stage = Stage.CONFIRM; - } else if (!bindFinish.isKeyDown()) { - bindFinishToggle.set(false); + + if (bindSelect.isKeyDown() && bindSelectToggle.compareAndSet(false, true)) { + InvItem selected = LocalPlayerInventory.getSelected(); + + if (selected.isNull()) { + printWarning("No item selected!"); + return; } - break; + + this.selectedItem = + new ItemStack(selected.getItem(), 1, selected.getItemStack().getMetadata()); + + printInform( + "Selected item %s", + this.selectedItem.getItem().getRegistryName().toString() + + "{" + + this.selectedItem.getMetadata() + + "}"); + + stage = Stage.CONFIRM; + printToggle.set(false); + } else if (!bindSelect.isKeyDown()) { + bindSelectToggle.set(false); + } + break; + } + case CONFIRM: { + if (printToggle.compareAndSet(false, true)) { + printInform( + "Press %s to begin, or '.%s info' to set the current settings", + BindingHelper.getIndexName(bindFinish), getModName()); + } + + if (bindFinish.isKeyDown() + && selectedItem != null + && bindFinishToggle.compareAndSet(false, true)) { + printInform("Block place process started"); + printInform("Type '.%s reset' to restart the process", getModName()); + stage = Stage.READY; + } else if (!bindFinish.isKeyDown()) { + bindFinishToggle.set(false); + } + break; + } + case READY: { + if (bindFinish.isKeyDown() && bindFinishToggle.compareAndSet(false, true)) { + printInform("Block place process paused"); + stage = Stage.CONFIRM; + } else if (!bindFinish.isKeyDown()) { + bindFinishToggle.set(false); } + break; + } } } - + @Override public void onLocalPlayerMovementUpdate(Local state) { if (!Stage.READY.equals(stage)) { @@ -699,346 +708,356 @@ public void onLocalPlayerMovementUpdate(Local state) { currentRenderingTarget = null; return; } - if (cooldown.get() > 0 && Fields.Minecraft_rightClickDelayTimer.get(MC) > 0) return; - + if (cooldown.get() > 0 && Fields.Minecraft_rightClickDelayTimer.get(MC) > 0) { + return; + } + if (render.get()) { renderingBlocks.clear(); currentRenderingTarget = null; } - + InvItem items = - LocalPlayerInventory.getHotbarInventory() - .stream() - .filter(InvItem::nonNull) - .filter(inv -> inv.getItem().equals(selectedItem.getItem())) - .filter( - item -> - !(item.getItem() instanceof ItemBlock) - || item.getItemStack().getMetadata() == selectedItem.getMetadata()) - .findFirst() - .orElse(InvItem.EMPTY); - - if (items.isNull()) return; - + LocalPlayerInventory.getHotbarInventory() + .stream() + .filter(InvItem::nonNull) + .filter(inv -> inv.getItem().equals(selectedItem.getItem())) + .filter( + item -> + !(item.getItem() instanceof ItemBlock) + || item.getItemStack().getMetadata() == selectedItem.getMetadata()) + .findFirst() + .orElse(InvItem.EMPTY); + + if (items.isNull()) { + return; + } + final Vec3d eyes = LocalPlayerUtils.getEyePos(); final Vec3d dir = - client_angles.get() - ? LocalPlayerUtils.getDirectionVector() - : LocalPlayerUtils.getServerDirectionVector(); - + client_angles.get() + ? LocalPlayerUtils.getDirectionVector() + : LocalPlayerUtils.getServerDirectionVector(); + List blocks = - BlockHelper.getBlocksInRadius(eyes, getPlayerController().getBlockReachDistance()) - .stream() - .filter(pos -> !getWorld().isAirBlock(pos)) - .map(BlockHelper::newUniqueBlock) - .filter(this::isValidBlock) - .filter(this::isClickable) - .sorted( - Comparator.comparingDouble( - info -> - VectorUtils.getCrosshairDistance( - eyes, dir, BlockHelper.getOBBCenter(info.getPos())))) - .collect(Collectors.toList()); - - if (blocks.isEmpty()) return; - + BlockHelper.getBlocksInRadius(eyes, getPlayerController().getBlockReachDistance()) + .stream() + .filter(pos -> !getWorld().isAirBlock(pos)) + .map(BlockHelper::newUniqueBlock) + .filter(this::isValidBlock) + .filter(this::isClickable) + .sorted( + Comparator.comparingDouble( + info -> + VectorUtils.getCrosshairDistance( + eyes, dir, BlockHelper.getOBBCenter(info.getPos())))) + .collect(Collectors.toList()); + + if (blocks.isEmpty()) { + return; + } + if (render.get()) { currentRenderingTarget = null; renderingBlocks.clear(); renderingBlocks.addAll(blocks.stream().map(UniqueBlock::getPos).collect(Collectors.toSet())); } - + // find a block that can be placed int index = 0; BlockTraceInfo trace = null; do { - if (index >= blocks.size()) break; - + if (index >= blocks.size()) { + break; + } + final UniqueBlock at = blocks.get(index++); if (!check_neighbors.get()) { trace = - sides - .stream() - .map(FacingEntry::getFacing) - .map(side -> BlockHelper.getBlockSideTrace(eyes, at.getPos(), side.getOpposite())) - .filter(Objects::nonNull) - .filter(tr -> tr.isPlaceable(items)) - .max( - Comparator.comparing(BlockTraceInfo::isSneakRequired) - .thenComparing( - i -> -VectorUtils.getCrosshairDistance(eyes, dir, i.getCenteredPos()))) - .orElse(null); + sides + .stream() + .map(FacingEntry::getFacing) + .map(side -> BlockHelper.getBlockSideTrace(eyes, at.getPos(), side.getOpposite())) + .filter(Objects::nonNull) + .filter(tr -> tr.isPlaceable(items)) + .max( + Comparator.comparing(BlockTraceInfo::isSneakRequired) + .thenComparing( + i -> -VectorUtils.getCrosshairDistance(eyes, dir, i.getCenteredPos()))) + .orElse(null); } else { trace = - sides - .stream() - .map(FacingEntry::getFacing) - .map( - side -> - BlockHelper.getPlaceableBlockSideTrace(eyes, dir, at.getPos().offset(side))) - .filter(Objects::nonNull) - .filter(tr -> tr.isPlaceable(items)) - .max( - Comparator.comparing(BlockTraceInfo::isSneakRequired) - .thenComparing( - i -> -VectorUtils.getCrosshairDistance(eyes, dir, i.getCenteredPos()))) - .orElse(null); + sides + .stream() + .map(FacingEntry::getFacing) + .map( + side -> + BlockHelper.getPlaceableBlockSideTrace(eyes, dir, at.getPos().offset(side))) + .filter(Objects::nonNull) + .filter(tr -> tr.isPlaceable(items)) + .max( + Comparator.comparing(BlockTraceInfo::isSneakRequired) + .thenComparing( + i -> -VectorUtils.getCrosshairDistance(eyes, dir, i.getCenteredPos()))) + .orElse(null); } } while (trace == null); - + // if the block list is exhausted - if (trace == null) return; - - if (render.get()) currentRenderingTarget = trace.getPos(); - + if (trace == null) { + return; + } + + if (render.get()) { + currentRenderingTarget = trace.getPos(); + } + Angle va = Utils.getLookAtAngles(trace.getHitVec()); state.setViewAngles(va, silent.get()); - + final BlockTraceInfo tr = trace; state.invokeLater( - rs -> { - ResetFunction func = LocalPlayerInventory.setSelected(items); - - boolean sneak = tr.isSneakRequired() && !LocalPlayerUtils.isSneaking(); - if (sneak) { - // send start sneaking packet - PacketHelper.ignoreAndSend( - new CPacketEntityAction(getLocalPlayer(), Action.START_SNEAKING)); - - LocalPlayerUtils.setSneakingSuppression(true); - LocalPlayerUtils.setSneaking(true); - } - - getPlayerController() - .processRightClickBlock( - getLocalPlayer(), - getWorld(), - tr.getPos(), - tr.getOppositeSide(), - tr.getHitVec(), - EnumHand.MAIN_HAND); - - // stealth send swing packet - getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); - - if (sneak) { - LocalPlayerUtils.setSneaking(false); - LocalPlayerUtils.setSneakingSuppression(false); - - getNetworkManager() - .sendPacket(new CPacketEntityAction(getLocalPlayer(), Action.STOP_SNEAKING)); - } - - func.revert(); - - // set the block place delay - Fields.Minecraft_rightClickDelayTimer.set(MC, cooldown.get()); - }); + rs -> { + ResetFunction func = LocalPlayerInventory.setSelected(items); + + boolean sneak = tr.isSneakRequired() && !LocalPlayerUtils.isSneaking(); + if (sneak) { + // send start sneaking packet + PacketHelper.ignoreAndSend( + new CPacketEntityAction(getLocalPlayer(), Action.START_SNEAKING)); + + LocalPlayerUtils.setSneakingSuppression(true); + LocalPlayerUtils.setSneaking(true); + } + + getPlayerController() + .processRightClickBlock( + getLocalPlayer(), + getWorld(), + tr.getPos(), + tr.getOppositeSide(), + tr.getHitVec(), + EnumHand.MAIN_HAND); + + // stealth send swing packet + getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); + + if (sneak) { + LocalPlayerUtils.setSneaking(false); + LocalPlayerUtils.setSneakingSuppression(false); + + getNetworkManager() + .sendPacket(new CPacketEntityAction(getLocalPlayer(), Action.STOP_SNEAKING)); + } + + func.revert(); + + // set the block place delay + Fields.Minecraft_rightClickDelayTimer.set(MC, cooldown.get()); + }); } - + private static class PlaceConfigEntry implements ISerializableJson { + private final String name; - + private final List targets = Lists.newArrayList(); private final List sides = Lists.newArrayList(); private ItemStack selection = ItemStack.EMPTY; private boolean use = false; private boolean whitelist = true; - + private PlaceConfigEntry(String name) { Objects.requireNonNull(name); this.name = name; } - + public String getName() { return name; } - + public List getTargets() { return Collections.unmodifiableList(targets); } - + public void setTargets(Collection list) { targets.clear(); targets.addAll( - list.stream() - .filter(info -> !Blocks.AIR.equals(info.getBlock())) - .collect(Collectors.toSet())); // collect to set to eliminate duplicates + list.stream() + .filter(info -> !Blocks.AIR.equals(info.getBlock())) + .collect(Collectors.toSet())); // collect to set to eliminate duplicates } - + public List getSides() { return Collections.unmodifiableList(sides); } - + public void setSides(Collection list) { sides.clear(); sides.addAll(Sets.newLinkedHashSet(list)); // copy to set to eliminate duplicates } - + public ItemStack getSelection() { return selection; } - + public void setSelection(ItemStack selection) { this.selection = - Optional.ofNullable(selection) - .filter(s -> !Items.AIR.equals(s.getItem())) - .orElse(ItemStack.EMPTY); + Optional.ofNullable(selection) + .filter(s -> !Items.AIR.equals(s.getItem())) + .orElse(ItemStack.EMPTY); } - + public boolean isUse() { return use; } - + public void setUse(boolean use) { this.use = use; } - + public boolean isWhitelist() { return whitelist; } - + public void setWhitelist(boolean whitelist) { this.whitelist = whitelist; } - + @Override public void serialize(JsonWriter writer) throws IOException { writer.beginObject(); - + writer.name("selection"); writer.beginObject(); { writer.name("item"); writer.value(getSelection().getItem().getRegistryName().toString()); - + writer.name("metadata"); writer.value(getSelection().getMetadata()); } writer.endObject(); - + writer.name("targets"); writer.beginArray(); { for (UniqueBlock info : getTargets()) { writer.beginObject(); - + writer.name("block"); writer.value(info.getBlock().getRegistryName().toString()); - + writer.name("metadata"); writer.value(info.getMetadata()); - + writer.endObject(); } } writer.endArray(); - + writer.name("use"); writer.value(isUse()); - + writer.name("whitelist"); writer.value(isWhitelist()); - + writer.name("sides"); writer.beginArray(); { - for (EnumFacing side : getSides()) writer.value(side.getName2()); + for (EnumFacing side : getSides()) { + writer.value(side.getName2()); + } } writer.endArray(); - + writer.endObject(); } - + @Override public void deserialize(JsonReader reader) throws IOException { reader.beginObject(); - + while (reader.hasNext()) { switch (reader.nextName()) { - case "selection": - { + case "selection": { + reader.beginObject(); + + reader.nextName(); + Item item = ItemSword.getByNameOrId(reader.nextString()); + + reader.nextName(); + int meta = reader.nextInt(); + + setSelection(new ItemStack(MoreObjects.firstNonNull(item, Items.AIR), 1, meta)); + + reader.endObject(); + break; + } + case "targets": { + reader.beginArray(); + + List blocks = Lists.newArrayList(); + while (reader.hasNext()) { reader.beginObject(); - + + // block reader.nextName(); - Item item = ItemSword.getByNameOrId(reader.nextString()); - + Block block = Block.getBlockFromName(reader.nextString()); + + // metadata reader.nextName(); int meta = reader.nextInt(); - - setSelection(new ItemStack(MoreObjects.firstNonNull(item, Items.AIR), 1, meta)); - + + blocks.add(BlockHelper.newUniqueBlock(block, meta)); + reader.endObject(); - break; - } - case "targets": - { - reader.beginArray(); - - List blocks = Lists.newArrayList(); - while (reader.hasNext()) { - reader.beginObject(); - - // block - reader.nextName(); - Block block = Block.getBlockFromName(reader.nextString()); - - // metadata - reader.nextName(); - int meta = reader.nextInt(); - - blocks.add(BlockHelper.newUniqueBlock(block, meta)); - - reader.endObject(); - } - setTargets(blocks); - - reader.endArray(); - break; - } - case "use": - { - setUse(reader.nextBoolean()); - break; } - case "whitelist": - { - setWhitelist(reader.nextBoolean()); - break; - } - case "sides": - { - reader.beginArray(); - - List sides = Lists.newArrayList(); - while (reader.hasNext()) { - sides.add( - Optional.ofNullable(reader.nextString()) - .map(EnumFacing::byName) - .orElse(EnumFacing.UP)); - } - setSides(sides); - - reader.endArray(); - break; + setTargets(blocks); + + reader.endArray(); + break; + } + case "use": { + setUse(reader.nextBoolean()); + break; + } + case "whitelist": { + setWhitelist(reader.nextBoolean()); + break; + } + case "sides": { + reader.beginArray(); + + List sides = Lists.newArrayList(); + while (reader.hasNext()) { + sides.add( + Optional.ofNullable(reader.nextString()) + .map(EnumFacing::byName) + .orElse(EnumFacing.UP)); } + setSides(sides); + + reader.endArray(); + break; + } default: reader.skipValue(); break; } } - + reader.endObject(); } - + @Override public boolean equals(Object obj) { return this == obj - || (obj instanceof PlaceConfigEntry - && getName().equalsIgnoreCase(((PlaceConfigEntry) obj).getName())) - || (obj instanceof String && getName().equalsIgnoreCase((String) obj)); + || (obj instanceof PlaceConfigEntry + && getName().equalsIgnoreCase(((PlaceConfigEntry) obj).getName())) + || (obj instanceof String && getName().equalsIgnoreCase((String) obj)); } - + @Override public String toString() { return name; diff --git a/src/main/java/com/matt/forgehax/mods/AutoReconnectMod.java b/src/main/java/com/matt/forgehax/mods/AutoReconnectMod.java index 15779e079..3d96f7a05 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoReconnectMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoReconnectMod.java @@ -22,72 +22,77 @@ @RegisterMod public class AutoReconnectMod extends ToggleMod { + private static ServerData lastConnectedServer; - + public static boolean hasAutoLogged = - false; // used to disable autoreconnecting without disabling the entire mod - + false; // used to disable autoreconnecting without disabling the entire mod + public void updateLastConnectedServer() { ServerData data = MC.getCurrentServerData(); - if (data != null) lastConnectedServer = data; + if (data != null) { + lastConnectedServer = data; + } } - + public final Setting delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("delay") - .description("Delay between each reconnect attempt") - .defaultTo(5.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("delay") + .description("Delay between each reconnect attempt") + .defaultTo(5.D) + .build(); + public AutoReconnectMod() { super(Category.MISC, "AutoReconnect", false, "Automatically reconnects to server"); } - + @SubscribeEvent public void onGuiOpened(GuiOpenEvent event) { - if (!hasAutoLogged) + if (!hasAutoLogged) { if (event.getGui() instanceof GuiDisconnected - && !(event.getGui() instanceof GuiDisconnectedOverride)) { + && !(event.getGui() instanceof GuiDisconnectedOverride)) { updateLastConnectedServer(); GuiDisconnected disconnected = (GuiDisconnected) event.getGui(); event.setGui( - new GuiDisconnectedOverride( - FastReflection.Fields.GuiDisconnected_parentScreen.get(disconnected), - "connect.failed", - FastReflection.Fields.GuiDisconnected_message.get(disconnected), - FastReflection.Fields.GuiDisconnected_reason.get(disconnected), - delay.get())); + new GuiDisconnectedOverride( + FastReflection.Fields.GuiDisconnected_parentScreen.get(disconnected), + "connect.failed", + FastReflection.Fields.GuiDisconnected_message.get(disconnected), + FastReflection.Fields.GuiDisconnected_reason.get(disconnected), + delay.get())); } + } } - + @SubscribeEvent public void onWorldLoad(WorldEvent.Load event) { // we got on the server or stopped joining, now undo queue hasAutoLogged = false; // make mod work when you rejoin } - + @SubscribeEvent public void onWorldUnload(WorldEvent.Unload event) { updateLastConnectedServer(); } - + public static class GuiDisconnectedOverride extends GuiDisconnected { + private GuiScreen parent; private ITextComponent message; - + // delay * 1000 = seconds to miliseconds private long reconnectTime; - + private GuiButton reconnectButton = null; - + public GuiDisconnectedOverride( - GuiScreen screen, - String reasonLocalizationKey, - ITextComponent chatComp, - String reason, - double delay) { + GuiScreen screen, + String reasonLocalizationKey, + ITextComponent chatComp, + String reason, + double delay) { super(screen, reasonLocalizationKey, chatComp); parent = screen; message = chatComp; @@ -95,59 +100,59 @@ public GuiDisconnectedOverride( // set variable 'reason' to the previous classes value try { ReflectionHelper.setPrivateValue( - GuiDisconnected.class, - this, - reason, - "reason", - "field_146306_a", - "a"); // TODO: Find obbed mapping name + GuiDisconnected.class, + this, + reason, + "reason", + "field_146306_a", + "a"); // TODO: Find obbed mapping name } catch (Exception e) { Helper.printStackTrace(e); } // parse server return text and find queue pos } - + public long getTimeUntilReconnect() { return reconnectTime - System.currentTimeMillis(); } - + public double getTimeUntilReconnectInSeconds() { return (double) getTimeUntilReconnect() / 1000.D; } - + public String getFormattedReconnectText() { return String.format("Reconnecting (%.1f)...", getTimeUntilReconnectInSeconds()); } - + public ServerData getLastConnectedServerData() { return lastConnectedServer != null ? lastConnectedServer : MC.getCurrentServerData(); } - + private void reconnect() { ServerData data = getLastConnectedServerData(); if (data != null) { FMLClientHandler.instance().showGuiScreen(new GuiConnecting(parent, MC, data)); } } - + @Override public void initGui() { super.initGui(); List multilineMessage = - fontRenderer.listFormattedStringToWidth(message.getFormattedText(), width - 50); + fontRenderer.listFormattedStringToWidth(message.getFormattedText(), width - 50); int textHeight = multilineMessage.size() * fontRenderer.FONT_HEIGHT; - + if (getLastConnectedServerData() != null) { buttonList.add( - reconnectButton = - new GuiButton( - buttonList.size(), - width / 2 - 100, - (height / 2 + textHeight / 2 + fontRenderer.FONT_HEIGHT) + 23, - getFormattedReconnectText())); + reconnectButton = + new GuiButton( + buttonList.size(), + width / 2 - 100, + (height / 2 + textHeight / 2 + fontRenderer.FONT_HEIGHT) + 23, + getFormattedReconnectText())); } } - + @Override protected void actionPerformed(GuiButton button) throws IOException { super.actionPerformed(button); @@ -155,12 +160,16 @@ protected void actionPerformed(GuiButton button) throws IOException { reconnect(); } } - + @Override public void updateScreen() { super.updateScreen(); - if (reconnectButton != null) reconnectButton.displayString = getFormattedReconnectText(); - if (System.currentTimeMillis() >= reconnectTime) reconnect(); + if (reconnectButton != null) { + reconnectButton.displayString = getFormattedReconnectText(); + } + if (System.currentTimeMillis() >= reconnectTime) { + reconnect(); + } } } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoReply.java b/src/main/java/com/matt/forgehax/mods/AutoReply.java index 77a8b34db..4971d2a3a 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoReply.java +++ b/src/main/java/com/matt/forgehax/mods/AutoReply.java @@ -12,37 +12,38 @@ @RegisterMod public class AutoReply extends ToggleMod { + public final Setting reply = - getCommandStub() - .builders() - .newSettingBuilder() - .name("reply") - .description("Text to reply with") - .defaultTo("fuck off newfag") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("reply") + .description("Text to reply with") + .defaultTo("fuck off newfag") + .build(); + public final Setting mode = - getCommandStub() - .builders() - .newSettingBuilder() - .name("mode") - .description("Reply or chat") - .defaultTo("REPLY") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("mode") + .description("Reply or chat") + .defaultTo("REPLY") + .build(); + public final Setting search = - getCommandStub() - .builders() - .newSettingBuilder() - .name("search") - .description("Text to search for in message") - .defaultTo("whispers: ") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("search") + .description("Text to search for in message") + .defaultTo("whispers: ") + .build(); + public AutoReply() { super(Category.MISC, "AutoReply", false, "Automatically talk in chat if finds a strings"); } - + @SubscribeEvent public void onClientChat(ClientChatReceivedEvent event) { String message = (event.getMessage().getUnformattedText()); diff --git a/src/main/java/com/matt/forgehax/mods/AutoRespawnMod.java b/src/main/java/com/matt/forgehax/mods/AutoRespawnMod.java index 0be389092..631a250bd 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoRespawnMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoRespawnMod.java @@ -16,23 +16,24 @@ @RegisterMod public class AutoRespawnMod extends ToggleMod { + public AutoRespawnMod() { super(Category.PLAYER, "AutoRespawn", false, "Auto respawn on death"); } - + private final Setting delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("delay") - .description("wait ticks before respawning") - .min(0) - .defaultTo(50) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("delay") + .description("wait ticks before respawning") + .min(0) + .defaultTo(50) + .build(); + private boolean isDead = false; private int deadTicks = 0; - + @SubscribeEvent public void onClientTick(ClientTickEvent ev) { if (isDead) { @@ -44,16 +45,16 @@ public void onClientTick(ClientTickEvent ev) { } } } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { if (getLocalPlayer().getHealth() <= 0) { if (isDead == false) { // print once Helper.printInform("Died at %.1f, %.1f, %.1f on %s", - getLocalPlayer().posX, - getLocalPlayer().posY, - getLocalPlayer().posZ, - new SimpleDateFormat("HH:mm:ss").format(new Date()) + getLocalPlayer().posX, + getLocalPlayer().posY, + getLocalPlayer().posZ, + new SimpleDateFormat("HH:mm:ss").format(new Date()) ); } isDead = true; diff --git a/src/main/java/com/matt/forgehax/mods/AutoSprintMod.java b/src/main/java/com/matt/forgehax/mods/AutoSprintMod.java index 64d014aea..a04726147 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoSprintMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoSprintMod.java @@ -12,31 +12,33 @@ @RegisterMod public class AutoSprintMod extends ToggleMod { + private boolean isBound = false; - + enum Modes { ALWAYS, LEGIT } - + public final Setting mode = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("mode") - .description("Sprint mode") - .defaultTo(Modes.ALWAYS) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("mode") + .description("Sprint mode") + .defaultTo(Modes.ALWAYS) + .build(); + public AutoSprintMod() { super(Category.PLAYER, "AutoSprint", false, "Automatically sprints"); } - + private void startSprinting() { switch (mode.get()) { case ALWAYS: - if (!getLocalPlayer().collidedHorizontally && !getLocalPlayer().isSprinting()) + if (!getLocalPlayer().collidedHorizontally && !getLocalPlayer().isSprinting()) { getLocalPlayer().setSprinting(true); + } break; default: case LEGIT: @@ -44,11 +46,13 @@ private void startSprinting() { Bindings.sprint.bind(); isBound = true; } - if (!Bindings.sprint.getBinding().isKeyDown()) Bindings.sprint.setPressed(true); + if (!Bindings.sprint.getBinding().isKeyDown()) { + Bindings.sprint.setPressed(true); + } break; } } - + private void stopSprinting() { if (isBound) { Bindings.sprint.setPressed(false); @@ -56,19 +60,23 @@ private void stopSprinting() { isBound = false; } } - - /** Stop sprinting when the mod is disabled */ + + /** + * Stop sprinting when the mod is disabled + */ @Override public void onDisabled() { stopSprinting(); } - - /** Start sprinting every update tick */ + + /** + * Start sprinting every update tick + */ @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { if (event.getEntityLiving().moveForward > 0 - && !event.getEntityLiving().collidedHorizontally - && !event.getEntityLiving().isSneaking()) { + && !event.getEntityLiving().collidedHorizontally + && !event.getEntityLiving().isSneaking()) { startSprinting(); } } diff --git a/src/main/java/com/matt/forgehax/mods/AutoTool.java b/src/main/java/com/matt/forgehax/mods/AutoTool.java index 723c48a11..c26483e20 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoTool.java +++ b/src/main/java/com/matt/forgehax/mods/AutoTool.java @@ -30,168 +30,173 @@ @RegisterMod public class AutoTool extends ToggleMod { + private static AutoTool instance = null; - + public static AutoTool getInstance() { return instance; } - + private final Setting tools = - getCommandStub() - .builders() - .newSettingBuilder() - .name("tools") - .description("Enables AutoTool when tools") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("tools") + .description("Enables AutoTool when tools") + .defaultTo(true) + .build(); + private final Setting weapons = - getCommandStub() - .builders() - .newSettingBuilder() - .name("weapons") - .description("Enables AutoTool for weapons") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("weapons") + .description("Enables AutoTool for weapons") + .defaultTo(true) + .build(); + private final Setting revert_back = - getCommandStub() - .builders() - .newSettingBuilder() - .name("revert-back") - .description("Revert back to the previous item") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("revert-back") + .description("Revert back to the previous item") + .defaultTo(true) + .build(); + private final Setting durability_threshold = - getCommandStub() - .builders() - .newSettingBuilder() - .name("durability-threshold") - .description( - "Will filter out items with a damage equal to or less than the threshold. Set to 0 to disable.") - .defaultTo(0) - .min(0) - .max((int) Short.MAX_VALUE) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("durability-threshold") + .description( + "Will filter out items with a damage equal to or less than the threshold. Set to 0 to disable.") + .defaultTo(0) + .min(0) + .max((int) Short.MAX_VALUE) + .build(); + public AutoTool() { super(Category.PLAYER, "AutoTool", false, "Automatically switch to the best tool"); instance = this; } - + private boolean isInvincible(InvItem item) { return item.isNull() || !item.getItem().isDamageable(); } - + private boolean isDurabilityGood(InvItem item) { return durability_threshold.get() < 1 - || isInvincible(item) - || item.getDurability() > durability_threshold.get(); + || isInvincible(item) + || item.getDurability() > durability_threshold.get(); } - + private boolean isSilkTouchable(InvItem item, IBlockState state, BlockPos pos) { return LocalPlayerInventory.getSelected().getIndex() == item.getIndex() - && getEnchantmentLevel(Enchantments.SILK_TOUCH, item) > 0 - && state.getBlock().canSilkHarvest(getWorld(), pos, state, getLocalPlayer()); + && getEnchantmentLevel(Enchantments.SILK_TOUCH, item) > 0 + && state.getBlock().canSilkHarvest(getWorld(), pos, state, getLocalPlayer()); } - + private double getDigSpeed(InvItem item, IBlockState state, BlockPos pos) { double str = item.getItemStack().getDestroySpeed(state); int eff = getEnchantmentLevel(EFFICIENCY, item); return state.getBlockHardness(getWorld(), pos) > 0.D - ? Math.max(str + (str > 1.D ? (eff * eff + 1.D) : 0.D), 0.D) - : 1.D; + ? Math.max(str + (str > 1.D ? (eff * eff + 1.D) : 0.D), 0.D) + : 1.D; } - + private double getAttackDamage(InvItem item) { return Optional.ofNullable( - item.getItemStack() - .getAttributeModifiers(EntityEquipmentSlot.MAINHAND) - .get(SharedMonsterAttributes.ATTACK_DAMAGE.getName())) - .map(at -> at.stream().findAny().map(AttributeModifier::getAmount).orElse(0.D)) - .orElse(0.D); + item.getItemStack() + .getAttributeModifiers(EntityEquipmentSlot.MAINHAND) + .get(SharedMonsterAttributes.ATTACK_DAMAGE.getName())) + .map(at -> at.stream().findAny().map(AttributeModifier::getAmount).orElse(0.D)) + .orElse(0.D); } - + private double getAttackSpeed(InvItem item) { return Optional.ofNullable( - item.getItemStack() - .getAttributeModifiers(EntityEquipmentSlot.MAINHAND) - .get(SharedMonsterAttributes.ATTACK_DAMAGE.getName())) - .map( - at -> - at.stream().findAny().map(AttributeModifier::getAmount).map(Math::abs).orElse(0.D)) - .orElse(0.D); - } - + item.getItemStack() + .getAttributeModifiers(EntityEquipmentSlot.MAINHAND) + .get(SharedMonsterAttributes.ATTACK_DAMAGE.getName())) + .map( + at -> + at.stream().findAny().map(AttributeModifier::getAmount).map(Math::abs).orElse(0.D)) + .orElse(0.D); + } + private double getEntityAttackModifier(InvItem item, Entity target) { return EnchantmentHelper.getModifierForCreature( - item.getItemStack(), - Optional.ofNullable(target) - .filter(EntityLivingBase.class::isInstance) - .map(EntityLivingBase.class::cast) - .map(EntityLivingBase::getCreatureAttribute) - .orElse(EnumCreatureAttribute.UNDEFINED)); - } - + item.getItemStack(), + Optional.ofNullable(target) + .filter(EntityLivingBase.class::isInstance) + .map(EntityLivingBase.class::cast) + .map(EntityLivingBase::getCreatureAttribute) + .orElse(EnumCreatureAttribute.UNDEFINED)); + } + private double calculateDPS(InvItem item, Entity target) { return (getAttackDamage(item) + 1.D + getEntityAttackModifier(item, target)) - / (getAttackSpeed(item) + 1.D); + / (getAttackSpeed(item) + 1.D); } - + private int getEnchantmentLevel(Enchantment enchantment, InvItem item) { return EnchantmentHelper.getEnchantmentLevel(enchantment, item.getItemStack()); } - + private InvItem getBestTool(BlockPos pos) { InvItem current = LocalPlayerInventory.getSelected(); - - if (!BlockHelper.isBlockPlaceable(pos) || getWorld().isAirBlock(pos)) return current; - + + if (!BlockHelper.isBlockPlaceable(pos) || getWorld().isAirBlock(pos)) { + return current; + } + final IBlockState state = getWorld().getBlockState(pos); return LocalPlayerInventory.getHotbarInventory() - .stream() - .filter(this::isDurabilityGood) - .max( - Comparator.comparingDouble(item -> getDigSpeed(item, state, pos)) - .thenComparing(item -> isSilkTouchable(item, state, pos)) - .thenComparing(this::isInvincible) - .thenComparing(LocalPlayerInventory::getHotbarDistance)) - .orElse(current); - } - + .stream() + .filter(this::isDurabilityGood) + .max( + Comparator.comparingDouble(item -> getDigSpeed(item, state, pos)) + .thenComparing(item -> isSilkTouchable(item, state, pos)) + .thenComparing(this::isInvincible) + .thenComparing(LocalPlayerInventory::getHotbarDistance)) + .orElse(current); + } + private InvItem getBestWeapon(Entity target) { InvItem current = LocalPlayerInventory.getSelected(); return LocalPlayerInventory.getHotbarInventory() - .stream() - .filter(this::isDurabilityGood) - .max( - Comparator.comparingDouble(item -> calculateDPS(item, target)) - .thenComparing(item -> getEnchantmentLevel(Enchantments.FIRE_ASPECT, item)) - .thenComparing(item -> getEnchantmentLevel(Enchantments.SWEEPING, item)) - .thenComparing(this::isInvincible) - .thenComparing(LocalPlayerInventory::getHotbarDistance)) - .orElse(current); - } - + .stream() + .filter(this::isDurabilityGood) + .max( + Comparator.comparingDouble(item -> calculateDPS(item, target)) + .thenComparing(item -> getEnchantmentLevel(Enchantments.FIRE_ASPECT, item)) + .thenComparing(item -> getEnchantmentLevel(Enchantments.SWEEPING, item)) + .thenComparing(this::isInvincible) + .thenComparing(LocalPlayerInventory::getHotbarDistance)) + .orElse(current); + } + public void selectBestTool(BlockPos pos) { - if (isEnabled() && tools.get()) + if (isEnabled() && tools.get()) { LocalPlayerInventory.setSelected(getBestTool(pos), revert_back.get(), ticks -> ticks > 5); + } } - + public void selectBestWeapon(Entity target) { - if (isEnabled() && weapons.get()) + if (isEnabled() && weapons.get()) { LocalPlayerInventory.setSelected( - getBestWeapon(target), - revert_back.get(), - ticks -> getLocalPlayer().getCooledAttackStrength(0.f) >= 1.f && ticks > 30); + getBestWeapon(target), + revert_back.get(), + ticks -> getLocalPlayer().getCooledAttackStrength(0.f) >= 1.f && ticks > 30); + } } - + @SubscribeEvent public void onBlockBreak(PlayerDamageBlockEvent event) { selectBestTool(event.getPos()); } - + @SubscribeEvent public void onAttackEntity(PlayerAttackEntityEvent event) { selectBestWeapon(event.getVictim()); diff --git a/src/main/java/com/matt/forgehax/mods/AutoTotemMod.java b/src/main/java/com/matt/forgehax/mods/AutoTotemMod.java index 7fa590fe9..352524cc0 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoTotemMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoTotemMod.java @@ -15,48 +15,53 @@ @RegisterMod public class AutoTotemMod extends ToggleMod { - + private final int OFFHAND_SLOT = 45; - + public AutoTotemMod() { super(Category.COMBAT, "AutoTotem", false, "Automatically move totems to off-hand"); } - + @Override public String getDisplayText() { final long totemCount = - IntStream.rangeClosed(9, 45) // include offhand slot - .mapToObj(i -> MC.player.inventoryContainer.getSlot(i).getStack().getItem()) - .filter(stack -> stack == Items.TOTEM_OF_UNDYING) - .count(); + IntStream.rangeClosed(9, 45) // include offhand slot + .mapToObj(i -> MC.player.inventoryContainer.getSlot(i).getStack().getItem()) + .filter(stack -> stack == Items.TOTEM_OF_UNDYING) + .count(); return String.format(super.getDisplayText() + "[%d]", totemCount); } - + @SubscribeEvent public void onPlayerUpdate(LocalPlayerUpdateEvent event) { - if (!getOffhand().isEmpty()) return; // if there's an item in offhand slot - if (MC.currentScreen != null) return; // if in inventory - + if (!getOffhand().isEmpty()) { + return; // if there's an item in offhand slot + } + if (MC.currentScreen != null) { + return; // if in inventory + } + findItem(Items.TOTEM_OF_UNDYING) - .ifPresent( - slot -> { - invPickup(slot); - invPickup(OFFHAND_SLOT); - }); + .ifPresent( + slot -> { + invPickup(slot); + invPickup(OFFHAND_SLOT); + }); } - + private void invPickup(final int slot) { MC.playerController.windowClick(0, slot, 0, ClickType.PICKUP, MC.player); } - + private OptionalInt findItem(final Item ofType) { for (int i = 9; i <= 44; i++) { - if (MC.player.inventoryContainer.getSlot(i).getStack().getItem() == ofType) + if (MC.player.inventoryContainer.getSlot(i).getStack().getItem() == ofType) { return OptionalInt.of(i); + } } return OptionalInt.empty(); } - + private ItemStack getOffhand() { return MC.player.getItemStackFromSlot(EntityEquipmentSlot.OFFHAND); } diff --git a/src/main/java/com/matt/forgehax/mods/AutoWalkMod.java b/src/main/java/com/matt/forgehax/mods/AutoWalkMod.java index 5d522393b..6740527fa 100644 --- a/src/main/java/com/matt/forgehax/mods/AutoWalkMod.java +++ b/src/main/java/com/matt/forgehax/mods/AutoWalkMod.java @@ -13,21 +13,22 @@ @RegisterMod public class AutoWalkMod extends ToggleMod { + public final Setting stop_at_unloaded_chunks = - getCommandStub() - .builders() - .newSettingBuilder() - .name("stop_at_unloaded_chunks") - .description("Stops moving at unloaded chunks") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("stop_at_unloaded_chunks") + .description("Stops moving at unloaded chunks") + .defaultTo(true) + .build(); + private boolean isBound = false; - + public AutoWalkMod() { super(Category.PLAYER, "AutoWalk", false, "Automatically walks forward"); } - + @Override public void onDisabled() { if (isBound) { @@ -36,18 +37,21 @@ public void onDisabled() { isBound = false; } } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { if (!isBound) { Bindings.forward.bind(); isBound = true; } - if (!Bindings.forward.getBinding().isKeyDown()) Bindings.forward.setPressed(true); - + if (!Bindings.forward.getBinding().isKeyDown()) { + Bindings.forward.setPressed(true); + } + if (stop_at_unloaded_chunks.get()) { - if (!getWorld().getChunkFromBlockCoords(getLocalPlayer().getPosition()).isLoaded()) + if (!getWorld().getChunkFromBlockCoords(getLocalPlayer().getPosition()).isLoaded()) { Bindings.forward.setPressed(false); + } } } } diff --git a/src/main/java/com/matt/forgehax/mods/BaritoneCompatibility.java b/src/main/java/com/matt/forgehax/mods/BaritoneCompatibility.java index e0cc53281..6130ecd74 100644 --- a/src/main/java/com/matt/forgehax/mods/BaritoneCompatibility.java +++ b/src/main/java/com/matt/forgehax/mods/BaritoneCompatibility.java @@ -14,71 +14,75 @@ @RegisterMod public class BaritoneCompatibility extends ToggleMod { + private final Setting on_string = - getCommandStub() - .builders() - .newSettingBuilder() - .name("on-string") - .description("Message to enable baritone") - .defaultTo("#mine diamond_ore") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("on-string") + .description("Message to enable baritone") + .defaultTo("#mine diamond_ore") + .build(); + private final Setting off_string = - getCommandStub() - .builders() - .newSettingBuilder() - .name("off-string") - .description("Message to disable baritone") - .defaultTo("#stop") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("off-string") + .description("Message to disable baritone") + .defaultTo("#stop") + .build(); + public BaritoneCompatibility() { super(Category.MISC, "BaritoneCompatibility", false, "the lazy compatibility mod"); } - + private boolean off = false; private boolean once = false; - + private void turnOn() { off = false; getLocalPlayer().sendChatMessage(on_string.get()); } - + private void turnOff() { off = true; getLocalPlayer().sendChatMessage(off_string.get()); } - + @Override protected void onDisabled() { off = once = false; } - + @SubscribeEvent public void onWorldUnload(WorldEvent.Unload event) { onDisabled(); } - + @SubscribeEvent public void onTick(LocalPlayerUpdateEvent event) { - if(!once) { + if (!once) { once = true; BlockPos pos = getLocalPlayer().getPosition(); - if(pos.getX() != 0 && pos.getZ() != 0) { + if (pos.getX() != 0 && pos.getZ() != 0) { turnOn(); } } } - + @SubscribeEvent public void onEvent(ForgeHaxEvent event) { - if(getLocalPlayer() == null) + if (getLocalPlayer() == null) { return; - + } + switch (event.getType()) { case EATING_START: case EATING_SELECT_FOOD: { - if(!off) turnOff(); + if (!off) { + turnOff(); + } break; } case EATING_STOP: { diff --git a/src/main/java/com/matt/forgehax/mods/BedModeMod.java b/src/main/java/com/matt/forgehax/mods/BedModeMod.java index 744bc8758..24a3aecfb 100644 --- a/src/main/java/com/matt/forgehax/mods/BedModeMod.java +++ b/src/main/java/com/matt/forgehax/mods/BedModeMod.java @@ -13,16 +13,17 @@ @RegisterMod public class BedModeMod extends ToggleMod { + public BedModeMod() { super(Category.PLAYER, "BedMode", false, "Sleep walking"); } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { FastReflection.Fields.EntityPlayer_sleeping.set(getLocalPlayer(), false); FastReflection.Fields.EntityPlayer_sleepTimer.set(getLocalPlayer(), 0); } - + @SubscribeEvent public void onGuiUpdate(GuiOpenEvent event) { if (event.getGui() instanceof GuiSleepMP) { diff --git a/src/main/java/com/matt/forgehax/mods/BlockHighlightMod.java b/src/main/java/com/matt/forgehax/mods/BlockHighlightMod.java index 9fb9fda94..84a1d2816 100644 --- a/src/main/java/com/matt/forgehax/mods/BlockHighlightMod.java +++ b/src/main/java/com/matt/forgehax/mods/BlockHighlightMod.java @@ -10,67 +10,67 @@ @RegisterMod public class BlockHighlightMod extends ToggleMod { - + private final Setting alpha = - getCommandStub() - .builders() - .newSettingBuilder() - .name("alpha") - .description("alpha") - .min(0) - .max(255) - .defaultTo(255) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("alpha") + .description("alpha") + .min(0) + .max(255) + .defaultTo(255) + .build(); private final Setting red = - getCommandStub() - .builders() - .newSettingBuilder() - .name("red") - .description("red") - .min(0) - .max(255) - .defaultTo(0) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("red") + .description("red") + .min(0) + .max(255) + .defaultTo(0) + .build(); private final Setting green = - getCommandStub() - .builders() - .newSettingBuilder() - .name("green") - .description("green") - .min(0) - .max(255) - .defaultTo(0) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("green") + .description("green") + .min(0) + .max(255) + .defaultTo(0) + .build(); private final Setting blue = - getCommandStub() - .builders() - .newSettingBuilder() - .name("blue") - .description("blue") - .min(0) - .max(255) - .defaultTo(0) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("blue") + .description("blue") + .min(0) + .max(255) + .defaultTo(0) + .build(); + private final Setting width = - getCommandStub() - .builders() - .newSettingBuilder() - .name("width") - .description("line width") - .min(0.f) - .defaultTo(5.f) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("width") + .description("line width") + .min(0.f) + .defaultTo(5.f) + .build(); + public BlockHighlightMod() { super( - Category.RENDER, "BlockHighlight", false, "Make selected block bounding box more visible"); + Category.RENDER, "BlockHighlight", false, "Make selected block bounding box more visible"); } - + private float toFloat(int colorVal) { return colorVal / 255.f; } - + @SubscribeEvent public void onRenderBoxPre(DrawBlockBoundingBoxEvent.Pre event) { GlStateManager.disableDepth(); @@ -80,7 +80,7 @@ public void onRenderBoxPre(DrawBlockBoundingBoxEvent.Pre event) { event.green = toFloat(green.get()); event.blue = toFloat(blue.get()); } - + @SubscribeEvent public void onRenderBoxPost(DrawBlockBoundingBoxEvent.Post event) { GlStateManager.enableDepth(); diff --git a/src/main/java/com/matt/forgehax/mods/BoatFly.java b/src/main/java/com/matt/forgehax/mods/BoatFly.java index 78de7248d..788f17f09 100644 --- a/src/main/java/com/matt/forgehax/mods/BoatFly.java +++ b/src/main/java/com/matt/forgehax/mods/BoatFly.java @@ -1,6 +1,7 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getRidingEntity; import com.matt.forgehax.asm.ForgeHaxHooks; import com.matt.forgehax.asm.events.RenderBoatEvent; @@ -17,61 +18,61 @@ @RegisterMod public class BoatFly extends ToggleMod { - + public final Setting speed = - getCommandStub() - .builders() - .newSettingBuilder() - .name("speed") - .description("how fast to move") - .defaultTo(5.0D) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("speed") + .description("how fast to move") + .defaultTo(5.0D) + .build(); /*public final Setting maintainY = getCommandStub().builders().newSettingBuilder() .name("YLevel").description("automatically teleport back up to this Y level").defaultTo(0.0D).build();*/ public final Setting speedY = - getCommandStub() - .builders() - .newSettingBuilder() - .name("FallSpeed") - .description("how slowly to fall") - .defaultTo(0.033D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("FallSpeed") + .description("how slowly to fall") + .defaultTo(0.033D) + .build(); + public final Setting setYaw = - getCommandStub() - .builders() - .newSettingBuilder() - .name("SetYaw") - .description("set the boat yaw") - .defaultTo(true) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("SetYaw") + .description("set the boat yaw") + .defaultTo(true) + .build(); public final Setting noClamp = - getCommandStub() - .builders() - .newSettingBuilder() - .name("NoClamp") - .description("clamp view angles") - .defaultTo(true) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("NoClamp") + .description("clamp view angles") + .defaultTo(true) + .build(); public final Setting noGravity = - getCommandStub() - .builders() - .newSettingBuilder() - .name("NoGravity") - .description("disable boat gravity") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("NoGravity") + .description("disable boat gravity") + .defaultTo(true) + .build(); + public BoatFly() { super(Category.MISC, "BoatFly", false, "Boathax"); } - + @SubscribeEvent // disable gravity public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { ForgeHaxHooks.isNoBoatGravityActivated = - getRidingEntity() instanceof EntityBoat; // disable gravity if in boat + getRidingEntity() instanceof EntityBoat; // disable gravity if in boat } - + @Override public void onDisabled() { // ForgeHaxHooks.isNoClampingActivated = false; // disable view clamping @@ -79,12 +80,12 @@ public void onDisabled() { ForgeHaxHooks.isBoatSetYawActivated = false; // ForgeHaxHooks.isNotRowingBoatActivated = false; // items always usable - can not be disabled } - + @Override public void onLoad() { ForgeHaxHooks.isNoClampingActivated = noClamp.getAsBoolean(); } - + @SubscribeEvent public void onRenderBoat(RenderBoatEvent event) { if (EntityUtils.isDrivenByPlayer(event.getBoat()) && setYaw.getAsBoolean()) { @@ -93,60 +94,66 @@ public void onRenderBoat(RenderBoatEvent event) { event.setYaw(yaw); } } - + @SubscribeEvent public void onClientTick(TickEvent.ClientTickEvent event) { // check if the player is really riding a entity if (MC.player != null && MC.player.getRidingEntity() != null) { - + ForgeHaxHooks.isNoClampingActivated = noClamp.getAsBoolean(); ForgeHaxHooks.isNoBoatGravityActivated = noGravity.getAsBoolean(); ForgeHaxHooks.isBoatSetYawActivated = setYaw.getAsBoolean(); - + if (MC.gameSettings.keyBindJump.isKeyDown()) { // trick the riding entity to think its onground MC.player.getRidingEntity().onGround = false; - + // teleport up MC.player.getRidingEntity().motionY = MC.gameSettings.keyBindSprint.isKeyDown() ? 5 : 1.5; } else { MC.player.getRidingEntity().motionY = - MC.gameSettings.keyBindSprint.isKeyDown() ? -1.0 : -speedY.getAsDouble(); + MC.gameSettings.keyBindSprint.isKeyDown() ? -1.0 : -speedY.getAsDouble(); } /*if ((MC.player.posY <= maintainY.getAsDouble()-5D) && (MC.player.posY > maintainY.getAsDouble()-10D) && maintainY.getAsDouble() != 0D) MC.player.getRidingEntity().setPositionAndUpdate(MC.player.posX, maintainY.getAsDouble(), MC.player.posZ );*/ - + setMoveSpeedEntity(speed.getAsDouble()); } } - + public static void setMoveSpeedEntity(double speed) { if (MC.player != null && MC.player.getRidingEntity() != null) { MovementInput movementInput = MC.player.movementInput; double forward = movementInput.moveForward; double strafe = movementInput.moveStrafe; float yaw = MC.player.rotationYaw; - + if ((forward == 0.0D) && (strafe == 0.0D)) { MC.player.getRidingEntity().motionX = (0.0D); MC.player.getRidingEntity().motionZ = (0.0D); } else { if (forward != 0.0D) { - if (strafe > 0.0D) yaw += (forward > 0.0D ? -45 : 45); - else if (strafe < 0.0D) yaw += (forward > 0.0D ? 45 : -45); - + if (strafe > 0.0D) { + yaw += (forward > 0.0D ? -45 : 45); + } else if (strafe < 0.0D) { + yaw += (forward > 0.0D ? 45 : -45); + } + strafe = 0.0D; - - if (forward > 0.0D) forward = 1.0D; - else if (forward < 0.0D) forward = -1.0D; + + if (forward > 0.0D) { + forward = 1.0D; + } else if (forward < 0.0D) { + forward = -1.0D; + } } MC.player.getRidingEntity().motionX = - (forward * speed * Math.cos(Math.toRadians(yaw + 90.0F)) - + strafe * speed * Math.sin(Math.toRadians(yaw + 90.0F))); + (forward * speed * Math.cos(Math.toRadians(yaw + 90.0F)) + + strafe * speed * Math.sin(Math.toRadians(yaw + 90.0F))); MC.player.getRidingEntity().motionZ = - (forward * speed * Math.sin(Math.toRadians(yaw + 90.0F)) - - strafe * speed * Math.cos(Math.toRadians(yaw + 90.0F))); + (forward * speed * Math.sin(Math.toRadians(yaw + 90.0F)) + - strafe * speed * Math.cos(Math.toRadians(yaw + 90.0F))); } } } diff --git a/src/main/java/com/matt/forgehax/mods/BookBot.java b/src/main/java/com/matt/forgehax/mods/BookBot.java index b43dd4271..62819d3fe 100644 --- a/src/main/java/com/matt/forgehax/mods/BookBot.java +++ b/src/main/java/com/matt/forgehax/mods/BookBot.java @@ -31,76 +31,80 @@ import net.minecraft.network.play.client.CPacketCustomPayload; import net.minecraft.util.EnumHand; -/** Created on 12/17/2017 by fr1kin */ +/** + * Created on 12/17/2017 by fr1kin + */ @RegisterMod public class BookBot extends ToggleMod { + private static final int MAX_CHARACTERS_PER_PAGE = 256; private static final int MAX_PAGES = 50; - + public static final String NUMBER_TOKEN = "\\{NUMBER\\}"; - + public static final String NEW_PAGE = ":PAGE:"; - + private final Setting name = - getCommandStub() - .builders() - .newSettingBuilder() - .name("name") - .description("Name of the book, use {NUMBER} for the number") - .defaultTo("Book #{NUMBER}") - .changed( - cb -> { - // 3 digits seems like a reasonable upper limit - String str = cb.getTo().replaceAll(NUMBER_TOKEN, "XXX"); - if (str.length() > 32) - printWarning( - "Final book names longer than 32 letters will cause crashes! Current length (assuming 3 digits): %d", - str.length()); - }) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("name") + .description("Name of the book, use {NUMBER} for the number") + .defaultTo("Book #{NUMBER}") + .changed( + cb -> { + // 3 digits seems like a reasonable upper limit + String str = cb.getTo().replaceAll(NUMBER_TOKEN, "XXX"); + if (str.length() > 32) { + printWarning( + "Final book names longer than 32 letters will cause crashes! Current length (assuming 3 digits): %d", + str.length()); + } + }) + .build(); + private final Setting file = - getCommandStub() - .builders() - .newSettingBuilder() - .name("file") - .description("Name of the file inside the forgehax directory to use") - .defaultTo("") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("file") + .description("Name of the file inside the forgehax directory to use") + .defaultTo("") + .build(); + private final Setting prettify = - getCommandStub() - .builders() - .newSettingBuilder() - .name("prettify") - .description("Enables word wrapping. Can cause book size to increase dramatically") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("prettify") + .description("Enables word wrapping. Can cause book size to increase dramatically") + .defaultTo(true) + .build(); + private final Setting sleep = - getCommandStub() - .builders() - .newSettingBuilder() - .name("sleep") - .description("Sleep time in ms") - .defaultTo(300L) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("sleep") + .description("Sleep time in ms") + .defaultTo(300L) + .build(); + private Thread writerThread = null; private BookWriter writer = null; - + public BookBot() { super(Category.MISC, "BookBot", false, "Automatically write books"); } - + private static final Collection CHARS_NO_REPEATING = - Lists.newArrayList(' ', '\n', '\t', '\r'); - + Lists.newArrayList(' ', '\n', '\t', '\r'); + private static String parseText(String text, boolean wrap) { text = text.replace('\r', '\n').replace('\t', ' ').replace("\0", ""); - + StringBuilder builder = new StringBuilder(); - + char next = '\0', last; int ls = -1; // last space index for (int i = 0, p = i; i < text.length(); i++, p++, p %= MAX_CHARACTERS_PER_PAGE) { @@ -108,27 +112,31 @@ private static String parseText(String text, boolean wrap) { last = next; // next character next = text.charAt(i); - + // start a new page at the initial position - if (p == 0) builder.append(NEW_PAGE); - + if (p == 0) { + builder.append(NEW_PAGE); + } + // if this index contains a space, save the index - if (next == ' ') ls = i; - + if (next == ' ') { + ls = i; + } + // prevent annoying repeating characters if (CHARS_NO_REPEATING.contains(next) && CHARS_NO_REPEATING.contains(last)) { // do not append, go back 1 position to act as if this was never processed p--; continue; } - + // word wrapping logic if (wrap && ls != -1 && last == ' ') { // next space index int ns = text.indexOf(' ', i); // distance from next space to last space int d = ns - ls; - + // if the word (distance between two spaces) is less than the max chars allowed (to prevent // words greater than it from causing an infinite loop), and // the word will not fit onto the current page. @@ -139,163 +147,185 @@ private static String parseText(String text, boolean wrap) { p = 0; } } - + builder.append(next); } - + return builder.toString(); } - + private BookWriter loadFile() throws RuntimeException { - if (file.get().isEmpty()) throw new RuntimeException("No file name set"); - + if (file.get().isEmpty()) { + throw new RuntimeException("No file name set"); + } + Path data = getFileManager().getBaseResolve(file.get()); - - if (!Files.exists(data)) throw new RuntimeException("File not found"); - if (!Files.isRegularFile(data)) throw new RuntimeException("Not a file type"); - + + if (!Files.exists(data)) { + throw new RuntimeException("File not found"); + } + if (!Files.isRegularFile(data)) { + throw new RuntimeException("Not a file type"); + } + String text; try { text = new String(Files.readAllBytes(data), StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException("Failed to read file"); } - + String name = data.getFileName().toString(); if (name.endsWith(".txt") || name.endsWith(".book")) { return new BookWriter(this, name.endsWith(".txt") ? parseText(text, prettify.get()) : text); - } else throw new RuntimeException("File is not a .txt or .book type"); + } else { + throw new RuntimeException("File is not a .txt or .book type"); + } } - + @Override public String getDisplayText() { return this.writer == null - ? super.getDisplayText() - : super.getDisplayText() + "[" + this.writer.toString() + "]"; + ? super.getDisplayText() + : super.getDisplayText() + "[" + this.writer.toString() + "]"; } - + @Override protected void onLoad() { getCommandStub() - .builders() - .newCommandBuilder() - .name("start") - .description("Start book bot. Can optionally set the starting position") - .processor( - data -> { - if (writerThread != null) - throw new RuntimeException("BookBot thread already running!"); - - Integer page = SafeConverter.toInteger(data.getArgument(0), 0); - - if (writer == null) { - writer = loadFile(); - data.write(String.format("BookBot file \"%s\" loaded successfully", file.get())); - } - - writer.setPage(page); - writerThread = new Thread(writer); - writer.start(); - writerThread.start(); - data.write("BookBot task started"); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("start") + .description("Start book bot. Can optionally set the starting position") + .processor( + data -> { + if (writerThread != null) { + throw new RuntimeException("BookBot thread already running!"); + } + + Integer page = SafeConverter.toInteger(data.getArgument(0), 0); + + if (writer == null) { + writer = loadFile(); + data.write(String.format("BookBot file \"%s\" loaded successfully", file.get())); + } + + writer.setPage(page); + writerThread = new Thread(writer); + writer.start(); + writerThread.start(); + data.write("BookBot task started"); + }) + .build(); + getCommandStub() - .builders() - .newCommandBuilder() - .name("reset") - .description("Stop the BookBot task") - .processor( - data -> { - if (writer != null) { - writer.setFinalListener( - o -> ConsoleIO.write("BookBot task stopped at page " + writer.getPage())); - writer.stop(); - writerThread = null; - data.write("Stopping BookBot"); - } else data.write("No writer present"); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("reset") + .description("Stop the BookBot task") + .processor( + data -> { + if (writer != null) { + writer.setFinalListener( + o -> ConsoleIO.write("BookBot task stopped at page " + writer.getPage())); + writer.stop(); + writerThread = null; + data.write("Stopping BookBot"); + } else { + data.write("No writer present"); + } + }) + .build(); + getCommandStub() - .builders() - .newCommandBuilder() - .name("resume") - .description("Resume the BookBot task") - .processor( - data -> { - if (writer != null) { - writerThread = new Thread(writer); - writer.start(); - writerThread.start(); - } else data.write("No writer present"); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("resume") + .description("Resume the BookBot task") + .processor( + data -> { + if (writer != null) { + writerThread = new Thread(writer); + writer.start(); + writerThread.start(); + } else { + data.write("No writer present"); + } + }) + .build(); + getCommandStub() - .builders() - .newCommandBuilder() - .name("delete") - .description("Delete the writer bot instance") - .processor( - data -> { - if (writer != null) { - writer.setFinalListener( - o -> ConsoleIO.write("BookBot task stopped at page " + writer.getPage())); - writer.stop(); - writer = null; - writerThread = null; - data.write("Shutting down BookBot instance"); - } else data.write("No writer present"); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("delete") + .description("Delete the writer bot instance") + .processor( + data -> { + if (writer != null) { + writer.setFinalListener( + o -> ConsoleIO.write("BookBot task stopped at page " + writer.getPage())); + writer.stop(); + writer = null; + writerThread = null; + data.write("Shutting down BookBot instance"); + } else { + data.write("No writer present"); + } + }) + .build(); + getCommandStub() - .builders() - .newCommandBuilder() - .name("load") - .description("Load the file into memory") - .processor( - data -> { - writer = loadFile(); - data.write(String.format("BookBot file \"%s\" loaded successfully", file.get())); - }) - .build(); - + .builders() + .newCommandBuilder() + .name("load") + .description("Load the file into memory") + .processor( + data -> { + writer = loadFile(); + data.write(String.format("BookBot file \"%s\" loaded successfully", file.get())); + }) + .build(); + getCommandStub() - .builders() - .newCommandBuilder() - .name("save") - .description("Save the contents to a .book file in the forgehax folder") - .processor( - data -> { - String fname = data.getArgument(0); - - // optional argument, if not given use name from file variable and rename the - // extension to .book - if (fname == null || fname.isEmpty()) { - fname = file.get(); - if (!fname.endsWith(".book")) fname = fname.substring(0, fname.lastIndexOf('.')); - } - if (!fname.endsWith(".book")) fname += ".book"; // append extension type - - if (writer != null) { - try(BufferedWriter out = Files.newBufferedWriter( - getFileManager().getBaseResolve(fname), - StandardCharsets.UTF_8, - StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { - out.write(writer.contents); - data.write("Successfully saved book data"); - } catch (IOException e) { - data.write("Failed to write file"); - } - } else data.write("No writer present"); - }) - .build(); + .builders() + .newCommandBuilder() + .name("save") + .description("Save the contents to a .book file in the forgehax folder") + .processor( + data -> { + String fname = data.getArgument(0); + + // optional argument, if not given use name from file variable and rename the + // extension to .book + if (fname == null || fname.isEmpty()) { + fname = file.get(); + if (!fname.endsWith(".book")) { + fname = fname.substring(0, fname.lastIndexOf('.')); + } + } + if (!fname.endsWith(".book")) { + fname += ".book"; // append extension type + } + + if (writer != null) { + try (BufferedWriter out = Files.newBufferedWriter( + getFileManager().getBaseResolve(fname), + StandardCharsets.UTF_8, + StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { + out.write(writer.contents); + data.write("Successfully saved book data"); + } catch (IOException e) { + data.write("Failed to write file"); + } + } else { + data.write("No writer present"); + } + }) + .build(); } - + private static class BookWriter implements Runnable { + public enum Status { INITIALIZED, FINISHED, @@ -308,26 +338,26 @@ public enum Status { CLOSING_BOOK, WRITING_BOOK, } - + private final BookBot parent; private final String contents; - + private final int totalPages; - + private volatile Status status = Status.INITIALIZED; private volatile boolean stopped = false; - + private Scanner parser; - + private int page = 0; - + private Consumer finalListener = null; - + public BookWriter(BookBot parent, String contents) { this.parent = parent; this.contents = contents; Scanner scanner = newScanner(); - + int c = 0; while (scanner.hasNext()) { scanner.next(); @@ -335,84 +365,90 @@ public BookWriter(BookBot parent, String contents) { } this.totalPages = c; } - + private Scanner newScanner() { return new Scanner(contents).useDelimiter(NEW_PAGE); } - + public int getTotalPages() { return totalPages; } - + public int getTotalBooks() { return totalPages > 0 ? (int) Math.ceil((double) (totalPages) / (double) (MAX_PAGES)) : 0; } - + public Status getStatus() { return status; } - + public int getPage() { return page; } - + public void setPage(int page) { - if (parser != null) + if (parser != null) { throw new RuntimeException("Cannot set position while task is running or stopped"); + } this.page = page; } - + public int getBook() { return page > 0 ? (int) Math.ceil((double) (page) / (double) (MAX_PAGES)) : 0; } - + public void setFinalListener(Consumer finalListener) { this.finalListener = finalListener; } - + public boolean isStopped() { return stopped; } - + public void start() { if (parser == null) { parser = newScanner(); - + // skip pages - for (int i = 0; i < page && parser.hasNext(); i++) parser.next(); + for (int i = 0; i < page && parser.hasNext(); i++) { + parser.next(); + } } stopped = false; finalListener = null; } - + public void stop() { stopped = true; } - + private void sendBook(ItemStack stack) { NBTTagList pages = new NBTTagList(); // page tag list - + // copy pages into NBT for (int i = 0; i < MAX_PAGES && parser.hasNext(); i++) { pages.appendTag(new NBTTagString(parser.next().trim())); page++; } - + // set our client side book - if (stack.hasTagCompound()) stack.getTagCompound().setTag("pages", pages); - else stack.setTagInfo("pages", pages); - + if (stack.hasTagCompound()) { + stack.getTagCompound().setTag("pages", pages); + } else { + stack.setTagInfo("pages", pages); + } + // publish the book stack.setTagInfo("author", new NBTTagString(getLocalPlayer().getName())); stack.setTagInfo( - "title", - new NBTTagString(parent.name.get().replaceAll(NUMBER_TOKEN, "" + getBook()).trim())); - + "title", + new NBTTagString(parent.name.get().replaceAll(NUMBER_TOKEN, "" + getBook()).trim())); + PacketBuffer buff = new PacketBuffer(Unpooled.buffer()); buff.writeItemStack(stack); MC.getConnection().sendPacket(new CPacketCustomPayload("MC|BSign", buff)); } - + @Override public void run() { try { @@ -422,61 +458,65 @@ public void run() { this.status = Status.FINISHED; break; } - + sleep(); - + // wait for screen if (MC.currentScreen != null) { this.status = Status.AWAITING_GUI_CLOSE; continue; } - + // search for empty book int slot = -1; ItemStack selected = null; for (int i = 0; i < InventoryPlayer.getHotbarSize(); i++) { ItemStack stack = getLocalPlayer().inventory.getStackInSlot(i); if (stack != null - && !stack.equals(ItemStack.EMPTY) - && stack.getItem() instanceof ItemWritableBook) { + && !stack.equals(ItemStack.EMPTY) + && stack.getItem() instanceof ItemWritableBook) { slot = i; selected = stack; break; } } - + // make sure we found a book if (slot == -1) { this.status = Status.NEED_EMPTY_BOOKS_IN_HOTBAR; continue; } - + // set selected item to that slot while (getLocalPlayer().inventory.currentItem != slot) { getLocalPlayer().inventory.currentItem = slot; this.status = Status.CHANGING_HELD_ITEM; sleep(); } - + final ItemStack item = selected; - + // open the book gui screen this.status = Status.OPENING_BOOK; MC.addScheduledTask(() -> getLocalPlayer().openBook(item, EnumHand.MAIN_HAND)); - + // wait for gui to open - while (!(MC.currentScreen instanceof GuiScreenBook)) sleep(); - + while (!(MC.currentScreen instanceof GuiScreenBook)) { + sleep(); + } + // send book to server this.status = Status.WRITING_BOOK; MC.addScheduledTask( - () -> { - sendBook(item); - MC.displayGuiScreen(null); - }); - + () -> { + sendBook(item); + MC.displayGuiScreen(null); + }); + // wait for screen to close - while (MC.currentScreen != null) sleep(); + while (MC.currentScreen != null) { + sleep(); + } } } catch (Throwable t) { this.status = Status.ERROR; @@ -485,25 +525,28 @@ public void run() { finalListener.accept(this); finalListener = null; } - + // set stopped to true this.stopped = true; - - if (!this.status.equals(Status.FINISHED) && !this.status.equals(Status.ERROR)) + + if (!this.status.equals(Status.FINISHED) && !this.status.equals(Status.ERROR)) { this.status = Status.STOPPED; + } } } - + @Override public String toString() { return String.format( - "Status=%s,P/T=%d/%d,B/T=%d/%d", - status.name(), page, getTotalPages(), getBook(), getTotalBooks()); + "Status=%s,P/T=%d/%d,B/T=%d/%d", + status.name(), page, getTotalPages(), getBook(), getTotalBooks()); } - + private void sleep() throws InterruptedException { Thread.sleep(parent.sleep.get()); - if (stopped) throw new RuntimeException("Thread stopped"); + if (stopped) { + throw new RuntimeException("Thread stopped"); + } } } } diff --git a/src/main/java/com/matt/forgehax/mods/ChamsMod.java b/src/main/java/com/matt/forgehax/mods/ChamsMod.java index 5618cfc79..3fefee259 100644 --- a/src/main/java/com/matt/forgehax/mods/ChamsMod.java +++ b/src/main/java/com/matt/forgehax/mods/ChamsMod.java @@ -13,53 +13,54 @@ @RegisterMod public class ChamsMod extends ToggleMod { + public final Setting players = - getCommandStub() - .builders() - .newSettingBuilder() - .name("players") - .description("Enables players") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("players") + .description("Enables players") + .defaultTo(true) + .build(); + public final Setting mobs_hostile = - getCommandStub() - .builders() - .newSettingBuilder() - .name("mobs_hostile") - .description("Enables hostile mobs") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("mobs_hostile") + .description("Enables hostile mobs") + .defaultTo(true) + .build(); + public final Setting mobs_friendly = - getCommandStub() - .builders() - .newSettingBuilder() - .name("mobs_friendly") - .description("Enables friendly mobs") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("mobs_friendly") + .description("Enables friendly mobs") + .defaultTo(true) + .build(); + public ChamsMod() { super(Category.RENDER, "Chams", false, "Render living models behind walls"); } - + public boolean shouldDraw(EntityLivingBase entity) { return !entity.equals(MC.player) - && !entity.isDead - && ((mobs_hostile.get() && EntityUtils.isHostileMob(entity)) - || // check this first - (players.get() && EntityUtils.isPlayer(entity)) - || (mobs_friendly.get() && EntityUtils.isFriendlyMob(entity))); + && !entity.isDead + && ((mobs_hostile.get() && EntityUtils.isHostileMob(entity)) + || // check this first + (players.get() && EntityUtils.isPlayer(entity)) + || (mobs_friendly.get() && EntityUtils.isFriendlyMob(entity))); } - + @SubscribeEvent public void onPreRenderLiving(RenderLivingEvent.Pre event) { GL11.glEnable(GL11.GL_POLYGON_OFFSET_FILL); GlStateManager.enablePolygonOffset(); GlStateManager.doPolygonOffset(1.0F, -1000000); } - + @SubscribeEvent public void onPostRenderLiving(RenderLivingEvent.Post event) { GL11.glDisable(GL11.GL_POLYGON_OFFSET_FILL); diff --git a/src/main/java/com/matt/forgehax/mods/ChatBot.java b/src/main/java/com/matt/forgehax/mods/ChatBot.java index d121434b8..6fc18c4f6 100644 --- a/src/main/java/com/matt/forgehax/mods/ChatBot.java +++ b/src/main/java/com/matt/forgehax/mods/ChatBot.java @@ -33,40 +33,41 @@ @RegisterMod public class ChatBot extends ToggleMod { + private final Options spams = - getCommandStub() - .builders() - .newOptionsBuilder() - .name("spam") - .description("Contents to spam") - .factory(SpamEntry::new) - .supplier(Sets::newConcurrentHashSet) - .build(); - + getCommandStub() + .builders() + .newOptionsBuilder() + .name("spam") + .description("Contents to spam") + .factory(SpamEntry::new) + .supplier(Sets::newConcurrentHashSet) + .build(); + private final Setting max_input_length = - getCommandStub() - .builders() - .newSettingBuilder() - .name("max_input_length") - .description("Maximum chat input length allowed") - .defaultTo(16) - .min(0) - .max(256) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("max_input_length") + .description("Maximum chat input length allowed") + .defaultTo(16) + .min(0) + .max(256) + .build(); + private final Setting resetSequentialIndex = getCommandStub() - .builders() - .newSettingBuilder() - .name("reset-sequential") - .description("start spam list anew in sequential mode") - .defaultTo(false) - .build(); - + .builders() + .newSettingBuilder() + .name("reset-sequential") + .description("start spam list anew in sequential mode") + .defaultTo(false) + .build(); + public ChatBot() { super(Category.MISC, "ChatBot", false, "Spam chat"); } - + @Override protected void onDisabled() { if (resetSequentialIndex.get()) { @@ -75,353 +76,369 @@ protected void onDisabled() { } } } - + @Override protected void onLoad() { spams - .builders() - .newCommandBuilder() - .name("add") - .description("Add new spam list") - .options( - parser -> { - parser.accepts("keyword", "Message activation keyword").withRequiredArg(); - parser.accepts("type", "Spam type (random, sequential)").withRequiredArg(); - parser - .accepts( - "trigger", - "How the spam will be triggered (spam, reply, reply_with_input, player_connect, player_disconnect)") - .withRequiredArg(); - parser.accepts("enabled", "Enabled").withRequiredArg(); - parser - .accepts("delay", "Custom delay between messages of the same type") - .withRequiredArg(); - }) - .processor( - data -> { - data.requiredArguments(1); - String name = data.getArgumentAsString(0); - - boolean givenInput = - data.hasOption("keyword") - || data.hasOption("type") - || data.hasOption("trigger") - || data.hasOption("enabled") - || data.hasOption("delay"); - - SpamEntry entry = spams.get(name); - if (entry == null) { - entry = new SpamEntry(name); - spams.add(entry); - data.write("Added new entry \"" + name + "\""); - } - - if (data.hasOption("keyword")) entry.setKeyword(data.getOptionAsString("keyword")); - if (data.hasOption("type")) entry.setType(data.getOptionAsString("type")); - if (data.hasOption("trigger")) entry.setTrigger(data.getOptionAsString("trigger")); - if (data.hasOption("enabled")) - entry.setEnabled(SafeConverter.toBoolean(data.getOptionAsString("enabled"))); - if (!entry.isEnabled() && resetSequentialIndex.get()) entry.reset(); - if (data.hasOption("delay")) - entry.setDelay(SafeConverter.toLong(data.getOptionAsString("delay"))); - - if (data.getArgumentCount() == 2) { - String msg = data.getArgumentAsString(1); - entry.add(msg); - data.write("Added message \"" + msg + "\""); - } - - if (givenInput) { - data.write("keyword=" + entry.getKeyword()); - data.write("type=" + entry.getType().name()); - data.write("trigger=" + entry.getTrigger().name()); - data.write("enabled=" + Boolean.toString(entry.isEnabled())); - data.write("delay=" + Long.toString(entry.getDelay())); - } - - data.markSuccess(); - }) - .success(e -> spams.serialize()) - .build(); - + .builders() + .newCommandBuilder() + .name("add") + .description("Add new spam list") + .options( + parser -> { + parser.accepts("keyword", "Message activation keyword").withRequiredArg(); + parser.accepts("type", "Spam type (random, sequential)").withRequiredArg(); + parser + .accepts( + "trigger", + "How the spam will be triggered (spam, reply, reply_with_input, player_connect, player_disconnect)") + .withRequiredArg(); + parser.accepts("enabled", "Enabled").withRequiredArg(); + parser + .accepts("delay", "Custom delay between messages of the same type") + .withRequiredArg(); + }) + .processor( + data -> { + data.requiredArguments(1); + String name = data.getArgumentAsString(0); + + boolean givenInput = + data.hasOption("keyword") + || data.hasOption("type") + || data.hasOption("trigger") + || data.hasOption("enabled") + || data.hasOption("delay"); + + SpamEntry entry = spams.get(name); + if (entry == null) { + entry = new SpamEntry(name); + spams.add(entry); + data.write("Added new entry \"" + name + "\""); + } + + if (data.hasOption("keyword")) { + entry.setKeyword(data.getOptionAsString("keyword")); + } + if (data.hasOption("type")) { + entry.setType(data.getOptionAsString("type")); + } + if (data.hasOption("trigger")) { + entry.setTrigger(data.getOptionAsString("trigger")); + } + if (data.hasOption("enabled")) { + entry.setEnabled(SafeConverter.toBoolean(data.getOptionAsString("enabled"))); + } + if (!entry.isEnabled() && resetSequentialIndex.get()) { + entry.reset(); + } + if (data.hasOption("delay")) { + entry.setDelay(SafeConverter.toLong(data.getOptionAsString("delay"))); + } + + if (data.getArgumentCount() == 2) { + String msg = data.getArgumentAsString(1); + entry.add(msg); + data.write("Added message \"" + msg + "\""); + } + + if (givenInput) { + data.write("keyword=" + entry.getKeyword()); + data.write("type=" + entry.getType().name()); + data.write("trigger=" + entry.getTrigger().name()); + data.write("enabled=" + Boolean.toString(entry.isEnabled())); + data.write("delay=" + Long.toString(entry.getDelay())); + } + + data.markSuccess(); + }) + .success(e -> spams.serialize()) + .build(); + spams - .builders() - .newCommandBuilder() - .name("import") - .description("Import a txt or json file") - .processor( - data -> { - data.requiredArguments(2); - String name = data.getArgumentAsString(0); - String fileN = data.getArgumentAsString(1); - - SpamEntry entry = spams.get(name); - if (entry == null) { - entry = new SpamEntry(name); - spams.add(entry); - data.write("Added new entry \"" + name + "\""); - } - - Path file = getFileManager().getBaseResolve(fileN); - if (Files.exists(file)) { - if (fileN.endsWith(".json")) { - try { - JsonParser parser = new JsonParser(); - JsonElement element = parser.parse(new String(Files.readAllBytes(file))); - if (element.isJsonArray()) { - JsonArray head = (JsonArray) element; - int count = 0; - for (JsonElement e : head) { - if (e.isJsonPrimitive()) { - String str = e.getAsString(); - entry.add(str); - ++count; - } - } - data.write("Successfully imported " + count + " messages"); - } else { - data.write("Json head must be a JsonArray"); - } - } catch (Throwable t) { - data.write("Failed parsing json: " + t.getMessage()); - } - } else if (fileN.endsWith(".txt")) { - try { - Scanner scanner = new Scanner(file); - int count = 0; - while (scanner.hasNextLine()) { - String next = scanner.nextLine(); - if (!Strings.isNullOrEmpty(next)) { - entry.add(next); - ++count; - } + .builders() + .newCommandBuilder() + .name("import") + .description("Import a txt or json file") + .processor( + data -> { + data.requiredArguments(2); + String name = data.getArgumentAsString(0); + String fileN = data.getArgumentAsString(1); + + SpamEntry entry = spams.get(name); + if (entry == null) { + entry = new SpamEntry(name); + spams.add(entry); + data.write("Added new entry \"" + name + "\""); + } + + Path file = getFileManager().getBaseResolve(fileN); + if (Files.exists(file)) { + if (fileN.endsWith(".json")) { + try { + JsonParser parser = new JsonParser(); + JsonElement element = parser.parse(new String(Files.readAllBytes(file))); + if (element.isJsonArray()) { + JsonArray head = (JsonArray) element; + int count = 0; + for (JsonElement e : head) { + if (e.isJsonPrimitive()) { + String str = e.getAsString(); + entry.add(str); + ++count; } - data.write("Successfully imported " + count + " messages"); - } catch (Throwable t) { - data.write("Failed parsing text: " + t.getMessage()); } + data.write("Successfully imported " + count + " messages"); } else { - data.write( - "Invalid file extension for \"" + fileN + "\" (requires .txt or .json)"); + data.write("Json head must be a JsonArray"); } - } else { - data.write("Could not find file \"" + fileN + "\" in base directory"); - } - }) - .success(e -> spams.serialize()) - .build(); - - spams - .builders() - .newCommandBuilder() - .name("export") - .description("Export all the contents of an entry") - .processor( - data -> { - data.requiredArguments(2); - String name = data.getArgumentAsString(0); - String fileN = data.getArgumentAsString(1); - - SpamEntry entry = spams.get(name); - if (entry == null) { - data.write("No such entry: " + name); - return; + } catch (Throwable t) { + data.write("Failed parsing json: " + t.getMessage()); } - - if (!fileN.endsWith(".json") && !fileN.endsWith(".txt")) fileN += ".txt"; - - Path file = getFileManager().getBaseResolve(fileN); - + } else if (fileN.endsWith(".txt")) { try { - if (!Files.isDirectory(file.getParent())) Files.createDirectories(file.getParent()); - - if (name.endsWith(".json")) { - final JsonArray head = new JsonArray(); - entry.getMessages().forEach(str -> head.add(new JsonPrimitive(str))); - Files.write(file, GsonConstant.GSON_PRETTY.toJson(head).getBytes()); - } else { - final StringBuilder builder = new StringBuilder(); - entry - .getMessages() - .forEach( - str -> { - builder.append(str); - builder.append('\n'); - }); - Files.write(file, builder.toString().getBytes()); + Scanner scanner = new Scanner(file); + int count = 0; + while (scanner.hasNextLine()) { + String next = scanner.nextLine(); + if (!Strings.isNullOrEmpty(next)) { + entry.add(next); + ++count; + } } - data.markSuccess(); + data.write("Successfully imported " + count + " messages"); } catch (Throwable t) { - data.write("Failed exporting file: " + t.getMessage()); + data.write("Failed parsing text: " + t.getMessage()); } - }) - .build(); - + } else { + data.write( + "Invalid file extension for \"" + fileN + "\" (requires .txt or .json)"); + } + } else { + data.write("Could not find file \"" + fileN + "\" in base directory"); + } + }) + .success(e -> spams.serialize()) + .build(); + spams - .builders() - .newCommandBuilder() - .name("remove") - .description("Remove spam entry") - .processor( - data -> { - data.requiredArguments(1); - String name = data.getArgumentAsString(0); - - SpamEntry entry = spams.get(name); - if (entry != null) { - spams.remove(entry); - data.write("Removed entry \"" + name + "\""); - data.markSuccess(); - } else { - data.write("Invalid entry \"" + name + "\""); - data.markFailed(); - } - }) - .success(e -> spams.serialize()) - .build(); - - spams - .builders() - .newCommandBuilder() - .name("list") - .description("List all current entries") - .processor( - data -> { + .builders() + .newCommandBuilder() + .name("export") + .description("Export all the contents of an entry") + .processor( + data -> { + data.requiredArguments(2); + String name = data.getArgumentAsString(0); + String fileN = data.getArgumentAsString(1); + + SpamEntry entry = spams.get(name); + if (entry == null) { + data.write("No such entry: " + name); + return; + } + + if (!fileN.endsWith(".json") && !fileN.endsWith(".txt")) { + fileN += ".txt"; + } + + Path file = getFileManager().getBaseResolve(fileN); + + try { + if (!Files.isDirectory(file.getParent())) { + Files.createDirectories(file.getParent()); + } + + if (name.endsWith(".json")) { + final JsonArray head = new JsonArray(); + entry.getMessages().forEach(str -> head.add(new JsonPrimitive(str))); + Files.write(file, GsonConstant.GSON_PRETTY.toJson(head).getBytes()); + } else { final StringBuilder builder = new StringBuilder(); - Iterator it = spams.iterator(); - while (it.hasNext()) { - SpamEntry next = it.next(); - builder.append(next.getName()); - if (it.hasNext()) builder.append(", "); - } - data.write(builder.toString()); - data.markSuccess(); - }) - .build(); + entry + .getMessages() + .forEach( + str -> { + builder.append(str); + builder.append('\n'); + }); + Files.write(file, builder.toString().getBytes()); + } + data.markSuccess(); + } catch (Throwable t) { + data.write("Failed exporting file: " + t.getMessage()); + } + }) + .build(); + + spams + .builders() + .newCommandBuilder() + .name("remove") + .description("Remove spam entry") + .processor( + data -> { + data.requiredArguments(1); + String name = data.getArgumentAsString(0); + + SpamEntry entry = spams.get(name); + if (entry != null) { + spams.remove(entry); + data.write("Removed entry \"" + name + "\""); + data.markSuccess(); + } else { + data.write("Invalid entry \"" + name + "\""); + data.markFailed(); + } + }) + .success(e -> spams.serialize()) + .build(); + + spams + .builders() + .newCommandBuilder() + .name("list") + .description("List all current entries") + .processor( + data -> { + final StringBuilder builder = new StringBuilder(); + Iterator it = spams.iterator(); + while (it.hasNext()) { + SpamEntry next = it.next(); + builder.append(next.getName()); + if (it.hasNext()) { + builder.append(", "); + } + } + data.write(builder.toString()); + data.markSuccess(); + }) + .build(); } - + @SubscribeEvent public void onTick(LocalPlayerUpdateEvent event) { - if (SpamService.isEmpty() && !spams.isEmpty()) + if (SpamService.isEmpty() && !spams.isEmpty()) { for (SpamEntry e : spams) { if (e.isEnabled() && !e.isEmpty() && e.getTrigger().equals(SpamTrigger.SPAM)) { SpamService.send( - new SpamMessage( - e.next(), - "SPAM" + e.getName(), - e.getDelay(), - "self" + e.getName().toLowerCase(), - PriorityEnum.DEFAULT)); + new SpamMessage( + e.next(), + "SPAM" + e.getName(), + e.getDelay(), + "self" + e.getName().toLowerCase(), + PriorityEnum.DEFAULT)); return; } } + } } - + @SubscribeEvent public void onChat(ChatMessageEvent event) { - if (event.getSender().isLocalPlayer()) return; - + if (event.getSender().isLocalPlayer()) { + return; + } + String[] args = event.getMessage().split(" "); final String sender = event.getSender().getId().toString(); final String keyword = ArrayHelper.getOrDefault(args, 0, Strings.EMPTY); final String arg = ArrayHelper.getOrDefault(args, 1, Strings.EMPTY); spams - .stream() - .filter(SpamEntry::isEnabled) - .filter(e -> e.getKeyword().equalsIgnoreCase(keyword)) - .forEach( - e -> { - switch (e.getTrigger()) { - case REPLY: - { - SpamService.send( - new SpamMessage( - SpamTokens.SENDER_NAME.fill(e.next(), event.getSender().getName()), - "REPLY" + e.getName(), - e.getDelay(), - sender, - PriorityEnum.HIGH)); - break; - } - case REPLY_WITH_INPUT: - { - if (!Strings.isNullOrEmpty(arg) && arg.length() <= max_input_length.get()) - SpamService.send( - new SpamMessage( - SpamTokens.fillAll( - e.next(), - SpamTokens.PLAYERNAME_SENDERNAME, - arg, - event.getSender().getName()), - "REPLY_WITH_INPUT" + e.getName(), - e.getDelay(), - sender, - PriorityEnum.HIGH)); - break; - } - default: - break; + .stream() + .filter(SpamEntry::isEnabled) + .filter(e -> e.getKeyword().equalsIgnoreCase(keyword)) + .forEach( + e -> { + switch (e.getTrigger()) { + case REPLY: { + SpamService.send( + new SpamMessage( + SpamTokens.SENDER_NAME.fill(e.next(), event.getSender().getName()), + "REPLY" + e.getName(), + e.getDelay(), + sender, + PriorityEnum.HIGH)); + break; + } + case REPLY_WITH_INPUT: { + if (!Strings.isNullOrEmpty(arg) && arg.length() <= max_input_length.get()) { + SpamService.send( + new SpamMessage( + SpamTokens.fillAll( + e.next(), + SpamTokens.PLAYERNAME_SENDERNAME, + arg, + event.getSender().getName()), + "REPLY_WITH_INPUT" + e.getName(), + e.getDelay(), + sender, + PriorityEnum.HIGH)); } - }); + break; + } + default: + break; + } + }); } - + @SubscribeEvent public void onPlayerConnect(PlayerConnectEvent.Join event) { final String player = event.getProfile() != null ? event.getProfile().getName() : "null"; spams - .stream() - .filter(SpamEntry::isEnabled) - .forEach( - e -> { - switch (e.getTrigger()) { - case PLAYER_CONNECT: - { - SpamService.send( - new SpamMessage( - SpamTokens.fillAll( - e.next(), - SpamTokens.PLAYERNAME_NAMEHISTORY, - player, - event.getPlayerInfo().getNameHistoryAsString()), - "PLAYER_CONNECT" + e.getName(), - e.getDelay(), - null, - PriorityEnum.HIGH)); - break; - } - default: - break; - } - }); + .stream() + .filter(SpamEntry::isEnabled) + .forEach( + e -> { + switch (e.getTrigger()) { + case PLAYER_CONNECT: { + SpamService.send( + new SpamMessage( + SpamTokens.fillAll( + e.next(), + SpamTokens.PLAYERNAME_NAMEHISTORY, + player, + event.getPlayerInfo().getNameHistoryAsString()), + "PLAYER_CONNECT" + e.getName(), + e.getDelay(), + null, + PriorityEnum.HIGH)); + break; + } + default: + break; + } + }); } - + @SubscribeEvent public void onPlayerDisconnect(PlayerConnectEvent.Leave event) { final String player = event.getProfile() != null ? event.getProfile().getName() : "null"; spams - .stream() - .filter(SpamEntry::isEnabled) - .forEach( - e -> { - switch (e.getTrigger()) { - case PLAYER_DISCONNECT: - { - SpamService.send( - new SpamMessage( - SpamTokens.fillAll( - e.next(), - SpamTokens.PLAYERNAME_NAMEHISTORY, - player, - event.getPlayerInfo().getNameHistoryAsString()), - "PLAYER_DISCONNECT" + e.getName(), - e.getDelay(), - null, - PriorityEnum.HIGH)); - break; - } - default: - break; - } - }); + .stream() + .filter(SpamEntry::isEnabled) + .forEach( + e -> { + switch (e.getTrigger()) { + case PLAYER_DISCONNECT: { + SpamService.send( + new SpamMessage( + SpamTokens.fillAll( + e.next(), + SpamTokens.PLAYERNAME_NAMEHISTORY, + player, + event.getPlayerInfo().getNameHistoryAsString()), + "PLAYER_DISCONNECT" + e.getName(), + e.getDelay(), + null, + PriorityEnum.HIGH)); + break; + } + default: + break; + } + }); } } diff --git a/src/main/java/com/matt/forgehax/mods/ChunkLogger.java b/src/main/java/com/matt/forgehax/mods/ChunkLogger.java index 9ae670f14..84f462c0c 100644 --- a/src/main/java/com/matt/forgehax/mods/ChunkLogger.java +++ b/src/main/java/com/matt/forgehax/mods/ChunkLogger.java @@ -1,17 +1,17 @@ package com.matt.forgehax.mods; -import com.github.lunatrius.core.client.renderer.unique.GeometryMasks; -import com.github.lunatrius.core.client.renderer.unique.GeometryTessellator; import com.google.common.collect.EvictingQueue; import com.google.common.collect.Lists; import com.google.common.collect.Queues; import com.matt.forgehax.asm.events.PacketEvent; import com.matt.forgehax.events.RenderEvent; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.command.Setting; import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; +import com.matt.forgehax.util.tesselation.GeometryMasks; +import com.matt.forgehax.util.tesselation.GeometryTessellator; import java.util.List; import java.util.Objects; import java.util.Queue; @@ -24,88 +24,91 @@ import net.minecraftforge.event.world.ChunkEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 10/12/2017 by fr1kin */ +/** + * Created on 10/12/2017 by fr1kin + */ @RegisterMod public class ChunkLogger extends ToggleMod { + public ChunkLogger() { super(Category.MISC, "ChunkLogger", false, "Show new chunks"); } - + enum ShowChunkEnum { ALL, NEW_ONLY, OLD_ONLY, ; } - + enum DetectionMethodEnum { IS_FULL_CHUNK, TIMING, BLOCK_CHANGE_THRESHOLD, DECORATOR_BLOCKS_DETECTED, } - + private final Setting max_chunks = - getCommandStub() - .builders() - .newSettingBuilder() - .name("max-chunks") - .description("Maximum chunks to render (set to 0 for infinite)") - .defaultTo(5120) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("max-chunks") + .description("Maximum chunks to render (set to 0 for infinite)") + .defaultTo(5120) + .build(); + private final Setting clear_on_toggle = - getCommandStub() - .builders() - .newSettingBuilder() - .name("clear-on-toggle") - .description("Clear chunk list on disable") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("clear-on-toggle") + .description("Clear chunk list on disable") + .defaultTo(true) + .build(); + private final Setting show_only = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("show-only") - .description("Specify which chunk to only show") - .defaultTo(ShowChunkEnum.ALL) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("show-only") + .description("Specify which chunk to only show") + .defaultTo(ShowChunkEnum.ALL) + .build(); + private final Setting detection_method = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("detection-method") - .description( - "Specify the method to detect new chunks. Currently only IS_FULL_CHUNK is supported.") - .defaultTo(DetectionMethodEnum.IS_FULL_CHUNK) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("detection-method") + .description( + "Specify the method to detect new chunks. Currently only IS_FULL_CHUNK is supported.") + .defaultTo(DetectionMethodEnum.IS_FULL_CHUNK) + .build(); + private final Setting flag_timing = - getCommandStub() - .builders() - .newSettingBuilder() - .name("flag-timing") - .description( - "Maximum time in MS that another chunk load in succession will trigger it to be marked as a new chunk") - .defaultTo(1000L) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("flag-timing") + .description( + "Maximum time in MS that another chunk load in succession will trigger it to be marked as a new chunk") + .defaultTo(1000L) + .build(); + private final Setting block_change_threshold = - getCommandStub() - .builders() - .newSettingBuilder() - .name("block-change-threshold") - .description( - "Maximum number of blocks required to change between chunk loading in order to be marked as a new chunk") - .defaultTo(100) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("block-change-threshold") + .description( + "Maximum number of blocks required to change between chunk loading in order to be marked as a new chunk") + .defaultTo(100) + .build(); + private final Lock chunkLock = new ReentrantLock(); - + private Queue chunks = null; - + void addChunk(SPacketChunkData packet) { if (chunks != null) { chunkLock.lock(); @@ -124,18 +127,21 @@ void addChunk(SPacketChunkData packet) { } } } - + @Override protected void onEnabled() { chunkLock.lock(); try { - if (max_chunks.get() <= 0) chunks = Queues.newArrayDeque(); - else chunks = EvictingQueue.create(max_chunks.get()); + if (max_chunks.get() <= 0) { + chunks = Queues.newArrayDeque(); + } else { + chunks = EvictingQueue.create(max_chunks.get()); + } } finally { chunkLock.unlock(); } } - + @Override protected void onDisabled() { if (clear_on_toggle.get() && chunks != null) { @@ -148,12 +154,13 @@ protected void onDisabled() { } } } - + @SubscribeEvent public void onChunkLoad(ChunkEvent.Load event) { - if (chunks != null) {} + if (chunks != null) { + } } - + @SubscribeEvent public void onPacketInbound(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketChunkData) { @@ -161,13 +168,15 @@ public void onPacketInbound(PacketEvent.Incoming.Pre event) { addChunk(packet); } } - + @SubscribeEvent public void onRender(RenderEvent event) { - if (chunks == null) return; - + if (chunks == null) { + return; + } + event.getTessellator().beginLines(); - + List copy; chunkLock.lock(); try { @@ -175,83 +184,93 @@ public void onRender(RenderEvent event) { } finally { chunkLock.unlock(); } - + copy.forEach( - chunk -> { - switch (show_only.get()) { - case NEW_ONLY: - if (!chunk.isNewChunk()) return; - break; - case OLD_ONLY: - if (chunk.isNewChunk()) return; - break; - case ALL: - default: - break; - } - - int color = chunk.isNewChunk() ? Utils.Colors.WHITE : Utils.Colors.RED; - - GeometryTessellator.drawQuads( - event.getBuffer(), - chunk.bbox.minX, - chunk.bbox.minY, - chunk.bbox.minZ, - chunk.bbox.maxX, - chunk.bbox.maxY, - chunk.bbox.maxZ, - GeometryMasks.Quad.ALL, - color); - }); - + chunk -> { + switch (show_only.get()) { + case NEW_ONLY: + if (!chunk.isNewChunk()) { + return; + } + break; + case OLD_ONLY: + if (chunk.isNewChunk()) { + return; + } + break; + case ALL: + default: + break; + } + + int color = chunk.isNewChunk() ? Colors.WHITE.toBuffer() : Colors.RED.toBuffer(); + + GeometryTessellator.drawQuads( + event.getBuffer(), + chunk.bbox.minX, + chunk.bbox.minY, + chunk.bbox.minZ, + chunk.bbox.maxX, + chunk.bbox.maxY, + chunk.bbox.maxZ, + GeometryMasks.Quad.ALL, + color); + }); + event.getTessellator().draw(); } - - private interface ChunkLoadThread extends Callable {} - + + private interface ChunkLoadThread extends Callable { + + } + private class ChunkData { + final ChunkPos pos; final AxisAlignedBB bbox; final boolean isFullChunk; // initial chunk - + boolean isNewByFullChunk = false; boolean isNewByTiming = false; boolean isNewByBlockCount = false; boolean isNewByDecoratorBlocks = false; - + boolean updatedIsFullChunk; - + long timeArrived = -1; long previousTimeArrived; - + int blockCount = 0; int previousBlockCount; - + ChunkData(SPacketChunkData packet) { pos = new ChunkPos(packet.getChunkX(), packet.getChunkZ()); bbox = - new AxisAlignedBB(pos.getXStart(), 0, pos.getZStart(), pos.getXEnd(), 255, pos.getZEnd()); + new AxisAlignedBB(pos.getXStart(), 0, pos.getZStart(), pos.getXEnd(), 255, pos.getZEnd()); isFullChunk = packet.isFullChunk(); update(packet); } - + void update(SPacketChunkData packet) { updatedIsFullChunk = packet.isFullChunk(); - if (!updatedIsFullChunk) isNewByFullChunk = true; - + if (!updatedIsFullChunk) { + isNewByFullChunk = true; + } + previousTimeArrived = timeArrived; timeArrived = System.currentTimeMillis(); - - if (getTimeDifference() != -1 && getTimeDifference() <= flag_timing.get()) + + if (getTimeDifference() != -1 && getTimeDifference() <= flag_timing.get()) { isNewByTiming = true; - + } + previousBlockCount = blockCount; } - + long getTimeDifference() { return previousTimeArrived == -1 ? -1 : previousTimeArrived - timeArrived; } - + boolean isNewChunk() { switch (detection_method.get()) { case IS_FULL_CHUNK: @@ -261,15 +280,15 @@ boolean isNewChunk() { } return false; } - + @Override public boolean equals(Object obj) { return obj == this - || (obj instanceof ChunkData - && this.pos.x == ((ChunkData) obj).pos.x - && this.pos.z == ((ChunkData) obj).pos.z); + || (obj instanceof ChunkData + && this.pos.x == ((ChunkData) obj).pos.x + && this.pos.z == ((ChunkData) obj).pos.z); } - + @Override public int hashCode() { return Objects.hash(pos.x, pos.z); diff --git a/src/main/java/com/matt/forgehax/mods/ClientChunkSize.java b/src/main/java/com/matt/forgehax/mods/ClientChunkSize.java index 4acf4685a..a61537506 100644 --- a/src/main/java/com/matt/forgehax/mods/ClientChunkSize.java +++ b/src/main/java/com/matt/forgehax/mods/ClientChunkSize.java @@ -27,35 +27,45 @@ @RegisterMod public class ClientChunkSize extends ToggleMod { + private static final File DUMMY = getFileManager().getBaseResolve("dummy").toFile(); - + private final SimpleTimer timer = new SimpleTimer(); - + private boolean running = false; private long size = 0L; private long previousSize = 0L; private ChunkPos current = null; - + public ClientChunkSize() { super(Category.MISC, "ClientChunkSize", false, "Shows the client-side chunk size in bytes"); } - + private static String toFormattedBytes(long size) { NumberFormat format = NumberFormat.getInstance(); format.setGroupingUsed(true); if (size < 1000) // less than 1KB - return format.format(size) + " B"; - else if (size < 1000000) // less than 1MB - return format.format((double) size / 1000.D) + " KB"; - else return format.format((double) size / 1000000.D) + " MB"; + { + return format.format(size) + " B"; + } else if (size < 1000000) // less than 1MB + { + return format.format((double) size / 1000.D) + " KB"; + } else { + return format.format((double) size / 1000000.D) + " MB"; + } } - + private static String difference(long size) { - if (size == 0) return "+0 B"; - if (size > 0) return "+" + toFormattedBytes(size); - else return "-" + toFormattedBytes(Math.abs(size)); + if (size == 0) { + return "+0 B"; + } + if (size > 0) { + return "+" + toFormattedBytes(size); + } else { + return "-" + toFormattedBytes(Math.abs(size)); + } } - + @Override protected void onEnabled() { timer.reset(); @@ -63,77 +73,82 @@ protected void onEnabled() { size = previousSize = 0L; current = null; } - + @Override public String getDisplayText() { return super.getDisplayText() - + " " - + String.format( - "[%s | %s]", - size == -1 ? "" : toFormattedBytes(size), difference(size - previousSize)); + + " " + + String.format( + "[%s | %s]", + size == -1 ? "" : toFormattedBytes(size), difference(size - previousSize)); } - + @SubscribeEvent public void onTick(ClientTickEvent event) { - if (getWorld() == null || getLocalPlayer() == null || running) return; - + if (getWorld() == null || getLocalPlayer() == null || running) { + return; + } + switch (event.phase) { - case END: - { - Chunk chunk = getWorld().getChunkFromBlockCoords(getLocalPlayer().getPosition()); - if (chunk.isEmpty()) return; - - ChunkPos pos = chunk.getPos(); - if (!pos.equals(current) || (timer.isStarted() && timer.hasTimeElapsed(1000L))) { - // chunk changed, don't show diff between different chunks - if (current != null && !pos.equals(current)) size = previousSize = 0L; - - current = pos; - running = true; - - // process size calculation on another thread - Executors.defaultThreadFactory() - .newThread( - () -> { - try { - final NBTTagCompound root = new NBTTagCompound(); - NBTTagCompound level = new NBTTagCompound(); - root.setTag("Level", level); - root.setInteger("DataVersion", 1337); - - try { - // this should be done on the main mc thread but it works 99% of the - // time outside it - AnvilChunkLoader loader = new AnvilChunkLoader(DUMMY, null); - Methods.AnvilChunkLoader_writeChunkToNBT.invoke( - loader, chunk, getWorld(), level); - } catch (Throwable t) { - size = -1L; - previousSize = 0L; - return; // couldn't save chunk - } - - DataOutputStream compressed = - new DataOutputStream( - new BufferedOutputStream( - new DeflaterOutputStream(new ByteArrayOutputStream(8096)))); - try { - CompressedStreamTools.write(root, compressed); - previousSize = size; - size = compressed.size(); - } catch (IOException e) { - size = -1L; - previousSize = 0L; - } - } finally { - timer.start(); - running = false; - } - }) - .start(); + case END: { + Chunk chunk = getWorld().getChunkFromBlockCoords(getLocalPlayer().getPosition()); + if (chunk.isEmpty()) { + return; + } + + ChunkPos pos = chunk.getPos(); + if (!pos.equals(current) || (timer.isStarted() && timer.hasTimeElapsed(1000L))) { + // chunk changed, don't show diff between different chunks + if (current != null && !pos.equals(current)) { + size = previousSize = 0L; } - break; + + current = pos; + running = true; + + // process size calculation on another thread + Executors.defaultThreadFactory() + .newThread( + () -> { + try { + final NBTTagCompound root = new NBTTagCompound(); + NBTTagCompound level = new NBTTagCompound(); + root.setTag("Level", level); + root.setInteger("DataVersion", 1337); + + try { + // this should be done on the main mc thread but it works 99% of the + // time outside it + AnvilChunkLoader loader = new AnvilChunkLoader(DUMMY, null); + Methods.AnvilChunkLoader_writeChunkToNBT.invoke( + loader, chunk, getWorld(), level); + } catch (Throwable t) { + size = -1L; + previousSize = 0L; + return; // couldn't save chunk + } + + DataOutputStream compressed = + new DataOutputStream( + new BufferedOutputStream( + new DeflaterOutputStream(new ByteArrayOutputStream(8096)))); + try { + CompressedStreamTools.write(root, compressed); + previousSize = size; + size = compressed.size(); + } catch (IOException e) { + size = -1L; + previousSize = 0L; + } + } finally { + timer.start(); + running = false; + } + }) + .start(); } + break; + } default: break; } diff --git a/src/main/java/com/matt/forgehax/mods/CompassMod.java b/src/main/java/com/matt/forgehax/mods/CompassMod.java index 1864d21e5..7359804e3 100644 --- a/src/main/java/com/matt/forgehax/mods/CompassMod.java +++ b/src/main/java/com/matt/forgehax/mods/CompassMod.java @@ -2,7 +2,7 @@ import com.matt.forgehax.Helper; import com.matt.forgehax.events.Render2DEvent; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.command.Setting; import com.matt.forgehax.util.draw.SurfaceHelper; import com.matt.forgehax.util.mod.Category; @@ -10,66 +10,68 @@ import com.matt.forgehax.util.mod.loader.RegisterMod; import net.minecraft.util.math.MathHelper; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import org.apache.commons.lang3.ArrayUtils; -/** Created by Babbaj on 10/28/2017. */ +/** + * Created by Babbaj on 10/28/2017. + */ @RegisterMod public class CompassMod extends ToggleMod { - + public final Setting scale = - getCommandStub() - .builders() - .newSettingBuilder() - .name("scale") - .description("size of the compass") - .defaultTo(3.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("scale") + .description("size of the compass") + .defaultTo(3.D) + .build(); + private static final double HALF_PI = Math.PI / 2; - + private enum Direction { N, W, S, E } - + public CompassMod() { super(Category.RENDER, "Compass", false, "cool compass overlay"); } - + @SubscribeEvent public void onRender(Render2DEvent event) { final double centerX = event.getScreenWidth() / 2; final double centerY = event.getScreenHeight() * 0.8; - + for (Direction dir : Direction.values()) { double rad = getPosOnCompass(dir); SurfaceHelper.drawTextShadowCentered( - dir.name(), - (float) (centerX + getX(rad)), - (float) (centerY + getY(rad)), - dir == Direction.N ? Utils.Colors.RED : Utils.Colors.WHITE); - + dir.name(), + (float) (centerX + getX(rad)), + (float) (centerY + getY(rad)), + dir == Direction.N ? Colors.RED.toBuffer() : Colors.WHITE.toBuffer()); + } - + } - + private double getX(double rad) { return Math.sin(rad) * (scale.getAsDouble() * 10); } - + private double getY(double rad) { - final double epicPitch = MathHelper.clamp(Helper.getLocalPlayer().rotationPitch + 30f, -90f, 90f); + final double epicPitch = MathHelper + .clamp(Helper.getLocalPlayer().rotationPitch + 30f, -90f, 90f); final double pitchRadians = Math.toRadians(epicPitch); // player pitch return Math.cos(rad) * Math.sin(pitchRadians) * (scale.getAsDouble() * 10); } - + // return the position on the circle in radians private static double getPosOnCompass(Direction dir) { double yaw = - Math.toRadians( - MathHelper.wrapDegrees(Helper.getLocalPlayer().rotationYaw - 90)); // player yaw + Math.toRadians( + MathHelper.wrapDegrees(Helper.getLocalPlayer().rotationYaw - 90)); // player yaw int index = dir.ordinal() + 1; return yaw + (index * HALF_PI); } diff --git a/src/main/java/com/matt/forgehax/mods/CustomPayloadLogger.java b/src/main/java/com/matt/forgehax/mods/CustomPayloadLogger.java index 9aab96311..cb6f612ed 100644 --- a/src/main/java/com/matt/forgehax/mods/CustomPayloadLogger.java +++ b/src/main/java/com/matt/forgehax/mods/CustomPayloadLogger.java @@ -14,55 +14,58 @@ import net.minecraft.network.play.server.SPacketCustomPayload; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 6/1/2017 by fr1kin */ +/** + * Created on 6/1/2017 by fr1kin + */ @RegisterMod public class CustomPayloadLogger extends ToggleMod { + private static final Path CLIENT_PAYLOAD_LOG = - getFileManager().getMkBaseResolve("logs/payload/client2server_payload.log"); + getFileManager().getMkBaseResolve("logs/payload/client2server_payload.log"); private static final Path SERVER_PAYLOAD_LOG = - getFileManager().getMkBaseResolve("logs/payload/server2client_payload.log"); - + getFileManager().getMkBaseResolve("logs/payload/server2client_payload.log"); + public CustomPayloadLogger() { super(Category.MISC, "PayloadLogger", false, "Logs custom payloads"); } - + private void log(Packet packet) { if (packet instanceof SPacketCustomPayload) { SPacketCustomPayload payloadPacket = (SPacketCustomPayload) packet; String input = - String.format( - "%s=%s\n", - payloadPacket.getChannelName(), payloadPacket.getBufferData().toString()); + String.format( + "%s=%s\n", + payloadPacket.getChannelName(), payloadPacket.getBufferData().toString()); try { Files.write( - SERVER_PAYLOAD_LOG, - input.getBytes(), - StandardOpenOption.CREATE, - StandardOpenOption.APPEND); + SERVER_PAYLOAD_LOG, + input.getBytes(), + StandardOpenOption.CREATE, + StandardOpenOption.APPEND); } catch (Exception e) { } } else if (packet instanceof CPacketCustomPayload) { CPacketCustomPayload payloadPacket = (CPacketCustomPayload) packet; String input = - String.format( - "%s=%s\n", - payloadPacket.getChannelName(), payloadPacket.getBufferData().toString()); + String.format( + "%s=%s\n", + payloadPacket.getChannelName(), payloadPacket.getBufferData().toString()); try { Files.write( - CLIENT_PAYLOAD_LOG, - input.getBytes(), - StandardOpenOption.CREATE, - StandardOpenOption.APPEND); + CLIENT_PAYLOAD_LOG, + input.getBytes(), + StandardOpenOption.CREATE, + StandardOpenOption.APPEND); } catch (Exception e) { } } } - + @SubscribeEvent public void onOutgoingCustomPayload(PacketEvent.Outgoing.Pre event) { log(event.getPacket()); } - + @SubscribeEvent public void onIncomingCustomPayload(PacketEvent.Incoming.Pre event) { log(event.getPacket()); diff --git a/src/main/java/com/matt/forgehax/mods/ESP.java b/src/main/java/com/matt/forgehax/mods/ESP.java index e48d7f92e..cd1b0f8d9 100644 --- a/src/main/java/com/matt/forgehax/mods/ESP.java +++ b/src/main/java/com/matt/forgehax/mods/ESP.java @@ -5,11 +5,12 @@ import com.google.common.util.concurrent.AtomicDouble; import com.matt.forgehax.events.Render2DEvent; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Color; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.command.Setting; -import com.matt.forgehax.util.draw.Fonts; import com.matt.forgehax.util.draw.SurfaceBuilder; import com.matt.forgehax.util.draw.SurfaceHelper; +import com.matt.forgehax.util.draw.font.Fonts; import com.matt.forgehax.util.entity.EntityUtils; import com.matt.forgehax.util.math.Plane; import com.matt.forgehax.util.math.VectorUtils; @@ -32,132 +33,140 @@ @RegisterMod public class ESP extends ToggleMod implements Fonts { + private static final int HEALTHBAR_WIDTH = 15; private static final int HEALTHBAR_HEIGHT = 3; - + public enum DrawOptions { DISABLED, NAME, SIMPLE, ADVANCED, } - + public enum ArmorOptions { DISABLED, SIMPLE, ENCHANTMENTS } - + public final Setting players = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("players") - .description("Enables players") - .defaultTo(DrawOptions.NAME) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("players") + .description("Enables players") + .defaultTo(DrawOptions.NAME) + .build(); + public final Setting mobs_hostile = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("hostile") - .description("Enables hostile mobs") - .defaultTo(DrawOptions.NAME) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("hostile") + .description("Enables hostile mobs") + .defaultTo(DrawOptions.NAME) + .build(); + public final Setting mobs_friendly = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("friendly") - .description("Enables friendly mobs") - .defaultTo(DrawOptions.NAME) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("friendly") + .description("Enables friendly mobs") + .defaultTo(DrawOptions.NAME) + .build(); + public ESP() { super(Category.RENDER, "ESP", false, "Shows entity locations and info"); } - + @SubscribeEvent public void onRenderPlayerNameTag(RenderLivingEvent.Specials.Pre event) { - if (EntityUtils.isPlayer(event.getEntity())) event.setCanceled(true); + if (EntityUtils.isPlayer(event.getEntity())) { + event.setCanceled(true); + } } - + @SubscribeEvent(priority = EventPriority.LOW) public void onRender2D(final Render2DEvent event) { getWorld() - .loadedEntityList - .stream() - .filter(EntityUtils::isLiving) - .filter( - entity -> - !Objects.equals(getLocalPlayer(), entity) && !EntityUtils.isFakeLocalPlayer(entity)) - .filter(EntityUtils::isAlive) - .filter(EntityUtils::isValidEntity) - .map(entity -> (EntityLivingBase) entity) - .forEach( - living -> { - final Setting setting; - - switch (EntityUtils.getRelationship(living)) { - case PLAYER: - setting = players; - break; - case HOSTILE: - setting = mobs_hostile; - break; - case NEUTRAL: - case FRIENDLY: - setting = mobs_friendly; - break; - default: - setting = null; - break; - } - - if (setting == null || DrawOptions.DISABLED.equals(setting.get())) return; - - Vec3d bottomPos = EntityUtils.getInterpolatedPos(living, event.getPartialTicks()); - Vec3d topPos = - bottomPos.addVector(0.D, living.getRenderBoundingBox().maxY - living.posY, 0.D); - - Plane top = VectorUtils.toScreen(topPos); - Plane bot = VectorUtils.toScreen(bottomPos); - - // stop here if neither are visible - if (!top.isVisible() && !bot.isVisible()) return; - - double topX = top.getX(); - double topY = top.getY() + 1.D; - double botX = bot.getX(); - double botY = bot.getY() + 1.D; - double height = (bot.getY() - top.getY()); - double width = height; - - AtomicDouble offset = new AtomicDouble(); - TopComponents.REVERSE_VALUES - .stream() - .filter(comp -> comp.valid(setting)) - .forEach( - comp -> { - double os = offset.get(); - offset.set( - os - + comp.draw( - event.getSurfaceBuilder(), - living, - topX, - topY - os, - botX, - botY, - width, - height)); - }); - }); + .loadedEntityList + .stream() + .filter(EntityUtils::isLiving) + .filter( + entity -> + !Objects.equals(getLocalPlayer(), entity) && !EntityUtils.isFakeLocalPlayer(entity)) + .filter(EntityUtils::isAlive) + .filter(EntityUtils::isValidEntity) + .map(entity -> (EntityLivingBase) entity) + .forEach( + living -> { + final Setting setting; + + switch (EntityUtils.getRelationship(living)) { + case PLAYER: + setting = players; + break; + case HOSTILE: + setting = mobs_hostile; + break; + case NEUTRAL: + case FRIENDLY: + setting = mobs_friendly; + break; + default: + setting = null; + break; + } + + if (setting == null || DrawOptions.DISABLED.equals(setting.get())) { + return; + } + + Vec3d bottomPos = EntityUtils.getInterpolatedPos(living, event.getPartialTicks()); + Vec3d topPos = + bottomPos.addVector(0.D, living.getRenderBoundingBox().maxY - living.posY, 0.D); + + Plane top = VectorUtils.toScreen(topPos); + Plane bot = VectorUtils.toScreen(bottomPos); + + // stop here if neither are visible + if (!top.isVisible() && !bot.isVisible()) { + return; + } + + double topX = top.getX(); + double topY = top.getY() + 1.D; + double botX = bot.getX(); + double botY = bot.getY() + 1.D; + double height = (bot.getY() - top.getY()); + double width = height; + + AtomicDouble offset = new AtomicDouble(); + TopComponents.REVERSE_VALUES + .stream() + .filter(comp -> comp.valid(setting)) + .forEach( + comp -> { + double os = offset.get(); + offset.set( + os + + comp.draw( + event.getSurfaceBuilder(), + living, + topX, + topY - os, + botX, + botY, + width, + height)); + }); + }); } - + private interface IComponent { + /** * Draw component * @@ -171,59 +180,56 @@ private interface IComponent { * @return y offset */ double draw( - SurfaceBuilder builder, - EntityLivingBase living, - double topX, - double topY, - double botX, - double botY, - double width, - double height); - + SurfaceBuilder builder, + EntityLivingBase living, + double topX, + double topY, + double botX, + double botY, + double width, + double height); + /** * Check if the draw component is valid for this setting - * - * @param setting - * @return */ boolean valid(Setting setting); } - + private enum TopComponents implements IComponent { NAME { @Override public double draw( - SurfaceBuilder builder, - EntityLivingBase living, - double topX, - double topY, - double botX, - double botY, - double width, - double height) { + SurfaceBuilder builder, + EntityLivingBase living, + double topX, + double topY, + double botX, + double botY, + double width, + double height) { String text = living.getDisplayName().getUnformattedText(); - + double x = topX - ((double) builder.getFontWidth(text) / 2.D); double y = topY - (double) builder.getFontHeight() - 1.D; - + builder - .reset() - .push() - .task(SurfaceBuilder::enableBlend) - .task(SurfaceBuilder::enableFontRendering) - .task(SurfaceBuilder::enableTexture2D) // enable texture - .fontRenderer(ARIAL) - .color(Utils.Colors.BLACK) - .text(text, x + 1, y + 1) - .color(Utils.Colors.WHITE) - .text(text, x, y) - .task(SurfaceBuilder::disableBlend) - .task(SurfaceBuilder::disableFontRendering) - .pop(); - + .reset() + .push() + .task(SurfaceBuilder::enableBlend) + .task(SurfaceBuilder::enableFontRendering) + .task(SurfaceBuilder::enableTexture2D) // enable texture + .fontRenderer(ARIAL) + .color(Colors.BLACK.toBuffer()) + .text(text, x + 1, y + 1) + .color(Colors.WHITE.toBuffer()) + .text(text, x, y) + .task(SurfaceBuilder::disableBlend) + .task(SurfaceBuilder::disableFontRendering) + .pop(); + return SurfaceHelper.getTextHeight() + 1.D; } - + @Override public boolean valid(Setting setting) { return DrawOptions.DISABLED.compareTo(setting.get()) < 0; // DISABLED less than SETTING @@ -232,71 +238,71 @@ public boolean valid(Setting setting) { HEALTH { @Override public double draw( - SurfaceBuilder builder, - EntityLivingBase living, - double topX, - double topY, - double botX, - double botY, - double width, - double height) { + SurfaceBuilder builder, + EntityLivingBase living, + double topX, + double topY, + double botX, + double botY, + double width, + double height) { float hp = - MathHelper.clamp(living.getHealth(), 0, living.getMaxHealth()) / living.getMaxHealth(); + MathHelper.clamp(living.getHealth(), 0, living.getMaxHealth()) / living.getMaxHealth(); double x = topX - (HEALTHBAR_WIDTH / 2); double y = topY - HEALTHBAR_HEIGHT - 2; int color = - (living.getHealth() + living.getAbsorptionAmount() > living.getMaxHealth()) - ? Utils.Colors.YELLOW - : Utils.toRGBA( - (int) ((255 - hp) * 255), - (int) (255 * hp), - 0, - 255); // if above 20 hp bar is yellow - + (living.getHealth() + living.getAbsorptionAmount() > living.getMaxHealth()) + ? Colors.YELLOW.toBuffer() + : Color.of( + (int) ((255 - hp) * 255), + (int) (255 * hp), + 0, + 255).toBuffer(); // if above 20 hp bar is yellow + builder - .reset() // clean up from previous uses - .push() - .task(SurfaceBuilder::enableBlend) - .task(SurfaceBuilder::disableTexture2D) - .beginQuads() - .color(Utils.Colors.BLACK) - .rectangle(x, y, HEALTHBAR_WIDTH, HEALTHBAR_HEIGHT) - .end() - .reset() - .beginQuads() - .color(color) - .rectangle( - x + 1.D, y + 1.D, ((double) HEALTHBAR_WIDTH - 2.D) * hp, HEALTHBAR_HEIGHT - 2.D) - .end() - .task(SurfaceBuilder::disableBlend) - .task(SurfaceBuilder::enableTexture2D) - .pop(); - + .reset() // clean up from previous uses + .push() + .task(SurfaceBuilder::enableBlend) + .task(SurfaceBuilder::disableTexture2D) + .beginQuads() + .color(Colors.BLACK.toBuffer()) + .rectangle(x, y, HEALTHBAR_WIDTH, HEALTHBAR_HEIGHT) + .end() + .reset() + .beginQuads() + .color(color) + .rectangle( + x + 1.D, y + 1.D, ((double) HEALTHBAR_WIDTH - 2.D) * hp, HEALTHBAR_HEIGHT - 2.D) + .end() + .task(SurfaceBuilder::disableBlend) + .task(SurfaceBuilder::enableTexture2D) + .pop(); + return HEALTHBAR_HEIGHT + 1.D; } - + @Override public boolean valid(Setting setting) { return DrawOptions.SIMPLE.compareTo(setting.get()) - <= 0; // SIMPLE less than or equal to SETTING + <= 0; // SIMPLE less than or equal to SETTING } }, ITEMS { @Override public double draw( - SurfaceBuilder builder, - EntityLivingBase living, - double topX, - double topY, - double botX, - double botY, - double width, - double height) { + SurfaceBuilder builder, + EntityLivingBase living, + double topX, + double topY, + double botX, + double botY, + double width, + double height) { List items = - StreamSupport.stream(living.getEquipmentAndArmor().spliterator(), false) - .filter(Objects::nonNull) - .filter(stack -> !stack.isEmpty()) - .collect(Collectors.toList()); + StreamSupport.stream(living.getEquipmentAndArmor().spliterator(), false) + .filter(Objects::nonNull) + .filter(stack -> !stack.isEmpty()) + .collect(Collectors.toList()); if (!items.isEmpty()) { // only continue if there are elements present final double itemSize = 16; double x = topX - ((itemSize * (double) items.size()) / 2.D); @@ -305,28 +311,30 @@ public double draw( ItemStack stack = items.get(index); double xx = x + (index * itemSize); builder - .reset() - .push() - .task(SurfaceBuilder::clearColor) - .task(SurfaceBuilder::enableItemRendering) - .item(stack, xx, y) - .itemOverlay(stack, xx, y) - .task(SurfaceBuilder::disableItemRendering) - .pop(); + .reset() + .push() + .task(SurfaceBuilder::clearColor) + .task(SurfaceBuilder::enableItemRendering) + .item(stack, xx, y) + .itemOverlay(stack, xx, y) + .task(SurfaceBuilder::disableItemRendering) + .pop(); } return itemSize + 1.D; - } else return 0.D; + } else { + return 0.D; + } } - + @Override public boolean valid(Setting setting) { return DrawOptions.ADVANCED.compareTo(setting.get()) - <= 0; // ADVANCED less than or equal to SETTING + <= 0; // ADVANCED less than or equal to SETTING } }; - + static final List REVERSE_VALUES = Arrays.asList(TopComponents.values()); - + static { Collections.reverse(REVERSE_VALUES); } diff --git a/src/main/java/com/matt/forgehax/mods/ElytraFlight.java b/src/main/java/com/matt/forgehax/mods/ElytraFlight.java index 53bb4ea38..cb838d10d 100644 --- a/src/main/java/com/matt/forgehax/mods/ElytraFlight.java +++ b/src/main/java/com/matt/forgehax/mods/ElytraFlight.java @@ -18,41 +18,44 @@ @RegisterMod public class ElytraFlight extends ToggleMod { + public final Setting fly_on_enable = - getCommandStub() - .builders() - .newSettingBuilder() - .name("fly_on_enable") - .description("Start flying when enabled") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("fly_on_enable") + .description("Start flying when enabled") + .defaultTo(false) + .build(); + public final Setting speed = - getCommandStub() - .builders() - .newSettingBuilder() - .name("speed") - .description("Movement speed") - .defaultTo(0.05D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("speed") + .description("Movement speed") + .defaultTo(0.05D) + .build(); + private final Handle flying = LocalPlayerUtils.getFlySwitch().createHandle(getModName()); - + public ElytraFlight() { super(Category.PLAYER, "ElytraFlight", false, "Elytra Flight"); } - + @Override protected void onEnabled() { - if (fly_on_enable.get()) + if (fly_on_enable.get()) { MC.addScheduledTask( - () -> { - if (getLocalPlayer() != null && !getLocalPlayer().isElytraFlying()) - getNetworkManager() - .sendPacket(new CPacketEntityAction(getLocalPlayer(), Action.START_FALL_FLYING)); - }); + () -> { + if (getLocalPlayer() != null && !getLocalPlayer().isElytraFlying()) { + getNetworkManager() + .sendPacket(new CPacketEntityAction(getLocalPlayer(), Action.START_FALL_FLYING)); + } + }); + } } - + @Override public void onDisabled() { flying.disable(); @@ -60,10 +63,10 @@ public void onDisabled() { if (getLocalPlayer() != null) { // Ensure the player starts flying again. getNetworkManager() - .sendPacket(new CPacketEntityAction(getLocalPlayer(), Action.START_FALL_FLYING)); + .sendPacket(new CPacketEntityAction(getLocalPlayer(), Action.START_FALL_FLYING)); } } - + @SubscribeEvent @SideOnly(Side.CLIENT) public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { diff --git a/src/main/java/com/matt/forgehax/mods/ExtraInventory.java b/src/main/java/com/matt/forgehax/mods/ExtraInventory.java index 506d6b4aa..dca055133 100644 --- a/src/main/java/com/matt/forgehax/mods/ExtraInventory.java +++ b/src/main/java/com/matt/forgehax/mods/ExtraInventory.java @@ -15,14 +15,29 @@ import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; import java.io.IOException; -import java.util.*; +import java.util.Arrays; +import java.util.Comparator; +import java.util.EnumSet; +import java.util.List; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import net.minecraft.client.gui.inventory.GuiInventory; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.init.Items; -import net.minecraft.inventory.*; -import net.minecraft.item.*; +import net.minecraft.inventory.ClickType; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.ContainerPlayer; +import net.minecraft.inventory.Slot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemArmor; +import net.minecraft.item.ItemArrow; +import net.minecraft.item.ItemAxe; +import net.minecraft.item.ItemFood; +import net.minecraft.item.ItemPickaxe; +import net.minecraft.item.ItemShulkerBox; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemSword; import net.minecraft.network.play.client.CPacketClickWindow; import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; @@ -31,44 +46,45 @@ @RegisterMod public class ExtraInventory extends ToggleMod { + private static final int GUI_INVENTORY_ID = 0; - + private final Setting auto_store = - getCommandStub() - .builders() - .newSettingBuilder() - .name("auto-store") - .description( - "Automatically store items in the extra inventory slots when the main inventory is full") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("auto-store") + .description( + "Automatically store items in the extra inventory slots when the main inventory is full") + .defaultTo(false) + .build(); + private final Setting delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("delay") - .description("Delay between window clicks (in MS)") - .defaultTo(500L) - .min(0L) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("delay") + .description("Delay between window clicks (in MS)") + .defaultTo(500L) + .min(0L) + .build(); + private TaskChain nextClickTask = null; - + private GuiInventory openedGui = null; private AtomicBoolean guiNeedsClose = new AtomicBoolean(false); private boolean guiCloseGuard = false; - + private SimpleTimer clickTimer = new SimpleTimer(); - + public ExtraInventory() { super( - Category.PLAYER, - "ExtraInventory", - false, - "Allows one to carry up to 5 extra items in their inventory"); + Category.PLAYER, + "ExtraInventory", + false, + "Allows one to carry up to 5 extra items in their inventory"); } - + private GuiInventory createGuiWrapper(GuiInventory gui) { try { GuiInventoryWrapper wrapper = new GuiInventoryWrapper(); @@ -79,11 +95,11 @@ private GuiInventory createGuiWrapper(GuiInventory gui) { return null; } } - + private boolean isCraftingSlotsAvailable() { return getPlayerContainer().isPresent(); } - + private TaskChain getSlotSettingTask(Slot source, EasyIndex destination) { final Slot dst = getSlot(destination); // copy the original slot for later integrity checks @@ -95,13 +111,13 @@ private TaskChain getSlotSettingTask(Slot source, EasyIndex destination) { // pick up the item checkContainerIntegrity(); checkSlotIntegrity(source, srcCopy); - + ItemStack moved = - getCurrentContainer() - .slotClick(source.slotNumber, 0, ClickType.PICKUP, getLocalPlayer()); + getCurrentContainer() + .slotClick(source.slotNumber, 0, ClickType.PICKUP, getLocalPlayer()); getNetworkManager() - .sendPacket(newClickPacket(source.slotNumber, 0, ClickType.PICKUP, moved)); - + .sendPacket(newClickPacket(source.slotNumber, 0, ClickType.PICKUP, moved)); + return null; // stop task }; case CRAFTING_0: @@ -109,41 +125,41 @@ private TaskChain getSlotSettingTask(Slot source, EasyIndex destination) { case CRAFTING_2: case CRAFTING_3: return dst == null - ? null - : () -> { - // pick up the item + ? null + : () -> { + // pick up the item + checkContainerIntegrity(); + checkSlotIntegrity(source, srcCopy); + checkSlotIntegrity(dst, dstCopy); + + ItemStack moved = + getCurrentContainer() + .slotClick(source.slotNumber, 0, ClickType.PICKUP, getLocalPlayer()); + getNetworkManager() + .sendPacket(newClickPacket(source.slotNumber, 0, ClickType.PICKUP, moved)); + + final Slot srcCopy2 = copyOfSlot(source); // copy the new source + + return () -> { + // place item in crafting inventory checkContainerIntegrity(); - checkSlotIntegrity(source, srcCopy); + checkSlotIntegrity(source, srcCopy2); checkSlotIntegrity(dst, dstCopy); - - ItemStack moved = - getCurrentContainer() - .slotClick(source.slotNumber, 0, ClickType.PICKUP, getLocalPlayer()); + + final ItemStack moved2 = + getCurrentContainer() + .slotClick(dst.slotNumber, 0, ClickType.PICKUP, getLocalPlayer()); getNetworkManager() - .sendPacket(newClickPacket(source.slotNumber, 0, ClickType.PICKUP, moved)); - - final Slot srcCopy2 = copyOfSlot(source); // copy the new source - - return () -> { - // place item in crafting inventory - checkContainerIntegrity(); - checkSlotIntegrity(source, srcCopy2); - checkSlotIntegrity(dst, dstCopy); - - final ItemStack moved2 = - getCurrentContainer() - .slotClick(dst.slotNumber, 0, ClickType.PICKUP, getLocalPlayer()); - getNetworkManager() - .sendPacket(newClickPacket(dst.slotNumber, 0, ClickType.PICKUP, moved2)); - - return null; // stop task - }; + .sendPacket(newClickPacket(dst.slotNumber, 0, ClickType.PICKUP, moved2)); + + return null; // stop task }; + }; default: return null; } } - + private Slot getSlot(EasyIndex index) { switch (index) { case HOLDING: @@ -153,15 +169,15 @@ private Slot getSlot(EasyIndex index) { case CRAFTING_2: case CRAFTING_3: return getPlayerContainer() - .filter(container -> Utils.isInRange(container.inventorySlots, index.getSlotIndex())) - .map(container -> container.inventorySlots.get(index.getSlotIndex())) - .orElse(null); + .filter(container -> Utils.isInRange(container.inventorySlots, index.getSlotIndex())) + .map(container -> container.inventorySlots.get(index.getSlotIndex())) + .orElse(null); case NONE: default: return null; } } - + private ItemStack getItemStack(EasyIndex index) { switch (index) { case HOLDING: @@ -170,27 +186,27 @@ private ItemStack getItemStack(EasyIndex index) { return Optional.ofNullable(getSlot(index)).map(Slot::getStack).orElse(ItemStack.EMPTY); } } - + private EasyIndex getAvailableIndex() { return EasyIndex.ALL - .stream() - .filter(e -> getItemStack(e).isEmpty()) - .min(Comparator.reverseOrder()) - .orElse(EasyIndex.NONE); + .stream() + .filter(e -> getItemStack(e).isEmpty()) + .min(Comparator.reverseOrder()) + .orElse(EasyIndex.NONE); } - + private Slot getBestSlotCandidate() { return getMainInventory() - .stream() - .max(Comparator.comparingInt(ExtraInventory::getItemValue)) - .map(item -> LocalPlayerInventory.getInventory().getSlotFor(item)) - .map( - index -> - getCurrentContainer() - .getSlotFromInventory(LocalPlayerInventory.getInventory(), index)) - .orElse(null); + .stream() + .max(Comparator.comparingInt(ExtraInventory::getItemValue)) + .map(item -> LocalPlayerInventory.getInventory().getSlotFor(item)) + .map( + index -> + getCurrentContainer() + .getSlotFromInventory(LocalPlayerInventory.getInventory(), index)) + .orElse(null); } - + private void closeGui() { if (guiNeedsClose.compareAndSet(true, false)) { if (getLocalPlayer() != null) { @@ -204,7 +220,7 @@ private void closeGui() { } } } - + private void reset() { nextClickTask = null; openedGui = null; @@ -212,16 +228,16 @@ private void reset() { guiCloseGuard = false; clickTimer.reset(); } - + @Override protected void onDisabled() { MC.addScheduledTask( - () -> { - closeGui(); - reset(); - }); + () -> { + closeGui(); + reset(); + }); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { if (auto_store.get() && (!clickTimer.isStarted() || clickTimer.hasTimeElapsed(delay.get()))) { @@ -237,18 +253,18 @@ public void onUpdate(LocalPlayerUpdateEvent event) { Slot best = getBestSlotCandidate(); if (best != null) { // open and close the gui to create open instance - + if (openedGui == null) { MC.displayGuiScreen(new GuiInventory(getLocalPlayer())); MC.displayGuiScreen(null); } - + nextClickTask = getSlotSettingTask(best, next); } } } } - + if (nextClickTask != null) { try { // run the task @@ -262,12 +278,12 @@ public void onUpdate(LocalPlayerUpdateEvent event) { } } } - + @SubscribeEvent public void onDisconnectToServer(FMLNetworkEvent.ClientDisconnectionFromServerEvent event) { onDisabled(); } - + @SubscribeEvent(priority = EventPriority.LOWEST) public void onGuiOpen(GuiOpenEvent event) { if (guiCloseGuard) { @@ -280,172 +296,201 @@ public void onGuiOpen(GuiOpenEvent event) { guiNeedsClose.set(false); } } - + @SubscribeEvent public void onPacketSent(PacketEvent.Outgoing.Pre event) { - if (event.getPacket() instanceof CPacketClickWindow) clickTimer.start(); + if (event.getPacket() instanceof CPacketClickWindow) { + clickTimer.start(); + } } - + class GuiInventoryWrapper extends GuiInventory { + GuiInventoryWrapper() { super( - getLocalPlayer()); // provide anything that doesn't cause a nullpointer exception, will be + getLocalPlayer()); // provide anything that doesn't cause a nullpointer exception, will be // overwritten anyway } - + @Override protected void keyTyped(char typedChar, int keyCode) throws IOException { if (isEnabled() - && (keyCode == 1 || this.mc.gameSettings.keyBindInventory.isActiveAndMatches(keyCode))) { + && (keyCode == 1 || this.mc.gameSettings.keyBindInventory.isActiveAndMatches(keyCode))) { guiNeedsClose.set(true); MC.displayGuiScreen(null); - } else super.keyTyped(typedChar, keyCode); + } else { + super.keyTyped(typedChar, keyCode); + } } - + @Override public void onGuiClosed() { - if (guiCloseGuard || !isEnabled()) super.onGuiClosed(); + if (guiCloseGuard || !isEnabled()) { + super.onGuiClosed(); + } } } - + private static List getMainInventory() { List inventory = LocalPlayerInventory.getInventory().mainInventory; return inventory.subList(InventoryPlayer.getHotbarSize(), inventory.size()); } - + private static int getItemValue(ItemStack stack, boolean loopGuard) { Item item = stack.getItem(); - if (stack.isEmpty()) return 0; - else if (item instanceof ItemArmor - || item instanceof ItemPickaxe - || item instanceof ItemAxe - || item instanceof ItemSword - || item instanceof ItemFood - || item instanceof ItemArrow - || Items.TOTEM_OF_UNDYING.equals(item)) return 100 * stack.getCount(); // very important - else if (item instanceof ItemShulkerBox) { + if (stack.isEmpty()) { + return 0; + } else if (item instanceof ItemArmor + || item instanceof ItemPickaxe + || item instanceof ItemAxe + || item instanceof ItemSword + || item instanceof ItemFood + || item instanceof ItemArrow + || Items.TOTEM_OF_UNDYING.equals(item)) { + return 100 * stack.getCount(); // very important + } else if (item instanceof ItemShulkerBox) { return 5 - + (loopGuard - ? 0 - : Utils.getShulkerContents(stack) - .stream() - .mapToInt(ExtraInventory::getItemValueSafe) - .sum()); + + (loopGuard + ? 0 + : Utils.getShulkerContents(stack) + .stream() + .mapToInt(ExtraInventory::getItemValueSafe) + .sum()); } else { return 5; } } - + private static int getItemValue(ItemStack stack) { return getItemValue(stack, false); } - + private static int getItemValueSafe(ItemStack stack) { return getItemValue(stack, true); } - + private static Container getCurrentContainer() { return MoreObjects.firstNonNull( - LocalPlayerInventory.getOpenContainer(), LocalPlayerInventory.getContainer()); + LocalPlayerInventory.getOpenContainer(), LocalPlayerInventory.getContainer()); } - + private static Optional getPlayerContainer() { return Optional.ofNullable(getCurrentContainer()) - .filter(ContainerPlayer.class::isInstance) - .map(ContainerPlayer.class::cast); + .filter(ContainerPlayer.class::isInstance) + .map(ContainerPlayer.class::cast); } - + private static CPacketClickWindow newClickPacket( - int slotIdIn, int usedButtonIn, ClickType modeIn, ItemStack clickedItemIn) { + int slotIdIn, int usedButtonIn, ClickType modeIn, ItemStack clickedItemIn) { return new CPacketClickWindow( - GUI_INVENTORY_ID, - slotIdIn, - usedButtonIn, - modeIn, - clickedItemIn, - getCurrentContainer().getNextTransactionID(LocalPlayerInventory.getInventory())); + GUI_INVENTORY_ID, + slotIdIn, + usedButtonIn, + modeIn, + clickedItemIn, + getCurrentContainer().getNextTransactionID(LocalPlayerInventory.getInventory())); } - + private static Slot copyOfSlot(Slot slot) { return (slot == null || slot.getSlotIndex() == -999) ? null : new DuplicateSlot(slot); } - + private static void checkContainerIntegrity() throws ExecutionFailure { - if (!getPlayerContainer().isPresent()) fail(); + if (!getPlayerContainer().isPresent()) { + fail(); + } } - + private static void checkSlotIntegrity(Slot s1, Slot s2) throws ExecutionFailure { // compare references (yes i realize im doing ItemStack == ItemStack) if (s1 != null - && s2 != null - && (s1.inventory != s2.inventory - || s1.getSlotIndex() != s2.getSlotIndex() - || s1.slotNumber != s2.slotNumber - || s1.getStack() != s2.getStack())) fail(); + && s2 != null + && (s1.inventory != s2.inventory + || s1.getSlotIndex() != s2.getSlotIndex() + || s1.slotNumber != s2.slotNumber + || s1.getStack() != s2.getStack())) { + fail(); + } } - + private static void fail() { throw new ExecutionFailure(); } - - private static class ExecutionFailure extends RuntimeException {} - + + private static class ExecutionFailure extends RuntimeException { + + } + private static class DuplicateSlot extends Slot { + private final ItemStack stack; - + private DuplicateSlot(Slot original) { super(original.inventory, original.getSlotIndex(), original.xPos, original.yPos); this.slotNumber = original.slotNumber; this.stack = original.getStack(); } - + @Override public ItemStack getStack() { return stack; } } - + private interface TaskChain { + TaskChain run(); } - + enum EasyIndex { - /** Nothing */ + /** + * Nothing + */ NONE(Integer.MIN_VALUE), - - /** Item the player is holding */ + + /** + * Item the player is holding + */ HOLDING(-999), - - /** Item the player has in the top left crafting slot */ + + /** + * Item the player has in the top left crafting slot + */ CRAFTING_0(1), - - /** Item the player has in the bottom left crafting slot */ + + /** + * Item the player has in the bottom left crafting slot + */ CRAFTING_1(2), - - /** Item the player has in the top right crafting slot */ + + /** + * Item the player has in the top right crafting slot + */ CRAFTING_2(3), - - /** Item the player has in the bottom right crafting slot */ + + /** + * Item the player has in the bottom right crafting slot + */ CRAFTING_3(4), ; - + final int slotIndex; - + EasyIndex(int slotIndex) { this.slotIndex = slotIndex; } - + public int getSlotIndex() { return slotIndex; } - + public boolean isNone() { return ordinal() == 0; } - + static final EnumSet ALL = - Arrays.stream(values()) - .skip(1) - .collect(Collectors.toCollection(() -> EnumSet.noneOf(EasyIndex.class))); + Arrays.stream(values()) + .skip(1) + .collect(Collectors.toCollection(() -> EnumSet.noneOf(EasyIndex.class))); } } diff --git a/src/main/java/com/matt/forgehax/mods/ExtraTab.java b/src/main/java/com/matt/forgehax/mods/ExtraTab.java index 5fb2b4804..2837e10ce 100644 --- a/src/main/java/com/matt/forgehax/mods/ExtraTab.java +++ b/src/main/java/com/matt/forgehax/mods/ExtraTab.java @@ -5,18 +5,21 @@ import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; -/** Created by Babbaj on 9/2/2017. */ +/** + * Created by Babbaj on 9/2/2017. + */ @RegisterMod public class ExtraTab extends ToggleMod { + public ExtraTab() { super(Category.MISC, "ExtraTab", false, "Increase max size of tab list"); } - + @Override public void onEnabled() { ForgeHaxHooks.doIncreaseTabListSize = true; } - + @Override public void onDisabled() { ForgeHaxHooks.doIncreaseTabListSize = false; diff --git a/src/main/java/com/matt/forgehax/mods/FPSLock.java b/src/main/java/com/matt/forgehax/mods/FPSLock.java index c7c5394ea..a2bf85460 100644 --- a/src/main/java/com/matt/forgehax/mods/FPSLock.java +++ b/src/main/java/com/matt/forgehax/mods/FPSLock.java @@ -1,7 +1,5 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.getWorld; - import com.matt.forgehax.util.command.Setting; import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; @@ -12,65 +10,69 @@ @RegisterMod public class FPSLock extends ToggleMod { - - private final Setting defaultFps = - getCommandStub() - .builders() - .newSettingBuilder() - .name("default-fps") - .description("default FPS to revert to") - .defaultTo(MC.gameSettings.limitFramerate) - .min(1) - .build(); - - private final Setting fps = - getCommandStub() - .builders() - .newSettingBuilder() - .name("fps") - .description("FPS to use when the world is loaded. Set to 0 to disable.") - .min(0) - .defaultTo(0) - .build(); + + private final Setting defaultFps = + getCommandStub() + .builders() + .newSettingBuilder() + .name("default-fps") + .description("default FPS to revert to") + .defaultTo(MC.gameSettings.limitFramerate) + .min(1) + .build(); + + private final Setting fps = + getCommandStub() + .builders() + .newSettingBuilder() + .name("fps") + .description("FPS to use when the world is loaded. Set to 0 to disable.") + .min(0) + .defaultTo(0) + .build(); private final Setting menu_fps = - getCommandStub() - .builders() - .newSettingBuilder() - .name("menu-fps") - .description("FPS when the GUI is opened. Set to 0 to disable.") - .min(0) - .defaultTo(60) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("menu-fps") + .description("FPS when the GUI is opened. Set to 0 to disable.") + .min(0) + .defaultTo(60) + .build(); + private final Setting no_focus_fps = - getCommandStub() - .builders() - .newSettingBuilder() - .name("no-focus-fps") - .description("FPS when the game window doesn't have focus. Set to 0 to disable.") - .min(0) - .defaultTo(3) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("no-focus-fps") + .description("FPS when the game window doesn't have focus. Set to 0 to disable.") + .min(0) + .defaultTo(3) + .build(); + public FPSLock() { super( - Category.MISC, - "FPSLock", - false, - "Lock the fps to a lower-than-allowed value, and restore when disabled"); + Category.MISC, + "FPSLock", + false, + "Lock the fps to a lower-than-allowed value, and restore when disabled"); } - + private int getFps() { - if (no_focus_fps.get() > 0 && !Display.isActive()) return no_focus_fps.get(); - else if (MC.currentScreen != null) return menu_fps.get() > 0 ? menu_fps.get() : defaultFps.get(); - else return fps.get() > 0 ? fps.get() : defaultFps.get(); + if (no_focus_fps.get() > 0 && !Display.isActive()) { + return no_focus_fps.get(); + } else if (MC.currentScreen != null) { + return menu_fps.get() > 0 ? menu_fps.get() : defaultFps.get(); + } else { + return fps.get() > 0 ? fps.get() : defaultFps.get(); + } } - + @Override protected void onDisabled() { MC.gameSettings.limitFramerate = defaultFps.get(); } - + @SubscribeEvent void onTick(ClientTickEvent event) { switch (event.phase) { diff --git a/src/main/java/com/matt/forgehax/mods/FancyChat.java b/src/main/java/com/matt/forgehax/mods/FancyChat.java index 1f40574f0..f554a969e 100644 --- a/src/main/java/com/matt/forgehax/mods/FancyChat.java +++ b/src/main/java/com/matt/forgehax/mods/FancyChat.java @@ -22,6 +22,7 @@ @RegisterMod public class FancyChat extends ToggleMod { + private enum MODE { FULL_WIDTH, CIRCLE, @@ -31,9 +32,9 @@ private enum MODE { WAVE, RANDOMCASE } - + private static final String alphabet = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; private static final int[][] FONT = { { 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B, @@ -67,12 +68,12 @@ private enum MODE { 0x2B7, 0x2E3, 0x2B8, 0x1DBB, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 } }; - + // Uppercase Lookup for LEET private static HashMap LeetMap = new HashMap<>(); // Custom probability for rarely used LEET replacements private static HashMap LeetProbability = new HashMap<>(); - + static { LeetMap.put(65, "4"); LeetMap.put(69, "3"); @@ -109,136 +110,136 @@ private enum MODE { LeetMap.put(88, "><"); LeetProbability.put(88, 50); } - + private final Setting font = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("font") - .description("Font to use") - .defaultTo(MODE.FULL_WIDTH) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("font") + .description("Font to use") + .defaultTo(MODE.FULL_WIDTH) + .build(); + private Pattern prefixPattern; private final Setting prefixRegexp = - getCommandStub() - .builders() - .newSettingBuilder() - .name("prefix") - .description("Command prefixes (RegExp)") - .defaultTo("/|//|\\!") - .requiredArgs(1) - .processor( - data -> { - try { - Pattern.compile(data.getArgument(0)); - data.markSuccess(); - compileMessagePatterns(); - } catch (PatternSyntaxException e) { - printError( - String.format( - "Error in new pattern %s: %s", e.getPattern(), e.getDescription())); - data.markFailed(); - } - }) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("prefix") + .description("Command prefixes (RegExp)") + .defaultTo("/|//|\\!") + .requiredArgs(1) + .processor( + data -> { + try { + Pattern.compile(data.getArgument(0)); + data.markSuccess(); + compileMessagePatterns(); + } catch (PatternSyntaxException e) { + printError( + String.format( + "Error in new pattern %s: %s", e.getPattern(), e.getDescription())); + data.markFailed(); + } + }) + .build(); + private Pattern command0ArgPattern; private final Setting command0ArgRegexp = - getCommandStub() - .builders() - .newSettingBuilder() - .name("command0Arg") - .description("Commands where all text may be changed (RegExp)") - .defaultTo("r|reply") - .requiredArgs(1) - .processor( - data -> { - try { - Pattern.compile(data.getArgument(0)); - data.markSuccess(); - compileMessagePatterns(); - } catch (PatternSyntaxException e) { - printError( - String.format( - "Error in new pattern %s: %s", e.getPattern(), e.getDescription())); - data.markFailed(); - } - }) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("command0Arg") + .description("Commands where all text may be changed (RegExp)") + .defaultTo("r|reply") + .requiredArgs(1) + .processor( + data -> { + try { + Pattern.compile(data.getArgument(0)); + data.markSuccess(); + compileMessagePatterns(); + } catch (PatternSyntaxException e) { + printError( + String.format( + "Error in new pattern %s: %s", e.getPattern(), e.getDescription())); + data.markFailed(); + } + }) + .build(); + private Pattern command1ArgPattern; private final Setting command1ArgRegexp = - getCommandStub() - .builders() - .newSettingBuilder() - .name("command1Arg") - .description("Commands where only the first argument may not be changed (RegExp)") - .defaultTo("pm|tell|msg|message|w|whisper|nick|mail") - .requiredArgs(1) - .processor( - data -> { - try { - Pattern.compile(data.getArgument(0)); - data.markSuccess(); - compileMessagePatterns(); - } catch (PatternSyntaxException e) { - printError( - String.format( - "Error in new pattern %s: %s", e.getPattern(), e.getDescription())); - data.markFailed(); - } - }) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("command1Arg") + .description("Commands where only the first argument may not be changed (RegExp)") + .defaultTo("pm|tell|msg|message|w|whisper|nick|mail") + .requiredArgs(1) + .processor( + data -> { + try { + Pattern.compile(data.getArgument(0)); + data.markSuccess(); + compileMessagePatterns(); + } catch (PatternSyntaxException e) { + printError( + String.format( + "Error in new pattern %s: %s", e.getPattern(), e.getDescription())); + data.markFailed(); + } + }) + .build(); + public FancyChat() { super(Category.MISC, "FancyChat", false, "meme text"); } - + @Override protected void onLoad() { compileMessagePatterns(); } - + private void compileMessagePatterns() { prefixPattern = Pattern.compile("(^" + prefixRegexp.get() + ")(\\w+)"); command0ArgPattern = Pattern.compile("(" + command0ArgRegexp.get() + ")"); command1ArgPattern = Pattern.compile("(" + command1ArgRegexp.get() + ")"); } - + @SubscribeEvent public void onPacketSent(PacketEvent.Outgoing.Pre event) { if (event.getPacket() instanceof CPacketChatMessage - && !PacketHelper.isIgnored(event.getPacket())) { - + && !PacketHelper.isIgnored(event.getPacket())) { + boolean is0Arg = false; boolean is1Arg = false; boolean isIgnore = false; - + String prefix = ""; String command = ""; String message; String arg1 = ""; - + String inputMessage = ((CPacketChatMessage) event.getPacket()).getMessage(); - + Matcher prefixMatcher = prefixPattern.matcher(inputMessage); if (prefixMatcher.find()) { prefix = prefixMatcher.group(1); command = prefixMatcher.group(2); - + Matcher cmd0ArgMatcher = command0ArgPattern.matcher(command); Matcher cmd1ArgMatcher = command1ArgPattern.matcher(command); - + // if command is found, make sure the match is not just a substring if (cmd0ArgMatcher.find() && command.length() == cmd0ArgMatcher.group().length()) { is0Arg = true; message = inputMessage.substring(prefixMatcher.end()); - + } else if (cmd1ArgMatcher.find() && command.length() == cmd1ArgMatcher.group().length()) { is1Arg = true; Matcher arg1Matcher = Pattern.compile(" .+? ").matcher(inputMessage); - + if (arg1Matcher.find()) { arg1 = inputMessage.substring(arg1Matcher.start(), arg1Matcher.end()).trim(); message = inputMessage.substring(arg1Matcher.end()); @@ -246,7 +247,7 @@ public void onPacketSent(PacketEvent.Outgoing.Pre event) { isIgnore = true; message = inputMessage; } - + } else { message = inputMessage; // Completely ignore all unknown commands @@ -255,13 +256,16 @@ public void onPacketSent(PacketEvent.Outgoing.Pre event) { } else { message = inputMessage; } - + if (!isIgnore) { String messageOut = prettify(message); - - if (is0Arg) messageOut = prefix + command + " " + messageOut; - else if (is1Arg) messageOut = prefix + command + " " + arg1 + " " + messageOut; - + + if (is0Arg) { + messageOut = prefix + command + " " + messageOut; + } else if (is1Arg) { + messageOut = prefix + command + " " + arg1 + " " + messageOut; + } + if (getNetworkManager() != null) { CPacketChatMessage packet = new CPacketChatMessage(messageOut); PacketHelper.ignore(packet); @@ -271,16 +275,16 @@ public void onPacketSent(PacketEvent.Outgoing.Pre event) { } } } - + private String makeLeet(String message) { char[] messageArray; - + message = message.replaceAll("(?i)dude", "d00d").replaceAll("(^|\\s)ph", "$1f"); - + messageArray = message.toCharArray(); // match and replace the last only S in a word Matcher zMatcher = Pattern.compile("(? random.nextInt(100))) { + && LeetMap.get(key) != null + && (LeetProbability.get(key) == null + || LeetProbability.get(key) > random.nextInt(100))) { builder.append(LeetMap.get(key)); } else { builder.append(c); } } - + return builder.toString(); } - + private String makeWave(String message) { char[] messageArray = message.toCharArray(); ThreadLocalRandom rand = ThreadLocalRandom.current(); double span = rand.nextDouble(0.4D, 1.3D); double xoff = rand.nextDouble(0, 32); double yoff = rand.nextDouble(-0.4, 0.6); - + for (int i = 0; i < messageArray.length; i++) { if (waveCharIsUpper(i, span, xoff, yoff)) { messageArray[i] = Character.toUpperCase(messageArray[i]); @@ -323,31 +327,31 @@ private String makeWave(String message) { } return new String(messageArray); } - - private String randomCase(String message) { - char[] messageArray = message.toCharArray(); - ThreadLocalRandom rand = ThreadLocalRandom.current(); - - for (int i = 0; i < messageArray.length; i++) { - if (rand.nextBoolean()) { - messageArray[i] = Character.toUpperCase(messageArray[i]); - } else { - messageArray[i] = Character.toLowerCase(messageArray[i]); - } + + private String randomCase(String message) { + char[] messageArray = message.toCharArray(); + ThreadLocalRandom rand = ThreadLocalRandom.current(); + + for (int i = 0; i < messageArray.length; i++) { + if (rand.nextBoolean()) { + messageArray[i] = Character.toUpperCase(messageArray[i]); + } else { + messageArray[i] = Character.toLowerCase(messageArray[i]); } - return new String(messageArray); } - + return new String(messageArray); + } + private boolean waveCharIsUpper(double x, double span, double xoff, double yoff) { // defaults: span = 0.4, xoff=0, yoff=-0.5 - return Math.sin(x*span + xoff)+yoff > 0; + return Math.sin(x * span + xoff) + yoff > 0; } - + private String changeAlphabet(String message, MODE fontType) { char[] messageArray = message.toCharArray(); int[] currentFont = FONT[fontType.ordinal()]; int i = 0; - + for (char c : messageArray) { int letterKey = alphabet.indexOf(c); if (letterKey != -1 && (c != (char) 0x3E)) { @@ -357,7 +361,7 @@ private String changeAlphabet(String message, MODE fontType) { } return new String(messageArray); } - + public String prettify(String message) { switch (font.get()) { case LEET: diff --git a/src/main/java/com/matt/forgehax/mods/FastBreak.java b/src/main/java/com/matt/forgehax/mods/FastBreak.java index 9eab098bd..9a4886183 100644 --- a/src/main/java/com/matt/forgehax/mods/FastBreak.java +++ b/src/main/java/com/matt/forgehax/mods/FastBreak.java @@ -9,13 +9,15 @@ @RegisterMod public class FastBreak extends ToggleMod { + public FastBreak() { super(Category.PLAYER, "FastBreak", false, "Fast break retard"); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { - if (MC.playerController != null) + if (MC.playerController != null) { FastReflection.Fields.PlayerControllerMP_blockHitDelay.set(MC.playerController, 0); + } } } diff --git a/src/main/java/com/matt/forgehax/mods/FastPlaceMod.java b/src/main/java/com/matt/forgehax/mods/FastPlaceMod.java index 19d0233c1..40d07b54a 100644 --- a/src/main/java/com/matt/forgehax/mods/FastPlaceMod.java +++ b/src/main/java/com/matt/forgehax/mods/FastPlaceMod.java @@ -7,13 +7,16 @@ import com.matt.forgehax.util.mod.loader.RegisterMod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 9/4/2016 by fr1kin */ +/** + * Created on 9/4/2016 by fr1kin + */ @RegisterMod public class FastPlaceMod extends ToggleMod { + public FastPlaceMod() { super(Category.PLAYER, "FastPlace", false, "Fast place"); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { FastReflection.Fields.Minecraft_rightClickDelayTimer.set(MC, 0); diff --git a/src/main/java/com/matt/forgehax/mods/FlyMod.java b/src/main/java/com/matt/forgehax/mods/FlyMod.java index 56177b539..5f385db3a 100644 --- a/src/main/java/com/matt/forgehax/mods/FlyMod.java +++ b/src/main/java/com/matt/forgehax/mods/FlyMod.java @@ -20,103 +20,105 @@ @RegisterMod @SuppressWarnings("MethodCallSideOnly") public class FlyMod extends ToggleMod { - + private boolean zoomies = true; - + public FlyMod() { super(Category.PLAYER, "Fly", false, "Enables flying"); } - + @Override public void onDisabled() { - if (Objects.nonNull(getLocalPlayer())) getLocalPlayer().noClip = false; + if (Objects.nonNull(getLocalPlayer())) { + getLocalPlayer().noClip = false; + } } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { try { double[] dir = moveLooking(0); double xDir = dir[0]; double zDir = dir[1]; - + if ((MC.gameSettings.keyBindForward.isKeyDown() - || MC.gameSettings.keyBindLeft.isKeyDown() - || MC.gameSettings.keyBindRight.isKeyDown() - || MC.gameSettings.keyBindBack.isKeyDown()) - && !MC.gameSettings.keyBindJump.isKeyDown()) { + || MC.gameSettings.keyBindLeft.isKeyDown() + || MC.gameSettings.keyBindRight.isKeyDown() + || MC.gameSettings.keyBindBack.isKeyDown()) + && !MC.gameSettings.keyBindJump.isKeyDown()) { MC.player.motionX = xDir * 0.26; MC.player.motionZ = zDir * 0.26; } double posX = MC.player.posX + MC.player.motionX; double posY = - MC.player.posY - + (MC.gameSettings.keyBindJump.isKeyDown() ? (zoomies ? 0.0625 : 0.0624) : 0.00000001) - - (MC.gameSettings.keyBindSneak.isKeyDown() - ? (zoomies ? 0.0625 : 0.0624) - : 0.00000002); + MC.player.posY + + (MC.gameSettings.keyBindJump.isKeyDown() ? (zoomies ? 0.0625 : 0.0624) : 0.00000001) + - (MC.gameSettings.keyBindSneak.isKeyDown() + ? (zoomies ? 0.0625 : 0.0624) + : 0.00000002); double posZ = MC.player.posZ + MC.player.motionX; getNetworkManager() - .sendPacket( - new CPacketPlayer.PositionRotation( - MC.player.posX + MC.player.motionX, - MC.player.posY - + (MC.gameSettings.keyBindJump.isKeyDown() - ? (zoomies ? 0.0625 : 0.0624) - : 0.00000001) - - (MC.gameSettings.keyBindSneak.isKeyDown() - ? (zoomies ? 0.0625 : 0.0624) - : 0.00000002), - MC.player.posZ + MC.player.motionZ, - MC.player.rotationYaw, - MC.player.rotationPitch, - false)); + .sendPacket( + new CPacketPlayer.PositionRotation( + MC.player.posX + MC.player.motionX, + MC.player.posY + + (MC.gameSettings.keyBindJump.isKeyDown() + ? (zoomies ? 0.0625 : 0.0624) + : 0.00000001) + - (MC.gameSettings.keyBindSneak.isKeyDown() + ? (zoomies ? 0.0625 : 0.0624) + : 0.00000002), + MC.player.posZ + MC.player.motionZ, + MC.player.rotationYaw, + MC.player.rotationPitch, + false)); getNetworkManager() - .sendPacket( - new CPacketPlayer.PositionRotation( - MC.player.posX + MC.player.motionX, - 1337 + MC.player.posY, - MC.player.posZ + MC.player.motionZ, - MC.player.rotationYaw, - MC.player.rotationPitch, - true)); + .sendPacket( + new CPacketPlayer.PositionRotation( + MC.player.posX + MC.player.motionX, + 1337 + MC.player.posY, + MC.player.posZ + MC.player.motionZ, + MC.player.rotationYaw, + MC.player.rotationPitch, + true)); getNetworkManager().sendPacket(new CPacketEntityAction(MC.player, Action.START_FALL_FLYING)); MC.player.setPosition(posX, posY, posZ); - + zoomies = !zoomies; - + MC.player.motionX = 0; MC.player.motionY = 0; MC.player.motionZ = 0; - + MC.player.noClip = true; } catch (Exception e) { Helper.printStackTrace(e); } } - + public double[] moveLooking(int ignored) { - return new double[] {MC.player.rotationYaw * 360 / 360 * 180 / 180, 0}; + return new double[]{MC.player.rotationYaw * 360 / 360 * 180 / 180, 0}; } - + @SubscribeEvent public void onOutgoingPacketSent(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketPlayerPosLook) { SPacketPlayerPosLook packet = (SPacketPlayerPosLook) event.getPacket(); try { ObfuscationReflectionHelper.setPrivateValue( - SPacketPlayerPosLook.class, - packet, - MC.player.rotationYaw, - "yaw", - "field_148936_d", - "d"); + SPacketPlayerPosLook.class, + packet, + MC.player.rotationYaw, + "yaw", + "field_148936_d", + "d"); ObfuscationReflectionHelper.setPrivateValue( - SPacketPlayerPosLook.class, - packet, - MC.player.rotationPitch, - "pitch", - "field_148937_e", - "e"); + SPacketPlayerPosLook.class, + packet, + MC.player.rotationPitch, + "pitch", + "field_148937_e", + "e"); } catch (Exception e) { } } diff --git a/src/main/java/com/matt/forgehax/mods/FreecamMod.java b/src/main/java/com/matt/forgehax/mods/FreecamMod.java index 19b15a21e..c4d4f5fb1 100644 --- a/src/main/java/com/matt/forgehax/mods/FreecamMod.java +++ b/src/main/java/com/matt/forgehax/mods/FreecamMod.java @@ -1,7 +1,6 @@ package com.matt.forgehax.mods; import static com.matt.forgehax.Helper.getLocalPlayer; -import static com.matt.forgehax.Helper.getModManager; import static com.matt.forgehax.Helper.getWorld; import com.matt.forgehax.asm.events.PacketEvent; @@ -11,7 +10,6 @@ import com.matt.forgehax.util.entity.LocalPlayerUtils; import com.matt.forgehax.util.key.Bindings; import com.matt.forgehax.util.math.Angle; -import com.matt.forgehax.util.mod.BaseMod; import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; @@ -27,43 +25,50 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 9/3/2016 by fr1kin */ +/** + * Created on 9/3/2016 by fr1kin + */ @RegisterMod public class FreecamMod extends ToggleMod { + private final Setting speed = - getCommandStub() - .builders() - .newSettingBuilder() - .name("speed") - .description("Movement speed") - .defaultTo(0.05D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("speed") + .description("Movement speed") + .defaultTo(0.05D) + .build(); + private final Handle flying = LocalPlayerUtils.getFlySwitch().createHandle(getModName()); - + private Vec3d pos = Vec3d.ZERO; private Angle angle = Angle.ZERO; - + private boolean isRidingEntity; private Entity ridingEntity; - + private EntityOtherPlayerMP originalPlayer; - + public FreecamMod() { super(Category.PLAYER, "Freecam", false, "Freecam mode"); } - + @Override public void onEnabled() { - if (getLocalPlayer() == null || getWorld() == null) return; - + if (getLocalPlayer() == null || getWorld() == null) { + return; + } + if (isRidingEntity = getLocalPlayer().isRiding()) { ridingEntity = getLocalPlayer().getRidingEntity(); getLocalPlayer().dismountRidingEntity(); - } else pos = getLocalPlayer().getPositionVector(); - + } else { + pos = getLocalPlayer().getPositionVector(); + } + angle = LocalPlayerUtils.getViewAngles(); - + originalPlayer = new EntityOtherPlayerMP(getWorld(), MC.getSession().getProfile()); originalPlayer.copyLocationAndAnglesFrom(getLocalPlayer()); originalPlayer.rotationYawHead = getLocalPlayer().rotationYawHead; @@ -71,57 +76,63 @@ public void onEnabled() { originalPlayer.inventoryContainer = getLocalPlayer().inventoryContainer; getWorld().addEntityToWorld(-100, originalPlayer); } - + @Override public void onDisabled() { flying.disable(); - - if (getLocalPlayer() == null || originalPlayer == null) return; - + + if (getLocalPlayer() == null || originalPlayer == null) { + return; + } + getLocalPlayer().setPositionAndRotation(pos.x, pos.y, pos.z, angle.getYaw(), angle.getPitch()); getWorld().removeEntityFromWorld(-100); originalPlayer = null; - + getLocalPlayer().noClip = false; getLocalPlayer().setVelocity(0, 0, 0); - + if (isRidingEntity) { getLocalPlayer().startRiding(ridingEntity, true); ridingEntity = null; } } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { - if (getLocalPlayer() == null) return; - + if (getLocalPlayer() == null) { + return; + } + flying.enable(); getLocalPlayer().capabilities.setFlySpeed(speed.getAsFloat()); getLocalPlayer().noClip = true; getLocalPlayer().onGround = false; getLocalPlayer().fallDistance = 0; - + if (!Bindings.forward.isPressed() - && !Bindings.back.isPressed() - && !Bindings.left.isPressed() - && !Bindings.right.isPressed() - && !Bindings.jump.isPressed() - && !Bindings.sneak.isPressed()) { + && !Bindings.back.isPressed() + && !Bindings.left.isPressed() + && !Bindings.right.isPressed() + && !Bindings.jump.isPressed() + && !Bindings.sneak.isPressed()) { getLocalPlayer().setVelocity(0, 0, 0); } } - + @SubscribeEvent public void onPacketSend(PacketEvent.Outgoing.Pre event) { if (event.getPacket() instanceof CPacketPlayer || event.getPacket() instanceof CPacketInput) { event.setCanceled(true); } } - + @SubscribeEvent public void onPacketReceived(PacketEvent.Incoming.Pre event) { - if (originalPlayer == null || getLocalPlayer() == null) return; - + if (originalPlayer == null || getLocalPlayer() == null) { + return; + } + if (event.getPacket() instanceof SPacketPlayerPosLook) { SPacketPlayerPosLook packet = (SPacketPlayerPosLook) event.getPacket(); pos = new Vec3d(packet.getX(), packet.getY(), packet.getZ()); @@ -129,38 +140,47 @@ public void onPacketReceived(PacketEvent.Incoming.Pre event) { event.setCanceled(true); } } - + @SubscribeEvent public void onWorldLoad(WorldEvent.Load event) { - if (originalPlayer == null || getLocalPlayer() == null) return; - + if (originalPlayer == null || getLocalPlayer() == null) { + return; + } + pos = getLocalPlayer().getPositionVector(); angle = LocalPlayerUtils.getViewAngles(); } - + @SubscribeEvent public void onEntityRender(RenderLivingEvent.Pre event) { if (originalPlayer != null - && getLocalPlayer() != null - && getLocalPlayer().equals(event.getEntity())) event.setCanceled(true); + && getLocalPlayer() != null + && getLocalPlayer().equals(event.getEntity())) { + event.setCanceled(true); + } } - + @SubscribeEvent public void onRenderTag(RenderLivingEvent.Specials.Pre event) { if (originalPlayer != null - && getLocalPlayer() != null - && getLocalPlayer().equals(event.getEntity())) event.setCanceled(true); + && getLocalPlayer() != null + && getLocalPlayer().equals(event.getEntity())) { + event.setCanceled(true); + } } - + private static class DummyPlayer extends EntityOtherPlayerMP { + public DummyPlayer(World worldIn, GameProfile gameProfileIn) { super(worldIn, gameProfileIn); } - + @Override - public void onUpdate() {} - + public void onUpdate() { + } + @Override - public void onLivingUpdate() {} + public void onLivingUpdate() { + } } } diff --git a/src/main/java/com/matt/forgehax/mods/FullBrightMod.java b/src/main/java/com/matt/forgehax/mods/FullBrightMod.java index facd27387..7af67098a 100644 --- a/src/main/java/com/matt/forgehax/mods/FullBrightMod.java +++ b/src/main/java/com/matt/forgehax/mods/FullBrightMod.java @@ -9,12 +9,13 @@ @RegisterMod public class FullBrightMod extends ToggleMod { + public FullBrightMod() { super(Category.WORLD, "FullBright", false, "Makes everything render with maximum brightness"); } - + private final Setting defaultGamma = - getCommandStub() + getCommandStub() .builders() .newSettingBuilder() .name("gamma") @@ -23,17 +24,17 @@ public FullBrightMod() { .min(0.1F) .max(16F) .build(); - + @Override public void onEnabled() { MC.gameSettings.gammaSetting = 16F; } - + @Override public void onDisabled() { MC.gameSettings.gammaSetting = defaultGamma.get(); } - + @SubscribeEvent public void onClientTick(TickEvent.ClientTickEvent event) { MC.gameSettings.gammaSetting = 16F; diff --git a/src/main/java/com/matt/forgehax/mods/GuiMove.java b/src/main/java/com/matt/forgehax/mods/GuiMove.java index 4238e9f3c..33aff9e7e 100644 --- a/src/main/java/com/matt/forgehax/mods/GuiMove.java +++ b/src/main/java/com/matt/forgehax/mods/GuiMove.java @@ -4,19 +4,25 @@ import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; -import net.minecraft.client.gui.*; +import net.minecraft.client.gui.GuiIngameMenu; +import net.minecraft.client.gui.GuiOptions; +import net.minecraft.client.gui.GuiScreenOptionsSounds; +import net.minecraft.client.gui.GuiVideoSettings; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.settings.KeyBinding; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.input.Keyboard; -/** Created by Babbaj on 9/5/2017. */ +/** + * Created by Babbaj on 9/5/2017. + */ @RegisterMod public class GuiMove extends ToggleMod { + public GuiMove() { super(Category.MISC, "GuiMove", false, "move with a gui open"); } - + @SubscribeEvent public void LocalPlayerUpdate(LocalPlayerUpdateEvent event) { KeyBinding[] keys = { @@ -28,10 +34,10 @@ public void LocalPlayerUpdate(LocalPlayerUpdateEvent event) { MC.gameSettings.keyBindSprint }; if (MC.currentScreen instanceof GuiOptions - || MC.currentScreen instanceof GuiVideoSettings - || MC.currentScreen instanceof GuiScreenOptionsSounds - || MC.currentScreen instanceof GuiContainer - || MC.currentScreen instanceof GuiIngameMenu) { + || MC.currentScreen instanceof GuiVideoSettings + || MC.currentScreen instanceof GuiScreenOptionsSounds + || MC.currentScreen instanceof GuiContainer + || MC.currentScreen instanceof GuiIngameMenu) { for (KeyBinding bind : keys) { KeyBinding.setKeyBindState(bind.getKeyCode(), Keyboard.isKeyDown(bind.getKeyCode())); } diff --git a/src/main/java/com/matt/forgehax/mods/HorseJump.java b/src/main/java/com/matt/forgehax/mods/HorseJump.java index 1e65b556d..49261c293 100644 --- a/src/main/java/com/matt/forgehax/mods/HorseJump.java +++ b/src/main/java/com/matt/forgehax/mods/HorseJump.java @@ -10,10 +10,11 @@ @RegisterMod public class HorseJump extends ToggleMod { + public HorseJump() { super(Category.PLAYER, "HorseJump", false, "always max horse jump"); } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { FastReflection.Fields.EntityPlayerSP_horseJumpPower.set(Helper.getLocalPlayer(), 1.F); diff --git a/src/main/java/com/matt/forgehax/mods/HorseStats.java b/src/main/java/com/matt/forgehax/mods/HorseStats.java index a74869a32..6b9e67bf6 100644 --- a/src/main/java/com/matt/forgehax/mods/HorseStats.java +++ b/src/main/java/com/matt/forgehax/mods/HorseStats.java @@ -15,51 +15,54 @@ import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created by Babbaj on 9/1/2017. */ +/** + * Created by Babbaj on 9/1/2017. + */ @RegisterMod public class HorseStats extends ToggleMod { + public HorseStats() { super(Category.PLAYER, "HorseStats", false, "Change the stats of your horse"); } - + private final Setting jumpHeight = - getCommandStub() - .builders() - .newSettingBuilder() - .name("JumpHeight") - .description("Modified horse jump height attribute. Default: 1") - .defaultTo(1.0D) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("JumpHeight") + .description("Modified horse jump height attribute. Default: 1") + .defaultTo(1.0D) + .build(); private final Setting speed = - getCommandStub() - .builders() - .newSettingBuilder() - .name("Speed") - .description("Modified horse speed attribute. Default: 0.3375") - .defaultTo(0.3375D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("Speed") + .description("Modified horse speed attribute. Default: 0.3375") + .defaultTo(0.3375D) + .build(); + private final Setting multiplier = - getCommandStub() - .builders() - .newSettingBuilder() - .name("multiplier") - .description("multiplier while sprinting") - .defaultTo(1.0D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("multiplier") + .description("multiplier while sprinting") + .defaultTo(1.0D) + .build(); + @Override public void onDisabled() { if (getRidingEntity() instanceof AbstractHorse) { applyStats(jumpHeight.getDefault(), speed.getDefault()); } } - + @SubscribeEvent public void onLivingUpdate(LivingEvent.LivingUpdateEvent event) { if (EntityUtils.isDrivenByPlayer(event.getEntity()) - && getRidingEntity() instanceof AbstractHorse) { - + && getRidingEntity() instanceof AbstractHorse) { + double newSpeed = speed.getAsDouble(); if (getLocalPlayer().isSprinting()) { newSpeed *= multiplier.getAsDouble(); @@ -67,18 +70,18 @@ && getRidingEntity() instanceof AbstractHorse) { applyStats(jumpHeight.getAsDouble(), newSpeed); } } - + private void applyStats(double newJump, double newSpeed) { final IAttribute jump_strength = - FastReflection.Fields.AbstractHorse_JUMP_STRENGTH.get(getRidingEntity()); + FastReflection.Fields.AbstractHorse_JUMP_STRENGTH.get(getRidingEntity()); final IAttribute movement_speed = - FastReflection.Fields.SharedMonsterAttributes_MOVEMENT_SPEED.get(getRidingEntity()); - + FastReflection.Fields.SharedMonsterAttributes_MOVEMENT_SPEED.get(getRidingEntity()); + ((EntityLivingBase) getRidingEntity()) - .getEntityAttribute(jump_strength) - .setBaseValue(newJump); + .getEntityAttribute(jump_strength) + .setBaseValue(newJump); ((EntityLivingBase) getRidingEntity()) - .getEntityAttribute(movement_speed) - .setBaseValue(newSpeed); + .getEntityAttribute(movement_speed) + .setBaseValue(newSpeed); } } diff --git a/src/main/java/com/matt/forgehax/mods/InstantMessage.java b/src/main/java/com/matt/forgehax/mods/InstantMessage.java index 7903e77b5..40b0fb2c3 100644 --- a/src/main/java/com/matt/forgehax/mods/InstantMessage.java +++ b/src/main/java/com/matt/forgehax/mods/InstantMessage.java @@ -16,38 +16,41 @@ @RegisterMod public class InstantMessage extends ToggleMod { + private final Setting message = - getCommandStub() - .builders() - .newSettingBuilder() - .name("message") - .description("Message to send") - .defaultTo("Never fear on {SRVNAME}, {NAME} is here!") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("message") + .description("Message to send") + .defaultTo("Never fear on {SRVNAME}, {NAME} is here!") + .build(); + public InstantMessage() { super(Category.MISC, "InstantMessage", false, "Send message as soon as you join"); } - + @SubscribeEvent public void onPacketIn(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketLoginSuccess) { - + if (MC.currentScreen instanceof GuiConnecting) { - + ServerData serverData = MC.getCurrentServerData(); String serverName = serverData != null ? serverData.serverName : "Unknown"; String serverIP = serverData != null ? serverData.serverIP : ""; - + GuiConnecting_networkManager.get(MC.currentScreen) - .sendPacket( - new CPacketChatMessage( - message - .get() - .replace("{SRVNAME}", serverName) - .replace("{IP}", serverIP) - .replace("{NAME}", MC.getSession().getUsername()))); - } else getLog().warn("Did not send message as current screen is not GuiConnecting"); + .sendPacket( + new CPacketChatMessage( + message + .get() + .replace("{SRVNAME}", serverName) + .replace("{IP}", serverIP) + .replace("{NAME}", MC.getSession().getUsername()))); + } else { + getLog().warn("Did not send message as current screen is not GuiConnecting"); + } } } } diff --git a/src/main/java/com/matt/forgehax/mods/ItemESP.java b/src/main/java/com/matt/forgehax/mods/ItemESP.java index 021f77a2d..08e08be9d 100644 --- a/src/main/java/com/matt/forgehax/mods/ItemESP.java +++ b/src/main/java/com/matt/forgehax/mods/ItemESP.java @@ -20,70 +20,73 @@ @RegisterMod public class ItemESP extends ToggleMod { + public ItemESP() { super(Category.RENDER, "ItemESP", false, "ESP for items"); } - + public final Setting scale = - getCommandStub() - .builders() - .newSettingBuilder() - .name("scale") - .description("Scaling for text") - .defaultTo(1.D) - .min(0.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("scale") + .description("Scaling for text") + .defaultTo(1.D) + .min(0.D) + .build(); + @SubscribeEvent public void onRender2D(final Render2DEvent event) { GlStateManager.enableBlend(); GlStateManager.tryBlendFuncSeparate( - GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, - GlStateManager.SourceFactor.ONE, - GlStateManager.DestFactor.ZERO); + GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); GlStateManager.enableTexture2D(); GlStateManager.disableDepth(); - + final double scale = this.scale.get() == 0 ? 1.D : this.scale.get(); - + getWorld() - .loadedEntityList - .stream() - .filter(EntityItem.class::isInstance) - .map(EntityItem.class::cast) - .filter(entity -> entity.ticksExisted > 1) - .forEach( - entity -> { - Vec3d bottomPos = EntityUtils.getInterpolatedPos(entity, event.getPartialTicks()); - Vec3d topPos = - bottomPos.addVector(0.D, entity.getRenderBoundingBox().maxY - entity.posY, 0.D); - - Plane top = VectorUtils.toScreen(topPos); - Plane bot = VectorUtils.toScreen(bottomPos); - - if (!top.isVisible() && !bot.isVisible()) return; - - double offX = bot.getX() - top.getX(); - double offY = bot.getY() - top.getY(); - - GlStateManager.pushMatrix(); - GlStateManager.translate(top.getX() - (offX / 2.D), bot.getY(), 0); - - ItemStack stack = entity.getItem(); - String text = - stack.getDisplayName() + (stack.isStackable() ? (" x" + stack.getCount()) : ""); - - SurfaceHelper.drawTextShadow( - text, - (int) (offX / 2.D - SurfaceHelper.getTextWidth(text, scale) / 2.D), - -(int) (offY - SurfaceHelper.getTextHeight(scale) / 2.D) - 1, - Colors.WHITE.toBuffer(), - scale); - - GlStateManager.popMatrix(); - }); - + .loadedEntityList + .stream() + .filter(EntityItem.class::isInstance) + .map(EntityItem.class::cast) + .filter(entity -> entity.ticksExisted > 1) + .forEach( + entity -> { + Vec3d bottomPos = EntityUtils.getInterpolatedPos(entity, event.getPartialTicks()); + Vec3d topPos = + bottomPos.addVector(0.D, entity.getRenderBoundingBox().maxY - entity.posY, 0.D); + + Plane top = VectorUtils.toScreen(topPos); + Plane bot = VectorUtils.toScreen(bottomPos); + + if (!top.isVisible() && !bot.isVisible()) { + return; + } + + double offX = bot.getX() - top.getX(); + double offY = bot.getY() - top.getY(); + + GlStateManager.pushMatrix(); + GlStateManager.translate(top.getX() - (offX / 2.D), bot.getY(), 0); + + ItemStack stack = entity.getItem(); + String text = + stack.getDisplayName() + (stack.isStackable() ? (" x" + stack.getCount()) : ""); + + SurfaceHelper.drawTextShadow( + text, + (int) (offX / 2.D - SurfaceHelper.getTextWidth(text, scale) / 2.D), + -(int) (offY - SurfaceHelper.getTextHeight(scale) / 2.D) - 1, + Colors.WHITE.toBuffer(), + scale); + + GlStateManager.popMatrix(); + }); + GlStateManager.enableDepth(); GlStateManager.disableBlend(); } diff --git a/src/main/java/com/matt/forgehax/mods/Jesus.java b/src/main/java/com/matt/forgehax/mods/Jesus.java index 76f94b2ee..49b29a325 100644 --- a/src/main/java/com/matt/forgehax/mods/Jesus.java +++ b/src/main/java/com/matt/forgehax/mods/Jesus.java @@ -1,6 +1,9 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getModManager; +import static com.matt.forgehax.Helper.getRidingEntity; +import static com.matt.forgehax.Helper.getWorld; import static com.matt.forgehax.util.entity.EntityUtils.isAboveWater; import static com.matt.forgehax.util.entity.EntityUtils.isInWater; @@ -22,79 +25,89 @@ import net.minecraft.util.math.MathHelper; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created by Babbaj on 8/29/2017. */ +/** + * Created by Babbaj on 8/29/2017. + */ @RegisterMod public class Jesus extends ToggleMod { + private static final AxisAlignedBB WATER_WALK_AA = - new AxisAlignedBB(0.D, 0.D, 0.D, 1.D, 0.99D, 1.D); - + new AxisAlignedBB(0.D, 0.D, 0.D, 1.D, 0.99D, 1.D); + public Jesus() { super(Category.PLAYER, "Jesus", false, "Walk on water"); } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { if (!getModManager().get(FreecamMod.class).map(BaseMod::isEnabled).orElse(false)) { if (isInWater(getLocalPlayer()) && !getLocalPlayer().isSneaking()) { getLocalPlayer().motionY = 0.1; if (getLocalPlayer().getRidingEntity() != null - && !(getLocalPlayer().getRidingEntity() instanceof EntityBoat)) { + && !(getLocalPlayer().getRidingEntity() instanceof EntityBoat)) { getLocalPlayer().getRidingEntity().motionY = 0.3; } } } } - + @SubscribeEvent public void onAddCollisionBox(AddCollisionBoxToListEvent event) { if (getLocalPlayer() != null - && (event.getBlock() instanceof BlockLiquid) - && (EntityUtils.isDrivenByPlayer(event.getEntity()) - || EntityUtils.isLocalPlayer(event.getEntity())) - && !(event.getEntity() instanceof EntityBoat) - && !getLocalPlayer().isSneaking() - && getLocalPlayer().fallDistance < 3 - && !isInWater(getLocalPlayer()) - && (isAboveWater(getLocalPlayer(), false) || isAboveWater(getRidingEntity(), false)) - && isAboveBlock(getLocalPlayer(), event.getPos())) { + && (event.getBlock() instanceof BlockLiquid) + && (EntityUtils.isDrivenByPlayer(event.getEntity()) + || EntityUtils.isLocalPlayer(event.getEntity())) + && !(event.getEntity() instanceof EntityBoat) + && !getLocalPlayer().isSneaking() + && getLocalPlayer().fallDistance < 3 + && !isInWater(getLocalPlayer()) + && (isAboveWater(getLocalPlayer(), false) || isAboveWater(getRidingEntity(), false)) + && isAboveBlock(getLocalPlayer(), event.getPos())) { AxisAlignedBB axisalignedbb = WATER_WALK_AA.offset(event.getPos()); - if (event.getEntityBox().intersects(axisalignedbb)) + if (event.getEntityBox().intersects(axisalignedbb)) { event.getCollidingBoxes().add(axisalignedbb); + } // cancel event, which will stop it from calling the original code event.setCanceled(true); } } - + @SubscribeEvent public void onPacketSending(PacketEvent.Outgoing.Pre event) { if (event.getPacket() instanceof CPacketPlayer) { if (isAboveWater(getLocalPlayer(), true) - && !isInWater(getLocalPlayer()) - && !isAboveLand(getLocalPlayer())) { + && !isInWater(getLocalPlayer()) + && !isAboveLand(getLocalPlayer())) { int ticks = getLocalPlayer().ticksExisted % 2; double y = FastReflection.Fields.CPacketPlayer_y.get(event.getPacket()); - if (ticks == 0) FastReflection.Fields.CPacketPlayer_y.set(event.getPacket(), y + 0.02D); + if (ticks == 0) { + FastReflection.Fields.CPacketPlayer_y.set(event.getPacket(), y + 0.02D); + } } } } - + @SuppressWarnings("deprecation") private static boolean isAboveLand(Entity entity) { - if (entity == null) return false; - + if (entity == null) { + return false; + } + double y = entity.posY - 0.01; - - for (int x = MathHelper.floor(entity.posX); x < MathHelper.ceil(entity.posX); x++) + + for (int x = MathHelper.floor(entity.posX); x < MathHelper.ceil(entity.posX); x++) { for (int z = MathHelper.floor(entity.posZ); z < MathHelper.ceil(entity.posZ); z++) { BlockPos pos = new BlockPos(x, MathHelper.floor(y), z); - - if (getWorld().getBlockState(pos).getBlock().isFullBlock(getWorld().getBlockState(pos))) + + if (getWorld().getBlockState(pos).getBlock().isFullBlock(getWorld().getBlockState(pos))) { return true; + } } - + } + return false; } - + private static boolean isAboveBlock(Entity entity, BlockPos pos) { return entity.posY >= pos.getY(); } diff --git a/src/main/java/com/matt/forgehax/mods/JoinMessage.java b/src/main/java/com/matt/forgehax/mods/JoinMessage.java index a0699005f..562bd5850 100644 --- a/src/main/java/com/matt/forgehax/mods/JoinMessage.java +++ b/src/main/java/com/matt/forgehax/mods/JoinMessage.java @@ -33,148 +33,156 @@ import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 7/21/2017 by fr1kin */ +/** + * Created on 7/21/2017 by fr1kin + */ @RegisterMod public class JoinMessage extends ToggleMod { - private static final SpamTokens[] SPAM_TOKENS = new SpamTokens[] {PLAYER_NAME, MESSAGE}; - + + private static final SpamTokens[] SPAM_TOKENS = new SpamTokens[]{PLAYER_NAME, MESSAGE}; + private final Options messages = - getCommandStub() - .builders() - .newOptionsBuilder() - .name("messages") - .description("Custom messages") - .factory(CustomMessageEntry::new) - .supplier(Sets::newConcurrentHashSet) - .build(); - + getCommandStub() + .builders() + .newOptionsBuilder() + .name("messages") + .description("Custom messages") + .factory(CustomMessageEntry::new) + .supplier(Sets::newConcurrentHashSet) + .build(); + private final Setting keyword = - getCommandStub() - .builders() - .newSettingBuilder() - .name("keyword") - .description("Keyword for the join message") - .defaultTo("!joinmessage") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("keyword") + .description("Keyword for the join message") + .defaultTo("!joinmessage") + .build(); + private final Setting format = - getCommandStub() - .builders() - .newSettingBuilder() - .name("format") - .description( - "Join message format (Use {PLAYER_NAME} for the player joining, {MESSAGE} for the set message)") - .defaultTo("<{PLAYER_NAME}> {MESSAGE}") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("format") + .description( + "Join message format (Use {PLAYER_NAME} for the player joining, {MESSAGE} for the set message)") + .defaultTo("<{PLAYER_NAME}> {MESSAGE}") + .build(); + private final Setting delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("delay") - .description("Delay between each message in ms") - .defaultTo(15000L) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("delay") + .description("Delay between each message in ms") + .defaultTo(15000L) + .build(); + private final Setting message_length = - getCommandStub() - .builders() - .newSettingBuilder() - .name("message_length") - .description("Maximum length of a custom message") - .defaultTo(25) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("message_length") + .description("Maximum length of a custom message") + .defaultTo(25) + .build(); + private final Setting use_offline = - getCommandStub() - .builders() - .newSettingBuilder() - .name("use_offline") - .description("Allows non-authenticated player names to be added") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("use_offline") + .description("Allows non-authenticated player names to be added") + .defaultTo(false) + .build(); + private final Setting set_cooldown = - getCommandStub() - .builders() - .newSettingBuilder() - .name("set_cooldown") - .description("Setting cooldown for individual players in ms") - .defaultTo(15000L) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("set_cooldown") + .description("Setting cooldown for individual players in ms") + .defaultTo(15000L) + .build(); + private final Setting max_player_messages = - getCommandStub() - .builders() - .newSettingBuilder() - .name("max_player_messages") - .description("Maximum number of messages per individual player") - .defaultTo(5) - .min(1) - .max(Integer.MAX_VALUE) - .changed( - cb -> { - messages.forEach(e -> e.setSize(cb.getTo())); - messages.serialize(); - }) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("max_player_messages") + .description("Maximum number of messages per individual player") + .defaultTo(5) + .min(1) + .max(Integer.MAX_VALUE) + .changed( + cb -> { + messages.forEach(e -> e.setSize(cb.getTo())); + messages.serialize(); + }) + .build(); + private final Setting debug_messages = - getCommandStub() - .builders() - .newSettingBuilder() - .name("debug_messages") - .description("Displays messages in chat if a player fails to use the command properly") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("debug_messages") + .description("Displays messages in chat if a player fails to use the command properly") + .defaultTo(false) + .build(); + private final Map cooldowns = Maps.newConcurrentMap(); - + public JoinMessage() { super(Category.MISC, "JoinMessage", false, "Allows players to add custom join messages"); } - + private void debugMessage(String str) { - if (debug_messages.get()) + if (debug_messages.get()) { Helper.printMessageNaked( - Strings.EMPTY, str, new Style().setItalic(true).setColor(TextFormatting.GRAY)); + Strings.EMPTY, str, new Style().setItalic(true).setColor(TextFormatting.GRAY)); + } } - + private void setJoinMessage(UUID target, UUID setter, String message) { CustomMessageEntry entry = messages.get(target); if (entry == null) { entry = new CustomMessageEntry(target); messages.add(entry); } - + String replyMessage = "Join message changed."; - + if (!entry.containsEntry(setter)) { entry.setSize(max_player_messages.get() - 1); // evict a random message replyMessage = "Join message set."; } entry.addMessage(setter, message); // correct size now - + // set cooldown cooldowns - .computeIfAbsent(setter, s -> new AtomicLong(0L)) - .set(System.currentTimeMillis() + set_cooldown.get()); - + .computeIfAbsent(setter, s -> new AtomicLong(0L)) + .set(System.currentTimeMillis() + set_cooldown.get()); + messages.serialize(); - + SpamService.send( - new SpamMessage(replyMessage, "JOIN_MESSAGE_REPLY", 0, null, PriorityEnum.HIGHEST)); + new SpamMessage(replyMessage, "JOIN_MESSAGE_REPLY", 0, null, PriorityEnum.HIGHEST)); } - + @SubscribeEvent public void onPlayerChat(ChatMessageEvent event) { String[] args = event.getMessage().split(" "); - - if (args.length < 3) return; // not enough arguments - + + if (args.length < 3) { + return; // not enough arguments + } + final String keyword = ArrayHelper.getOrDefault(args, 0, Strings.EMPTY); - if (!this.keyword.get().equalsIgnoreCase(keyword)) return; - + if (!this.keyword.get().equalsIgnoreCase(keyword)) { + return; + } + final String target = ArrayHelper.getOrDefault(args, 1, Strings.EMPTY); if (target.length() > PlayerInfoHelper.MAX_NAME_LENGTH) { debugMessage("Input name over valid length"); @@ -184,7 +192,7 @@ public void onPlayerChat(ChatMessageEvent event) { debugMessage("Cannot set own join message"); return; } - + final String message = CommandHelper.join(args, " ", 2, args.length); if (Strings.isNullOrEmpty(message)) { debugMessage("Invalid message (null or empty)"); @@ -194,51 +202,55 @@ public void onPlayerChat(ChatMessageEvent event) { debugMessage("Message over maximum specified by JoinMessage.message_length"); return; } - + // setter is not in cooldown if (System.currentTimeMillis() - < cooldowns.getOrDefault(event.getSender().getId(), new AtomicLong(0L)).get()) { + < cooldowns.getOrDefault(event.getSender().getId(), new AtomicLong(0L)).get()) { debugMessage("Player is currently in a cooldown"); return; } - + if (use_offline.get()) { // use offline ID setJoinMessage(EntityPlayerSP.getOfflineUUID(target), event.getSender().getId(), message); return; // join message set, stop here } - + PlayerInfoHelper.registerWithCallback( - target, - new FutureCallback() { - @Override - public void onSuccess(@Nullable PlayerInfo result) { - if (result != null && !result.isOfflinePlayer()) - setJoinMessage(result.getId(), event.getSender().getId(), message); + target, + new FutureCallback() { + @Override + public void onSuccess(@Nullable PlayerInfo result) { + if (result != null && !result.isOfflinePlayer()) { + setJoinMessage(result.getId(), event.getSender().getId(), message); } - - @Override - public void onFailure(Throwable t) {} - }); + } + + @Override + public void onFailure(Throwable t) { + } + }); } - + @SubscribeEvent public void onPlayerConnect(PlayerConnectEvent.Join event) { CustomMessageEntry entry = messages.get(event.getPlayerInfo().getId()); if (entry != null) { // resize if needed - if (entry.getSize() > max_player_messages.get()) entry.setSize(max_player_messages.get()); + if (entry.getSize() > max_player_messages.get()) { + entry.setSize(max_player_messages.get()); + } SpamService.send( - new SpamMessage( - SpamTokens.fillAll( - format.get(), - SPAM_TOKENS, - event.getPlayerInfo().getName(), - entry.getRandomMessage()), - "JOIN_MESSAGE", - delay.get(), - null, - PriorityEnum.HIGH)); + new SpamMessage( + SpamTokens.fillAll( + format.get(), + SPAM_TOKENS, + event.getPlayerInfo().getName(), + entry.getRandomMessage()), + "JOIN_MESSAGE", + delay.get(), + null, + PriorityEnum.HIGH)); } } } diff --git a/src/main/java/com/matt/forgehax/mods/KillAura.java b/src/main/java/com/matt/forgehax/mods/KillAura.java index 060219477..6c2781596 100644 --- a/src/main/java/com/matt/forgehax/mods/KillAura.java +++ b/src/main/java/com/matt/forgehax/mods/KillAura.java @@ -4,19 +4,22 @@ import com.matt.forgehax.util.mod.ToggleMod; import net.minecraft.entity.Entity; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class KillAura extends ToggleMod { + enum TargetModes { CLOSEST, CROSSHAIR } - + private TargetModes modes = TargetModes.CLOSEST; - + public KillAura() { super(Category.COMBAT, "KillAura", false, "Attack anything within given parameters"); } - + private Entity getTarget() { return null; } diff --git a/src/main/java/com/matt/forgehax/mods/LogoutSpot.java b/src/main/java/com/matt/forgehax/mods/LogoutSpot.java index 0c5637e63..8c19396ac 100644 --- a/src/main/java/com/matt/forgehax/mods/LogoutSpot.java +++ b/src/main/java/com/matt/forgehax/mods/LogoutSpot.java @@ -3,8 +3,6 @@ import static com.matt.forgehax.Helper.getLocalPlayer; import static com.matt.forgehax.Helper.getWorld; -import com.github.lunatrius.core.client.renderer.unique.GeometryMasks; -import com.github.lunatrius.core.client.renderer.unique.GeometryTessellator; import com.google.common.collect.Sets; import com.matt.forgehax.Helper; import com.matt.forgehax.events.LocalPlayerUpdateEvent; @@ -19,7 +17,10 @@ import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; -import java.util.*; +import com.matt.forgehax.util.tesselation.GeometryMasks; +import com.matt.forgehax.util.tesselation.GeometryTessellator; +import java.util.Set; +import java.util.UUID; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.math.AxisAlignedBB; @@ -31,198 +32,210 @@ @RegisterMod public class LogoutSpot extends ToggleMod { + private final Setting render = - getCommandStub() - .builders() - .newSettingBuilder() - .name("render") - .description("Draw a box where the player logged out") - .defaultTo(true) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("render") + .description("Draw a box where the player logged out") + .defaultTo(true) + .build(); private final Setting max_distance = - getCommandStub() - .builders() - .newSettingBuilder() - .name("max-distance") - .description("Distance from box before deleting it") - .defaultTo(320) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("max-distance") + .description("Distance from box before deleting it") + .defaultTo(320) + .build(); private final Setting print_message = - getCommandStub() - .builders() - .newSettingBuilder() - .name("print-message") - .description("Print connect/disconnect messages in chat") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("print-message") + .description("Print connect/disconnect messages in chat") + .defaultTo(true) + .build(); + private final Set spots = Sets.newHashSet(); - + public LogoutSpot() { super(Category.RENDER, "LogoutSpot", false, "show where a player logs out"); } - + private void reset() { synchronized (spots) { spots.clear(); } } - + private void printWarning(String fmt, Object... args) { - if (print_message.get()) Helper.printWarning(fmt, args); + if (print_message.get()) { + Helper.printWarning(fmt, args); + } } - + @Override public void onLoad() { getCommandStub() - .builders() - .newCommandBuilder() - .name("clear") - .description("Clear cloned players") - .processor(data -> reset()) - .build(); + .builders() + .newCommandBuilder() + .name("clear") + .description("Clear cloned players") + .processor(data -> reset()) + .build(); } - + @Override protected void onDisabled() { reset(); } - + @SubscribeEvent public void onPlayerConnect(PlayerConnectEvent.Join event) { synchronized (spots) { - if (spots.removeIf(spot -> spot.getId().equals(event.getPlayerInfo().getId()))) + if (spots.removeIf(spot -> spot.getId().equals(event.getPlayerInfo().getId()))) { printWarning("%s has joined!", event.getPlayerInfo().getName()); + } } } - + @SubscribeEvent public void onPlayerDisconnect(PlayerConnectEvent.Leave event) { - if (getWorld() == null) return; - + if (getWorld() == null) { + return; + } + EntityPlayer player = getWorld().getPlayerEntityByUUID(event.getPlayerInfo().getId()); if (player != null && getLocalPlayer() != null && !getLocalPlayer().equals(player)) { AxisAlignedBB bb = player.getEntityBoundingBox(); synchronized (spots) { if (spots.add( - new LogoutPos( - event.getPlayerInfo().getId(), - event.getPlayerInfo().getName(), - new Vec3d(bb.maxX, bb.maxY, bb.maxZ), - new Vec3d(bb.minX, bb.minY, bb.minZ)))) + new LogoutPos( + event.getPlayerInfo().getId(), + event.getPlayerInfo().getName(), + new Vec3d(bb.maxX, bb.maxY, bb.maxZ), + new Vec3d(bb.minX, bb.minY, bb.minZ)))) { printWarning("%s has disconnected!", event.getPlayerInfo().getName()); + } } } } - + @SubscribeEvent(priority = EventPriority.LOW) public void onRenderGameOverlayEvent(Render2DEvent event) { - if (!render.get()) return; - + if (!render.get()) { + return; + } + synchronized (spots) { spots.forEach( - spot -> { - Vec3d top = spot.getTopVec(); - Plane upper = VectorUtils.toScreen(top); - if (upper.isVisible()) { - double distance = getLocalPlayer().getPositionVector().distanceTo(top); - String name = String.format("%s (%.1f)", spot.getName(), distance); - SurfaceHelper.drawTextShadow( - name, - (int) upper.getX() - (SurfaceHelper.getTextWidth(name) / 2), - (int) upper.getY() - (SurfaceHelper.getTextHeight() + 1), - Colors.RED.toBuffer()); - } - }); + spot -> { + Vec3d top = spot.getTopVec(); + Plane upper = VectorUtils.toScreen(top); + if (upper.isVisible()) { + double distance = getLocalPlayer().getPositionVector().distanceTo(top); + String name = String.format("%s (%.1f)", spot.getName(), distance); + SurfaceHelper.drawTextShadow( + name, + (int) upper.getX() - (SurfaceHelper.getTextWidth(name) / 2), + (int) upper.getY() - (SurfaceHelper.getTextHeight() + 1), + Colors.RED.toBuffer()); + } + }); } } - + @SubscribeEvent public void onRender(RenderEvent event) { - if (!render.get()) return; - + if (!render.get()) { + return; + } + event.getBuffer().begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); - + synchronized (spots) { spots.forEach( - spot -> - GeometryTessellator.drawLines( - event.getBuffer(), - spot.getMins().x, - spot.getMins().y, - spot.getMins().z, - spot.getMaxs().x, - spot.getMaxs().y, - spot.getMaxs().z, - GeometryMasks.Line.ALL, - Colors.RED.toBuffer())); + spot -> + GeometryTessellator.drawLines( + event.getBuffer(), + spot.getMins().x, + spot.getMins().y, + spot.getMins().z, + spot.getMaxs().x, + spot.getMaxs().y, + spot.getMaxs().z, + GeometryMasks.Line.ALL, + Colors.RED.toBuffer())); } - + event.getTessellator().draw(); } - + @SubscribeEvent public void onPlayerUpdate(LocalPlayerUpdateEvent event) { if (max_distance.get() > 0) { synchronized (spots) { spots.removeIf( - pos -> - getLocalPlayer().getPositionVector().distanceTo(pos.getTopVec()) - > max_distance.getAsDouble()); + pos -> + getLocalPlayer().getPositionVector().distanceTo(pos.getTopVec()) + > max_distance.getAsDouble()); } } } - + @SubscribeEvent public void onWorldUnload(WorldEvent.Unload event) { reset(); } - + @SubscribeEvent public void onWorldLoad(WorldEvent.Load event) { reset(); } - + private class LogoutPos { + final UUID id; final String name; final Vec3d maxs; final Vec3d mins; - + private LogoutPos(UUID uuid, String name, Vec3d maxs, Vec3d mins) { this.id = uuid; this.name = name; this.maxs = maxs; this.mins = mins; } - + public UUID getId() { return id; } - + public String getName() { return name; } - + public Vec3d getMaxs() { return maxs; } - + public Vec3d getMins() { return mins; } - + public Vec3d getTopVec() { return new Vec3d( - (getMins().x + getMaxs().x) / 2.D, getMaxs().y, (getMins().z + getMaxs().z) / 2.D); + (getMins().x + getMaxs().x) / 2.D, getMaxs().y, (getMins().z + getMaxs().z) / 2.D); } - + @Override public boolean equals(Object other) { return this == other - || (other instanceof LogoutPos && getId().equals(((LogoutPos) other).getId())); + || (other instanceof LogoutPos && getId().equals(((LogoutPos) other).getId())); } - + @Override public int hashCode() { return getId().hashCode(); diff --git a/src/main/java/com/matt/forgehax/mods/ManualDeleteMod.java b/src/main/java/com/matt/forgehax/mods/ManualDeleteMod.java index 44178213c..cc4ee4442 100644 --- a/src/main/java/com/matt/forgehax/mods/ManualDeleteMod.java +++ b/src/main/java/com/matt/forgehax/mods/ManualDeleteMod.java @@ -13,19 +13,23 @@ @RegisterMod public class ManualDeleteMod extends ToggleMod { - + public ManualDeleteMod() { - super(Category.WORLD, "ManualEntityDelete", false, "Manually delete entities with middle click"); + super(Category.WORLD, "ManualEntityDelete", false, + "Manually delete entities with middle click"); } - + @SubscribeEvent public void onInput(MouseEvent event) { - if(getWorld() == null || getLocalPlayer() == null) + if (getWorld() == null || getLocalPlayer() == null) { return; - + } + if (event.getButton() == 2 && Mouse.getEventButtonState()) { // on middle click RayTraceResult aim = MC.objectMouseOver; - if (aim == null) return; + if (aim == null) { + return; + } if (aim.typeOfHit == RayTraceResult.Type.ENTITY) { if (aim.entityHit != null) { MC.world.removeEntity(aim.entityHit); @@ -33,4 +37,4 @@ public void onInput(MouseEvent event) { } } } -} \ No newline at end of file +} diff --git a/src/main/java/com/matt/forgehax/mods/MapDownloader.java b/src/main/java/com/matt/forgehax/mods/MapDownloader.java index f49fccd11..c6e44df71 100644 --- a/src/main/java/com/matt/forgehax/mods/MapDownloader.java +++ b/src/main/java/com/matt/forgehax/mods/MapDownloader.java @@ -1,10 +1,10 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.util.ImageUtils.*; +import static com.matt.forgehax.util.ImageUtils.createResizedCopy; import com.matt.forgehax.Helper; import com.matt.forgehax.asm.reflection.FastReflection; -import com.matt.forgehax.log.FileManager; +import com.matt.forgehax.util.FileManager; import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; @@ -18,18 +18,20 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.MapData; -/** Created by Babbaj on 11/6/2017. */ +/** + * Created by Babbaj on 11/6/2017. + */ @RegisterMod public class MapDownloader extends ToggleMod { - + private File outputDir; - + public MapDownloader() { super(Category.MISC, "MapDownloader", false, "Saves map items as images"); } - + private void saveImage(String fileName, BufferedImage image) { - + if (outputDir == null) { outputDir = FileManager.getInstance().getBaseResolve("maps").toFile(); } @@ -43,73 +45,82 @@ private void saveImage(String fileName, BufferedImage image) { Helper.printStackTrace(e); } } - + private void downloadMap(String fileName, Integer scaledRes) { - if (MC.player == null || !(MC.player.getHeldItemMainhand().getItem() instanceof ItemMap)) + if (MC.player == null || !(MC.player.getHeldItemMainhand().getItem() instanceof ItemMap)) { return; - + } + ItemMap map = (ItemMap) MC.player.getHeldItemMainhand().getItem(); MapData heldMapData = map.getMapData(MC.player.getHeldItemMainhand(), MC.world); - - if (fileName == null) fileName = heldMapData.mapName; - + + if (fileName == null) { + fileName = heldMapData.mapName; + } + ResourceLocation location = findResourceLocation(heldMapData.mapName); if (location == null) { Helper.printMessage("Failed to find ResourceLocation"); return; } - + DynamicTexture texture = (DynamicTexture) MC.getTextureManager().getTexture(location); BufferedImage image = dynamicToImage(texture); - if (scaledRes != null) image = createResizedCopy(image, scaledRes, scaledRes, true); - + if (scaledRes != null) { + image = createResizedCopy(image, scaledRes, scaledRes, true); + } + saveImage(fileName, image); } - + private ResourceLocation findResourceLocation(String name) { Map mapTextureObjects = - FastReflection.Fields.TextureManager_mapTextureObjects.get(MC.getTextureManager()); - + FastReflection.Fields.TextureManager_mapTextureObjects.get(MC.getTextureManager()); + return mapTextureObjects - .keySet() - .stream() - .filter(k -> k.getResourcePath().contains(name)) - .findFirst() - .orElse(null); + .keySet() + .stream() + .filter(k -> k.getResourcePath().contains(name)) + .findFirst() + .orElse(null); } - + // TODO: generalize this private BufferedImage dynamicToImage(DynamicTexture texture) { int[] data = texture.getTextureData(); - if (data.length != 128 * 128) return null; - + if (data.length != 128 * 128) { + return null; + } + BufferedImage image = new BufferedImage(128, 128, 2); - + image.setRGB(0, 0, image.getWidth(), image.getHeight(), data, 0, 128); return image; } - + @Override public void onLoad() { getCommandStub() - .builders() - .newCommandBuilder() - .name("Download") - .description("Download the held map as an image") - .processor( - data -> { - data.requiredArguments(0); - // do stuff - String fileName = data.getArgument(0); - Integer scaledRes = null; - try { - if (data.getArgument(1) != null) scaledRes = Integer.valueOf(data.getArgument(1)); - } catch (NumberFormatException e) { - Helper.printMessage("Failed to parse resolution"); - } - - downloadMap(fileName, scaledRes); - }) - .build(); + .builders() + .newCommandBuilder() + .name("Download") + .description("Download the held map as an image") + .processor( + data -> { + data.requiredArguments(0); + // do stuff + String fileName = data.getArgument(0); + Integer scaledRes = null; + try { + if (data.getArgument(1) != null) { + scaledRes = Integer.valueOf(data.getArgument(1)); + } + } catch (NumberFormatException e) { + Helper.printMessage("Failed to parse resolution"); + } + + downloadMap(fileName, scaledRes); + }) + .build(); } } diff --git a/src/main/java/com/matt/forgehax/mods/MapMod.java b/src/main/java/com/matt/forgehax/mods/MapMod.java index 23c39a34a..51a337c35 100644 --- a/src/main/java/com/matt/forgehax/mods/MapMod.java +++ b/src/main/java/com/matt/forgehax/mods/MapMod.java @@ -1,16 +1,18 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.util.ImageUtils.*; -import static com.matt.forgehax.util.MapColors.*; +import static com.matt.forgehax.util.ImageUtils.createResizedCopy; +import static com.matt.forgehax.util.ImageUtils.getImageFromUrl; +import static com.matt.forgehax.util.ImageUtils.imageToArray; +import static com.matt.forgehax.util.MapColors.colorListLength; +import static com.matt.forgehax.util.MapColors.getColor; import com.matt.forgehax.Helper; import com.matt.forgehax.asm.reflection.FastReflection; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Color; import com.matt.forgehax.util.command.Setting; import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; -import java.awt.*; import java.awt.image.BufferedImage; import java.util.Map; import net.minecraft.client.renderer.texture.DynamicTexture; @@ -19,150 +21,155 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.MapData; -/** Created by Babbaj on 8/18/2017. */ +/** + * Created by Babbaj on 8/18/2017. + */ @RegisterMod public class MapMod extends ToggleMod { + public MapMod() { super(Category.MISC, "MapMod", false, "custom map images"); } - + private enum Mode { DATA, TEXTURE } - + public final Setting mode = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("mode") - .description("[DATA]change map data or [TEXTURE]render full image") - .defaultTo(MapMod.Mode.DATA) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("mode") + .description("[DATA]change map data or [TEXTURE]render full image") + .defaultTo(MapMod.Mode.DATA) + .build(); + private byte closest_color_RGB(int colorIn) { - int[] RGB_Array = Utils.toRGBAArray(colorIn); // [0] red [1] green [2] blue [3] alpha - + int[] RGB_Array = Color.of(colorIn).toIntegerArray(); // [0] red [1] green [2] blue [3] alpha + double closestDistance = 500; // create a starting point int closestColorIndex = - 4; // index of COLOR_LIST that is the closest color we've found to the input color - start + 4; // index of COLOR_LIST that is the closest color we've found to the input color - start // at 4 so we dont ever use air for (int i = 4; i < colorListLength(); i++) { - int[] currentColor = Utils.toRGBAArray(getColor(i)); + int[] currentColor = Color.of(getColor(i)).toIntegerArray(); double distance = distanceBetweenColors(currentColor, RGB_Array); if (distance < closestDistance) { closestDistance = distance; closestColorIndex = i; } } - + return (byte) closestColorIndex; } - + private double distanceBetweenColors(int[] a, int[] b) { return Math.sqrt( - (a[0] - b[0]) * (a[0] - b[0]) - + (a[1] - b[1]) * (a[1] - b[1]) - + (a[2] - b[2]) * (a[2] - b[2])); + (a[0] - b[0]) * (a[0] - b[0]) + + (a[1] - b[1]) * (a[1] - b[1]) + + (a[2] - b[2]) * (a[2] - b[2])); } - + private void updateHeldMap(String url) { - if (MC.player == null || !(MC.player.getHeldItemMainhand().getItem() instanceof ItemMap)) + if (MC.player == null || !(MC.player.getHeldItemMainhand().getItem() instanceof ItemMap)) { return; - + } + BufferedImage image = getImageFromUrl(url); if (image == null) { Helper.printMessage("Failed to download image"); return; } - + image = createResizedCopy(image, 128, 128, false); int[][] imageColors = imageToArray(image); // convert image into a 2d array of rgba integers - + byte[] convertedMapColors = - new byte - [128 - * 128]; // create a 1d array 128^2 in length that will be used to hold the final map + new byte + [128 + * 128]; // create a 1d array 128^2 in length that will be used to hold the final map // data - + int count = 0; for (int x = 0; x < 128; x++) { // iterate vertically for (int y = 0; y < 128; y++) { // iterate through row of pixels imageColors[y][x] = - closest_color_RGB( - imageColors[y][ - x]); // each color in the image data now a color in COLOR_LIST that is the + closest_color_RGB( + imageColors[y][ + x]); // each color in the image data now a color in COLOR_LIST that is the // closest match convertedMapColors[count] = - (byte) imageColors[y][x]; // convert the 2d array into a 1d array + (byte) imageColors[y][x]; // convert the 2d array into a 1d array count++; } // normally would do [x][y] but that appears to cause a rotation problem that is fixed by // doing [j][i] } - + ItemMap map = (ItemMap) MC.player.getHeldItemMainhand().getItem(); - + MapData heldMapData = map.getMapData(MC.player.getHeldItemMainhand(), MC.world); - + heldMapData.colors = convertedMapColors; // set the colors of the map to the colors of the image } - + private void updateHeldMapTexture(String url) { - if (MC.player == null || !(MC.player.getHeldItemMainhand().getItem() instanceof ItemMap)) + if (MC.player == null || !(MC.player.getHeldItemMainhand().getItem() instanceof ItemMap)) { return; - + } + MC.addScheduledTask( - () -> { // allows DynamicTexture to work - ItemMap map = (ItemMap) MC.player.getHeldItemMainhand().getItem(); - MapData heldMapData = map.getMapData(MC.player.getHeldItemMainhand(), MC.world); - - try { - BufferedImage image = getImageFromUrl(url); - - DynamicTexture dynamicTexture = new DynamicTexture(image); - dynamicTexture.loadTexture(MC.getResourceManager()); - - Map mapTextureObjects = - FastReflection.Fields.TextureManager_mapTextureObjects.get(MC.getTextureManager()); - - ResourceLocation textureLocation = - mapTextureObjects - .keySet() - .stream() - .filter(k -> k.getResourcePath().contains(heldMapData.mapName)) - .findFirst() - .orElse(null); - - mapTextureObjects.put( - textureLocation, dynamicTexture); // overwrite old texture with our custom one - - } catch (Exception e) { - e.printStackTrace(); - } - }); + () -> { // allows DynamicTexture to work + ItemMap map = (ItemMap) MC.player.getHeldItemMainhand().getItem(); + MapData heldMapData = map.getMapData(MC.player.getHeldItemMainhand(), MC.world); + + try { + BufferedImage image = getImageFromUrl(url); + + DynamicTexture dynamicTexture = new DynamicTexture(image); + dynamicTexture.loadTexture(MC.getResourceManager()); + + Map mapTextureObjects = + FastReflection.Fields.TextureManager_mapTextureObjects.get(MC.getTextureManager()); + + ResourceLocation textureLocation = + mapTextureObjects + .keySet() + .stream() + .filter(k -> k.getResourcePath().contains(heldMapData.mapName)) + .findFirst() + .orElse(null); + + mapTextureObjects.put( + textureLocation, dynamicTexture); // overwrite old texture with our custom one + + } catch (Exception e) { + e.printStackTrace(); + } + }); } - + @Override public void onLoad() { getCommandStub() - .builders() - .newCommandBuilder() - .name("updatemap") - .description("Update held map with image from internet") - .processor( - data -> { - data.requiredArguments(1); - // do stuff - String url = data.getArgumentAsString(0); - switch (mode.get()) { - case DATA: - updateHeldMap(url); - break; - case TEXTURE: - updateHeldMapTexture(url); - break; - } - }) - .build(); + .builders() + .newCommandBuilder() + .name("updatemap") + .description("Update held map with image from internet") + .processor( + data -> { + data.requiredArguments(1); + // do stuff + String url = data.getArgumentAsString(0); + switch (mode.get()) { + case DATA: + updateHeldMap(url); + break; + case TEXTURE: + updateHeldMapTexture(url); + break; + } + }) + .build(); } } diff --git a/src/main/java/com/matt/forgehax/mods/Markers.java b/src/main/java/com/matt/forgehax/mods/Markers.java index 837941415..4b040cbc2 100644 --- a/src/main/java/com/matt/forgehax/mods/Markers.java +++ b/src/main/java/com/matt/forgehax/mods/Markers.java @@ -1,21 +1,26 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getLog; +import static com.matt.forgehax.Helper.getWorld; +import static com.matt.forgehax.Helper.reloadChunks; +import static com.matt.forgehax.Helper.reloadChunksHard; -import com.github.lunatrius.core.client.renderer.unique.GeometryMasks; -import com.github.lunatrius.core.client.renderer.unique.GeometryTessellator; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.matt.forgehax.Helper; import com.matt.forgehax.asm.ForgeHaxHooks; -import com.matt.forgehax.asm.events.*; +import com.matt.forgehax.asm.events.BuildChunkEvent; +import com.matt.forgehax.asm.events.ChunkUploadedEvent; +import com.matt.forgehax.asm.events.DeleteGlResourcesEvent; +import com.matt.forgehax.asm.events.LoadRenderersEvent; +import com.matt.forgehax.asm.events.WorldRendererDeallocatedEvent; import com.matt.forgehax.asm.events.listeners.BlockModelRenderListener; import com.matt.forgehax.asm.events.listeners.Listeners; import com.matt.forgehax.events.RenderEvent; -import com.matt.forgehax.util.Utils; import com.matt.forgehax.util.blocks.BlockEntry; import com.matt.forgehax.util.blocks.properties.BoundProperty; import com.matt.forgehax.util.blocks.properties.ColorProperty; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.command.ExecuteData; import com.matt.forgehax.util.command.Options; import com.matt.forgehax.util.command.Setting; @@ -29,7 +34,13 @@ import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; -import java.util.*; +import com.matt.forgehax.util.tesselation.GeometryMasks; +import com.matt.forgehax.util.tesselation.GeometryTessellator; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nullable; import net.minecraft.block.Block; @@ -51,326 +62,337 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.opengl.GL11; -/** Created on 5/5/2017 by fr1kin */ +/** + * Created on 5/5/2017 by fr1kin + */ @RegisterMod public class Markers extends ToggleMod implements BlockModelRenderListener { + private static final int VERTEX_BUFFER_COUNT = 100; private static final int VERTEX_BUFFER_SIZE = 0x200; - + private final AtomicInteger renderingCount = new AtomicInteger(0); private final AtomicInteger dummyCount = new AtomicInteger(0); private final AtomicInteger wrongRegionCount = new AtomicInteger(0); - - @Nullable private Uploaders uploaders; - + + @Nullable + private Uploaders uploaders; + private Vec3d renderingOffset = new Vec3d(0, 0, 0); - + public final Options options = - getCommandStub() - .builders() - .newOptionsBuilder() - .name("options") - .description("Marker block options") - .supplier(Sets::newConcurrentHashSet) - .factory(BlockEntry::new) - .defaults( - () -> { - Set contents = Sets.newHashSet(); - BlockEntry entry; - try { - // chest - entry = new BlockEntry(Blocks.CHEST, -1, true); - entry.getWritableProperty(ColorProperty.class).set(255, 128, 0, 255); - contents.add(entry); - - // trapped chest - entry = new BlockEntry(Blocks.TRAPPED_CHEST, -1, true); - entry.getWritableProperty(ColorProperty.class).set(255, 92, 0, 255); - contents.add(entry); - - // ender chest - entry = new BlockEntry(Blocks.ENDER_CHEST, -1, true); - entry.getWritableProperty(ColorProperty.class).set(64, 0, 128, 255); - contents.add(entry); - - // nether portal - entry = new BlockEntry(Blocks.PORTAL, -1, true); - entry.getWritableProperty(ColorProperty.class).set(255, 0, 255, 255); - contents.add(entry); - - // end portal - entry = new BlockEntry(Blocks.END_PORTAL, -1, true); - entry.getWritableProperty(ColorProperty.class).set(64, 0, 64, 255); - contents.add(entry); - - // bed - entry = new BlockEntry(Blocks.BED, -1, true); - entry.getWritableProperty(ColorProperty.class).set(255, 0, 0, 255); - contents.add(entry); - - // dispenser - entry = new BlockEntry(Blocks.DISPENSER, -1, true); - entry.getWritableProperty(ColorProperty.class).set(0, 255, 0, 100); - contents.add(entry); - - // dropper - entry = new BlockEntry(Blocks.DROPPER, -1, true); - entry.getWritableProperty(ColorProperty.class).set(0, 128, 0, 150); - contents.add(entry); - - // hopper - entry = new BlockEntry(Blocks.HOPPER, -1, true); - entry.getWritableProperty(ColorProperty.class).set(0, 64, 128, 75); - contents.add(entry); - - // furnace - entry = new BlockEntry(Blocks.FURNACE, -1, true); - entry.getWritableProperty(ColorProperty.class).set(128, 128, 128, 150); - contents.add(entry); - - // furnace - entry = new BlockEntry(Blocks.LIT_FURNACE, -1, true); - entry.getWritableProperty(ColorProperty.class).set(128, 128, 128, 150); - contents.add(entry); - - // beacon - entry = new BlockEntry(Blocks.BEACON, -1, true); - entry.getWritableProperty(ColorProperty.class).set(0, 255, 255, 150); - contents.add(entry); - - // mob_spawner - entry = new BlockEntry(Blocks.MOB_SPAWNER, -1, true); - entry.getWritableProperty(ColorProperty.class).set(255, 64, 64, 255); - contents.add(entry); - - // shulker boxes - for (Block shulker : - new Block[] { - Blocks.WHITE_SHULKER_BOX, - Blocks.ORANGE_SHULKER_BOX, - Blocks.MAGENTA_SHULKER_BOX, - Blocks.LIGHT_BLUE_SHULKER_BOX, - Blocks.YELLOW_SHULKER_BOX, - Blocks.LIME_SHULKER_BOX, - Blocks.PINK_SHULKER_BOX, - Blocks.GRAY_SHULKER_BOX, - Blocks.SILVER_SHULKER_BOX, - Blocks.CYAN_SHULKER_BOX, - Blocks.PURPLE_SHULKER_BOX, - Blocks.BLUE_SHULKER_BOX, - Blocks.BROWN_SHULKER_BOX, - Blocks.GREEN_SHULKER_BOX, - Blocks.RED_SHULKER_BOX, - Blocks.BLACK_SHULKER_BOX - }) { - entry = new BlockEntry(shulker, -1, true); - entry.getWritableProperty(ColorProperty.class).set(255, 255, 0, 255); - contents.add(entry); - } - } catch (Throwable t) { - // ignore - getLog().warn(t.getMessage()); - } - return contents; - }) - .build(); - + getCommandStub() + .builders() + .newOptionsBuilder() + .name("options") + .description("Marker block options") + .supplier(Sets::newConcurrentHashSet) + .factory(BlockEntry::new) + .defaults( + () -> { + Set contents = Sets.newHashSet(); + BlockEntry entry; + try { + // chest + entry = new BlockEntry(Blocks.CHEST, -1, true); + entry.getWritableProperty(ColorProperty.class).set(255, 128, 0, 255); + contents.add(entry); + + // trapped chest + entry = new BlockEntry(Blocks.TRAPPED_CHEST, -1, true); + entry.getWritableProperty(ColorProperty.class).set(255, 92, 0, 255); + contents.add(entry); + + // ender chest + entry = new BlockEntry(Blocks.ENDER_CHEST, -1, true); + entry.getWritableProperty(ColorProperty.class).set(64, 0, 128, 255); + contents.add(entry); + + // nether portal + entry = new BlockEntry(Blocks.PORTAL, -1, true); + entry.getWritableProperty(ColorProperty.class).set(255, 0, 255, 255); + contents.add(entry); + + // end portal + entry = new BlockEntry(Blocks.END_PORTAL, -1, true); + entry.getWritableProperty(ColorProperty.class).set(64, 0, 64, 255); + contents.add(entry); + + // bed + entry = new BlockEntry(Blocks.BED, -1, true); + entry.getWritableProperty(ColorProperty.class).set(255, 0, 0, 255); + contents.add(entry); + + // dispenser + entry = new BlockEntry(Blocks.DISPENSER, -1, true); + entry.getWritableProperty(ColorProperty.class).set(0, 255, 0, 100); + contents.add(entry); + + // dropper + entry = new BlockEntry(Blocks.DROPPER, -1, true); + entry.getWritableProperty(ColorProperty.class).set(0, 128, 0, 150); + contents.add(entry); + + // hopper + entry = new BlockEntry(Blocks.HOPPER, -1, true); + entry.getWritableProperty(ColorProperty.class).set(0, 64, 128, 75); + contents.add(entry); + + // furnace + entry = new BlockEntry(Blocks.FURNACE, -1, true); + entry.getWritableProperty(ColorProperty.class).set(128, 128, 128, 150); + contents.add(entry); + + // furnace + entry = new BlockEntry(Blocks.LIT_FURNACE, -1, true); + entry.getWritableProperty(ColorProperty.class).set(128, 128, 128, 150); + contents.add(entry); + + // beacon + entry = new BlockEntry(Blocks.BEACON, -1, true); + entry.getWritableProperty(ColorProperty.class).set(0, 255, 255, 150); + contents.add(entry); + + // mob_spawner + entry = new BlockEntry(Blocks.MOB_SPAWNER, -1, true); + entry.getWritableProperty(ColorProperty.class).set(255, 64, 64, 255); + contents.add(entry); + + // shulker boxes + for (Block shulker : + new Block[]{ + Blocks.WHITE_SHULKER_BOX, + Blocks.ORANGE_SHULKER_BOX, + Blocks.MAGENTA_SHULKER_BOX, + Blocks.LIGHT_BLUE_SHULKER_BOX, + Blocks.YELLOW_SHULKER_BOX, + Blocks.LIME_SHULKER_BOX, + Blocks.PINK_SHULKER_BOX, + Blocks.GRAY_SHULKER_BOX, + Blocks.SILVER_SHULKER_BOX, + Blocks.CYAN_SHULKER_BOX, + Blocks.PURPLE_SHULKER_BOX, + Blocks.BLUE_SHULKER_BOX, + Blocks.BROWN_SHULKER_BOX, + Blocks.GREEN_SHULKER_BOX, + Blocks.RED_SHULKER_BOX, + Blocks.BLACK_SHULKER_BOX + }) { + entry = new BlockEntry(shulker, -1, true); + entry.getWritableProperty(ColorProperty.class).set(255, 255, 0, 255); + contents.add(entry); + } + } catch (Throwable t) { + // ignore + getLog().warn(t.getMessage()); + } + return contents; + }) + .build(); + public final Setting clear_buffer = - getCommandStub() - .builders() - .newSettingBuilder() - .name("clear_buffer") - .description("Clear the buffer instead of disabling depth") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("clear_buffer") + .description("Clear the buffer instead of disabling depth") + .defaultTo(false) + .build(); + public final Setting anti_aliasing = - getCommandStub() - .builders() - .newSettingBuilder() - .name("antialiasing") - .description("Enables antialiasing on lines") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("antialiasing") + .description("Enables antialiasing on lines") + .defaultTo(false) + .build(); + public final Setting anti_aliasing_max = - getCommandStub() - .builders() - .newSettingBuilder() - .name("antialiasing_max") - .description( - "Maximum number of render elements allowed in a render chunk until antialiasing is disabled") - .defaultTo(0) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("antialiasing_max") + .description( + "Maximum number of render elements allowed in a render chunk until antialiasing is disabled") + .defaultTo(0) + .build(); + public final Setting show_entities = - getCommandStub() - .builders() - .newSettingBuilder() - .name("show_entities") - .description("Mark entities that contain blocks, such as mine carts.") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("show_entities") + .description("Mark entities that contain blocks, such as mine carts.") + .defaultTo(true) + .build(); + public final Setting debug = - getCommandStub() - .builders() - .newSettingBuilder() - .name("debug") - .description("Enable debug mode") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("debug") + .description("Enable debug mode") + .defaultTo(false) + .build(); + public Markers() { super(Category.RENDER, "Markers", false, "Renders a box around a block"); } - + @Override public void onLoad() { options - .builders() - .newCommandBuilder() - .name("add") - .description("Adds block to block esp") - .options(OptionBuilders::rgba) - .processor(OptionProcessors::rgba) - .options(OptionBuilders::meta) - .processor(OptionProcessors::meta) - .options(OptionBuilders::id) - .options(OptionBuilders::regex) - .options(OptionBuilders::bounds) - .processor(BlockEntryProcessor::buildCollection) - .processor(BlockEntryProcessor::processBounds) - .processor(BlockEntryProcessor::processColor) - .processor( - data -> { - data.requiredArguments(1); - data.requiresEntry("entries"); - - Collection entries = data.get("entries"); - - final boolean isColorPresent = data.get("isColorPresent", false); - - final int colorBuffer = data.get("colorBuffer", Utils.Colors.WHITE); - - entries.forEach( - entry -> { - // check if there is an existing entry already in the list - // if so then append options to it - final BlockEntry existing = options.get(entry); - if (existing != null) { - // set color if a color was specified by the client - if (isColorPresent) - existing.getWritableProperty(ColorProperty.class).set(colorBuffer); - // copy bounds from entry into the existing one - entry - .getReadableProperty(BoundProperty.class) - .getAll() - .forEach( - bound -> - existing - .getWritableProperty(BoundProperty.class) - .add(bound.getMin(), bound.getMax())); - data.markSuccess(); - } else if (options.add(entry)) { - Helper.printMessage("Added block \"%s\"", entry.getPrettyName()); - data.markSuccess(); - } else { - Helper.printMessage("Failed to add block \"%s\"", entry.getPrettyName()); - data.markFailed(ExecuteData.State.SUCCESS); - } - }); - }) - .success(cmd -> reloadChunks()) - .build(); + .builders() + .newCommandBuilder() + .name("add") + .description("Adds block to block esp") + .options(OptionBuilders::rgba) + .processor(OptionProcessors::rgba) + .options(OptionBuilders::meta) + .processor(OptionProcessors::meta) + .options(OptionBuilders::id) + .options(OptionBuilders::regex) + .options(OptionBuilders::bounds) + .processor(BlockEntryProcessor::buildCollection) + .processor(BlockEntryProcessor::processBounds) + .processor(BlockEntryProcessor::processColor) + .processor( + data -> { + data.requiredArguments(1); + data.requiresEntry("entries"); + + Collection entries = data.get("entries"); + + final boolean isColorPresent = data.get("isColorPresent", false); + + final int colorBuffer = data.get("colorBuffer", Colors.WHITE.toBuffer()); + + entries.forEach( + entry -> { + // check if there is an existing entry already in the list + // if so then append options to it + final BlockEntry existing = options.get(entry); + if (existing != null) { + // set color if a color was specified by the client + if (isColorPresent) { + existing.getWritableProperty(ColorProperty.class).set(colorBuffer); + } + // copy bounds from entry into the existing one + entry + .getReadableProperty(BoundProperty.class) + .getAll() + .forEach( + bound -> + existing + .getWritableProperty(BoundProperty.class) + .add(bound.getMin(), bound.getMax())); + data.markSuccess(); + } else if (options.add(entry)) { + Helper.printMessage("Added block \"%s\"", entry.getPrettyName()); + data.markSuccess(); + } else { + Helper.printMessage("Failed to add block \"%s\"", entry.getPrettyName()); + data.markFailed(ExecuteData.State.SUCCESS); + } + }); + }) + .success(cmd -> reloadChunks()) + .build(); options - .builders() - .newCommandBuilder() - .name("remove") - .description("Removes block to block esp") - .options(OptionBuilders::meta) - .processor(OptionProcessors::meta) - .options(OptionBuilders::id) - .options(OptionBuilders::regex) - .options(OptionBuilders::bounds) - .processor(BlockEntryProcessor::buildCollection) - .processor(BlockEntryProcessor::processBounds) - .processor( - data -> { - data.requiredArguments(1); - data.requiresEntry("entries"); - - Collection entries = data.get("entries"); - - final boolean isBoundPresent = data.has("bounds"); - - entries.forEach( - entry -> { - final BlockEntry existing = options.get(entry); - if (existing != null) { - if (isBoundPresent) { - // copy bounds from entry into the existing one - entry - .getReadableProperty(BoundProperty.class) - .getAll() - .forEach( - bound -> - existing - .getWritableProperty(BoundProperty.class) - .remove(bound.getMin(), bound.getMax())); - data.markSuccess(); - } else if (options.remove(existing)) { - Helper.printMessage("Removed block \"%s\"", entry.getPrettyName()); - data.markSuccess(); - } - } else if (entries.size() <= 1) { - Helper.printMessage("Failed to remove block \"%s\"", entry.getPrettyName()); - data.markFailed(ExecuteData.State.SUCCESS); - } - }); - }) - .success(cmd -> reloadChunks()) - .build(); + .builders() + .newCommandBuilder() + .name("remove") + .description("Removes block to block esp") + .options(OptionBuilders::meta) + .processor(OptionProcessors::meta) + .options(OptionBuilders::id) + .options(OptionBuilders::regex) + .options(OptionBuilders::bounds) + .processor(BlockEntryProcessor::buildCollection) + .processor(BlockEntryProcessor::processBounds) + .processor( + data -> { + data.requiredArguments(1); + data.requiresEntry("entries"); + + Collection entries = data.get("entries"); + + final boolean isBoundPresent = data.has("bounds"); + + entries.forEach( + entry -> { + final BlockEntry existing = options.get(entry); + if (existing != null) { + if (isBoundPresent) { + // copy bounds from entry into the existing one + entry + .getReadableProperty(BoundProperty.class) + .getAll() + .forEach( + bound -> + existing + .getWritableProperty(BoundProperty.class) + .remove(bound.getMin(), bound.getMax())); + data.markSuccess(); + } else if (options.remove(existing)) { + Helper.printMessage("Removed block \"%s\"", entry.getPrettyName()); + data.markSuccess(); + } + } else if (entries.size() <= 1) { + Helper.printMessage("Failed to remove block \"%s\"", entry.getPrettyName()); + data.markFailed(ExecuteData.State.SUCCESS); + } + }); + }) + .success(cmd -> reloadChunks()) + .build(); } - - /** Initialize the VBO uploaders */ + + /** + * Initialize the VBO uploaders + */ private void vboStartup() { - if (uploaders != null) vboShutdown(); // unload previous if it exists - + if (uploaders != null) { + vboShutdown(); // unload previous if it exists + } + try { // create new instances uploaders = - new Uploaders<>( - RenderUploader::new, - new TessellatorCache<>( - VERTEX_BUFFER_COUNT, () -> new GeometryTessellator(VERTEX_BUFFER_SIZE))); + new Uploaders<>( + RenderUploader::new, + new TessellatorCache<>( + VERTEX_BUFFER_COUNT, () -> new GeometryTessellator(VERTEX_BUFFER_SIZE))); uploaders.onShutdown( - uploader -> - MC.addScheduledTask( - () -> { - uploader.nullifyCurrentThread(); // this will stop anything currently running - - // return the tessellator to cache - try { - uploader.freeTessellator(); - } catch (Throwable t) { - // ignore result - } - - // handle VBO - try { - // attempt to unload the VBO - uploader.unload(); - } catch (Throwable t) { - // ignore result - } - })); + uploader -> + MC.addScheduledTask( + () -> { + uploader.nullifyCurrentThread(); // this will stop anything currently running + + // return the tessellator to cache + try { + uploader.freeTessellator(); + } catch (Throwable t) { + // ignore result + } + + // handle VBO + try { + // attempt to unload the VBO + uploader.unload(); + } catch (Throwable t) { + // ignore result + } + })); } catch (Throwable t) { // ignore result } } - - /** Shutdown the uploaders */ + + /** + * Shutdown the uploaders + */ private void vboShutdown() { try { uploaders.unregisterAll(); @@ -379,53 +401,57 @@ private void vboShutdown() { // ignore result } } - + private final ThreadLocal> localUploader = - new ThreadLocal<>(); - - /** Improve speed by looking up in smaller map */ + new ThreadLocal<>(); + + /** + * Improve speed by looking up in smaller map + */ private Optional> getCurrentRenderUploader( - RenderChunk optional) { - if (uploaders == null) return Optional.empty(); + RenderChunk optional) { + if (uploaders == null) { + return Optional.empty(); + } RenderUploader ru = localUploader.get(); return ru == null ? uploaders.get(optional) : Optional.of(ru); } - + @Override public void onUnload() { options.forEach(BlockEntry::cleanupProperties); options.serialize(); } - + @Override public void onEnabled() { Listeners.BLOCK_MODEL_RENDER_LISTENER.register(this); ForgeHaxHooks.SHOULD_DISABLE_CAVE_CULLING.enable( - "Markers"); // need cave culling disabled to parse every block + "Markers"); // need cave culling disabled to parse every block reloadChunksHard(); } - + @Override public void onDisabled() { vboShutdown(); Listeners.BLOCK_MODEL_RENDER_LISTENER.unregister(this); ForgeHaxHooks.SHOULD_DISABLE_CAVE_CULLING.disable("Markers"); } - + @Override public String getDebugDisplayText() { int cacheSize = uploaders != null ? uploaders.cache().size() : 0; int cacheCapacity = uploaders != null ? uploaders.cache().capacity() : 0; return super.getDebugDisplayText() - + String.format( - " [size = %d/%d | chunks = %d | dummy = %d | bad-region = %d]", - cacheSize, - cacheCapacity, - renderingCount.get(), - dummyCount.get(), - wrongRegionCount.get()); + + String.format( + " [size = %d/%d | chunks = %d | dummy = %d | bad-region = %d]", + cacheSize, + cacheCapacity, + renderingCount.get(), + dummyCount.get(), + wrongRegionCount.get()); } - + @SubscribeEvent public void onWorldUnload(WorldEvent.Load event) { try { @@ -435,380 +461,397 @@ public void onWorldUnload(WorldEvent.Load event) { handleException(e); } } - + @SubscribeEvent public void onLoadRenderers(LoadRenderersEvent event) { try { // create new instances of everything vboStartup(); // allocate all space needed - for (RenderChunk renderChunk : event.getViewFrustum().renderChunks) + for (RenderChunk renderChunk : event.getViewFrustum().renderChunks) { uploaders.register(renderChunk); + } } catch (Throwable t) { handleException(t); } } - + @SubscribeEvent public void onWorldRendererDeallocated(WorldRendererDeallocatedEvent event) { - if (uploaders != null) + if (uploaders != null) { try { uploaders - .get(event.getRenderChunk()) - .ifPresent( - uploader -> { - uploader.lock().lock(); - try { - uploader.freeTessellator(); - } catch (Throwable t) { - handleException(event.getRenderChunk(), t); - } finally { - uploader.lock().unlock(); - } - }); + .get(event.getRenderChunk()) + .ifPresent( + uploader -> { + uploader.lock().lock(); + try { + uploader.freeTessellator(); + } catch (Throwable t) { + handleException(event.getRenderChunk(), t); + } finally { + uploader.lock().unlock(); + } + }); } catch (Throwable t) { // ignore } + } } - + @SubscribeEvent public void onPreBuildChunk(BuildChunkEvent.Pre event) { - if (uploaders != null) + if (uploaders != null) { try { uploaders - .get(event.getRenderChunk()) - .ifPresent( - uploader -> { - uploader.lock().lock(); - try { - localUploader.set(uploader); - uploader.setCurrentThread(); // set this to the current thread, stopping other - // threads processing this same chunk from continuing - uploader.setComplete( - false); // sometimes a chunk will still be uploaded, but will be old data. - // in that case we dont want to draw but still what the uploaded - // field to be true so that it can be cleaned up - - // check if a tessellator already exists, if so then this chunk is being - // processed on another thread and we should stop it - if (uploader.getTessellator() != null) uploader.freeTessellator(); - // now take a new tessellator - uploader.takeTessellator(); - - // begin drawing - uploader.getTessellator().beginLines(); - // reset render count - uploader.resetRenderCount(); - // translate buffer - BlockPos renderPos = event.getRenderChunk().getPosition(); - uploader - .getTessellator() - .setTranslation(-renderPos.getX(), -renderPos.getY(), -renderPos.getZ()); - } catch (Throwable t) { - handleException(event.getRenderChunk(), t); - } finally { - uploader.lock().unlock(); - } - }); + .get(event.getRenderChunk()) + .ifPresent( + uploader -> { + uploader.lock().lock(); + try { + localUploader.set(uploader); + uploader.setCurrentThread(); // set this to the current thread, stopping other + // threads processing this same chunk from continuing + uploader.setComplete( + false); // sometimes a chunk will still be uploaded, but will be old data. + // in that case we dont want to draw but still what the uploaded + // field to be true so that it can be cleaned up + + // check if a tessellator already exists, if so then this chunk is being + // processed on another thread and we should stop it + if (uploader.getTessellator() != null) { + uploader.freeTessellator(); + } + // now take a new tessellator + uploader.takeTessellator(); + + // begin drawing + uploader.getTessellator().beginLines(); + // reset render count + uploader.resetRenderCount(); + // translate buffer + BlockPos renderPos = event.getRenderChunk().getPosition(); + uploader + .getTessellator() + .setTranslation(-renderPos.getX(), -renderPos.getY(), -renderPos.getZ()); + } catch (Throwable t) { + handleException(event.getRenderChunk(), t); + } finally { + uploader.lock().unlock(); + } + }); } catch (Throwable t) { // ignore } + } } - + @SubscribeEvent public void onPostBuildChunk(BuildChunkEvent.Post event) { - if (uploaders != null) + if (uploaders != null) { try { getCurrentRenderUploader(event.getRenderChunk()) - .ifPresent( - uploader -> { - uploader.lock().lock(); - try { - // ensure we are in the right thread - uploader.validateCurrentThread(); - // finish drawing - uploader.finishDrawing(); - } catch (RenderUploader.ThreadMismatchException e) { - // ignore - } catch (Throwable t) { - handleException(event.getRenderChunk(), t); - } finally { - localUploader.remove(); - uploader.lock().unlock(); - } - }); + .ifPresent( + uploader -> { + uploader.lock().lock(); + try { + // ensure we are in the right thread + uploader.validateCurrentThread(); + // finish drawing + uploader.finishDrawing(); + } catch (RenderUploader.ThreadMismatchException e) { + // ignore + } catch (Throwable t) { + handleException(event.getRenderChunk(), t); + } finally { + localUploader.remove(); + uploader.lock().unlock(); + } + }); } catch (Throwable t) { // ignore } + } } - + @Override public void onBlockRenderInLoop( - final RenderChunk renderChunk, - final Block block, - final IBlockState state, - final BlockPos pos) { - if (uploaders != null) + final RenderChunk renderChunk, + final Block block, + final IBlockState state, + final BlockPos pos) { + if (uploaders != null) { try { getCurrentRenderUploader(renderChunk) - .ifPresent( - uploader -> { - uploader.lock().lock(); - try { - uploader.validateCurrentThread(); - if (uploader.isTessellatorDrawing()) { - BlockEntry blockEntry = options.get(state); - if (blockEntry != null - && blockEntry - .getReadableProperty(BoundProperty.class) - .isWithinBoundaries(pos.getY())) { - AxisAlignedBB bb = state.getSelectedBoundingBox(Helper.getWorld(), pos); - GeometryTessellator.drawLines( - uploader.getBufferBuilder(), - bb.minX, - bb.minY, - bb.minZ, - bb.maxX, - bb.maxY, - bb.maxZ, - GeometryMasks.Line.ALL, - blockEntry.getReadableProperty(ColorProperty.class).getAsBuffer()); - } - } - } catch (RenderUploader.ThreadMismatchException e) { - // ignore - } catch (Throwable t) { - handleException(renderChunk, t); - } finally { - uploader.lock().unlock(); + .ifPresent( + uploader -> { + uploader.lock().lock(); + try { + uploader.validateCurrentThread(); + if (uploader.isTessellatorDrawing()) { + BlockEntry blockEntry = options.get(state); + if (blockEntry != null + && blockEntry + .getReadableProperty(BoundProperty.class) + .isWithinBoundaries(pos.getY())) { + AxisAlignedBB bb = state.getSelectedBoundingBox(Helper.getWorld(), pos); + GeometryTessellator.drawLines( + uploader.getBufferBuilder(), + bb.minX, + bb.minY, + bb.minZ, + bb.maxX, + bb.maxY, + bb.maxZ, + GeometryMasks.Line.ALL, + blockEntry.getReadableProperty(ColorProperty.class).getAsBuffer()); } - }); + } + } catch (RenderUploader.ThreadMismatchException e) { + // ignore + } catch (Throwable t) { + handleException(renderChunk, t); + } finally { + uploader.lock().unlock(); + } + }); } catch (Throwable t) { // ignore } + } } - + @SubscribeEvent public void onChunkUploaded(ChunkUploadedEvent event) { - if (uploaders != null) + if (uploaders != null) { try { uploaders - .get(event.getRenderChunk()) - .ifPresent( - uploader -> { - try { - if (uploader.upload()) event.getRenderChunk().setNeedsUpdate(false); - - uploader.setRegion(event.getRenderChunk()); - } catch (Throwable t) { - handleException(event.getRenderChunk(), t); - } - }); + .get(event.getRenderChunk()) + .ifPresent( + uploader -> { + try { + if (uploader.upload()) { + event.getRenderChunk().setNeedsUpdate(false); + } + + uploader.setRegion(event.getRenderChunk()); + } catch (Throwable t) { + handleException(event.getRenderChunk(), t); + } + }); } catch (Throwable t) { // ignore } + } } - + @SubscribeEvent public void onChunkDeleted(DeleteGlResourcesEvent event) { - if (uploaders != null) + if (uploaders != null) { try { uploaders - .get(event.getRenderChunk()) - .ifPresent( - uploader -> - MC.addScheduledTask( - () -> { - try { - uploader.unload(); - } catch (Throwable t) { - handleException(event.getRenderChunk(), t); - } - })); + .get(event.getRenderChunk()) + .ifPresent( + uploader -> + MC.addScheduledTask( + () -> { + try { + uploader.unload(); + } catch (Throwable t) { + handleException(event.getRenderChunk(), t); + } + })); } catch (Throwable t) { // ignore } + } } - + @SubscribeEvent(priority = EventPriority.LOWEST) public void onRenderWorld(RenderEvent event) { - if (uploaders != null && MC.getRenderViewEntity() != null) + if (uploaders != null && MC.getRenderViewEntity() != null) { try { renderingOffset = - EntityUtils.getInterpolatedPos(MC.getRenderViewEntity(), MC.getRenderPartialTicks()); - + EntityUtils.getInterpolatedPos(MC.getRenderViewEntity(), MC.getRenderPartialTicks()); + GlStateManager.pushMatrix(); GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); GlStateManager.disableAlpha(); GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); GlStateManager.shadeModel(GL11.GL_SMOOTH); - if (!clear_buffer.get()) GlStateManager.disableDepth(); - else { + if (!clear_buffer.get()) { + GlStateManager.disableDepth(); + } else { GlStateManager.clearDepth(1.f); GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); } - + final boolean debug_mode = debug.get(); final List chunks = Lists.newArrayList(); - + final boolean aa_enabled = anti_aliasing.get(); final int aa_max = anti_aliasing_max.get(); - + renderingCount.set(0); dummyCount.set(0); wrongRegionCount.set(0); - + GlStateManager.glEnableClientState(GL11.GL_VERTEX_ARRAY); GlStateManager.glEnableClientState(GL11.GL_COLOR_ARRAY); - + uploaders.forEach( - (k, v) -> { - if (v.isUploaded() - /*&& !Uploaders.isDummy(k)*/ - && v.isCorrectRegion(k)) { - if (aa_enabled && (aa_max == 0 || v.getRenderCount() <= aa_max)) - GL11.glEnable(GL11.GL_LINE_SMOOTH); - - GlStateManager.pushMatrix(); - - BlockPos pos = k.getPosition(); - GlStateManager.translate( - (double) pos.getX() - renderingOffset.x, - (double) pos.getY() - renderingOffset.y, - (double) pos.getZ() - renderingOffset.z); - - k.multModelviewMatrix(); - - v.getVertexBuffer().bindBuffer(); - - GlStateManager.glVertexPointer( - DefaultVertexFormats.POSITION_3F.getElementCount(), - DefaultVertexFormats.POSITION_3F.getType().getGlConstant(), - DefaultVertexFormats.POSITION_3F.getSize() - + DefaultVertexFormats.COLOR_4UB.getSize(), - 0); - GlStateManager.glColorPointer( - DefaultVertexFormats.COLOR_4UB.getElementCount(), - DefaultVertexFormats.COLOR_4UB.getType().getGlConstant(), - DefaultVertexFormats.POSITION_3F.getSize() - + DefaultVertexFormats.COLOR_4UB.getSize(), - DefaultVertexFormats.POSITION_3F.getSize()); - - v.getVertexBuffer().drawArrays(GL11.GL_LINES); - - GlStateManager.popMatrix(); - - GL11.glDisable(GL11.GL_LINE_SMOOTH); - - renderingCount.incrementAndGet(); - } else if (v.isUploaded() && Uploaders.isDummy(k)) { - dummyCount.incrementAndGet(); - } else if (v.isUploaded() && !v.isCorrectRegion(k)) { - wrongRegionCount.incrementAndGet(); - if (debug_mode) chunks.add(k.getPosition()); + (k, v) -> { + if (v.isUploaded() + /*&& !Uploaders.isDummy(k)*/ + && v.isCorrectRegion(k)) { + if (aa_enabled && (aa_max == 0 || v.getRenderCount() <= aa_max)) { + GL11.glEnable(GL11.GL_LINE_SMOOTH); } - }); - + + GlStateManager.pushMatrix(); + + BlockPos pos = k.getPosition(); + GlStateManager.translate( + (double) pos.getX() - renderingOffset.x, + (double) pos.getY() - renderingOffset.y, + (double) pos.getZ() - renderingOffset.z); + + k.multModelviewMatrix(); + + v.getVertexBuffer().bindBuffer(); + + GlStateManager.glVertexPointer( + DefaultVertexFormats.POSITION_3F.getElementCount(), + DefaultVertexFormats.POSITION_3F.getType().getGlConstant(), + DefaultVertexFormats.POSITION_3F.getSize() + + DefaultVertexFormats.COLOR_4UB.getSize(), + 0); + GlStateManager.glColorPointer( + DefaultVertexFormats.COLOR_4UB.getElementCount(), + DefaultVertexFormats.COLOR_4UB.getType().getGlConstant(), + DefaultVertexFormats.POSITION_3F.getSize() + + DefaultVertexFormats.COLOR_4UB.getSize(), + DefaultVertexFormats.POSITION_3F.getSize()); + + v.getVertexBuffer().drawArrays(GL11.GL_LINES); + + GlStateManager.popMatrix(); + + GL11.glDisable(GL11.GL_LINE_SMOOTH); + + renderingCount.incrementAndGet(); + } else if (v.isUploaded() && Uploaders.isDummy(k)) { + dummyCount.incrementAndGet(); + } else if (v.isUploaded() && !v.isCorrectRegion(k)) { + wrongRegionCount.incrementAndGet(); + if (debug_mode) { + chunks.add(k.getPosition()); + } + } + }); + GL11.glDisable(GL11.GL_LINE_SMOOTH); - + GlStateManager.glDisableClientState(GL11.GL_VERTEX_ARRAY); GlStateManager.glDisableClientState(GL11.GL_COLOR_ARRAY); - + OpenGlHelper.glBindBuffer(OpenGlHelper.GL_ARRAY_BUFFER, 0); - + // // // - + final Vec3d renderViewPos = MC.getRenderViewEntity().getPositionVector(); - + if (show_entities.get()) { // draw markers around entities that have blocks inside them GlStateManager.pushMatrix(); - + final GeometryTessellator tessellator = event.getTessellator(); final BufferBuilder builder = tessellator.getBuffer(); - + tessellator.beginLines(); tessellator.setTranslation(0, 0, 0); - - if (aa_enabled) GL11.glEnable(GL11.GL_LINE_SMOOTH); - + + if (aa_enabled) { + GL11.glEnable(GL11.GL_LINE_SMOOTH); + } + getWorld() - .loadedEntityList - .stream() - .map(BlockHolder::new) - .filter(BlockHolder::nonNull) - .forEach( - o -> - options - .stream() - .filter(entry -> Objects.equals(o.getBlock(), entry.getBlock())) - .findFirst() - .ifPresent( - entry -> { - Entity e = o.getEntity(); - Vec3d rp = - EntityUtils.getInterpolatedAmount(e, event.getPartialTicks()) - .subtract(event.getRenderPos()); - builder.setTranslation(rp.x, rp.y, rp.z); - AxisAlignedBB bb = o.getBoundingBox(); - GeometryTessellator.drawLines( - builder, - bb.minX, - bb.minY, - bb.minZ, - bb.maxX, - bb.maxY, - bb.maxZ, - GeometryMasks.Line.ALL, - entry.getReadableProperty(ColorProperty.class).getAsBuffer()); - })); - + .loadedEntityList + .stream() + .map(BlockHolder::new) + .filter(BlockHolder::nonNull) + .forEach( + o -> + options + .stream() + .filter(entry -> Objects.equals(o.getBlock(), entry.getBlock())) + .findFirst() + .ifPresent( + entry -> { + Entity e = o.getEntity(); + Vec3d rp = + EntityUtils.getInterpolatedAmount(e, event.getPartialTicks()) + .subtract(event.getRenderPos()); + builder.setTranslation(rp.x, rp.y, rp.z); + AxisAlignedBB bb = o.getBoundingBox(); + GeometryTessellator.drawLines( + builder, + bb.minX, + bb.minY, + bb.minZ, + bb.maxX, + bb.maxY, + bb.maxZ, + GeometryMasks.Line.ALL, + entry.getReadableProperty(ColorProperty.class).getAsBuffer()); + })); + tessellator.draw(); tessellator.setTranslation(0, 0, 0); - + GL11.glDisable(GL11.GL_LINE_SMOOTH); GlStateManager.popMatrix(); } - + // // // - + if (debug_mode) { GlStateManager.pushMatrix(); - + final GeometryTessellator tessellator = event.getTessellator(); final BufferBuilder builder = tessellator.getBuffer(); - + tessellator.beginLines(); - + chunks.forEach( - pos -> { - Vec3d rp = new Vec3d(pos).subtract(event.getRenderPos()); - builder.setTranslation(rp.x, rp.y, rp.z); - - GeometryTessellator.drawLines( - builder, - 0.8, - 0.8, - 0.8, - 16.f - 0.16, - 16.f - 0.16, - 16.f - 0.16, - GeometryMasks.Line.ALL, - Utils.Colors.RED); - }); - + pos -> { + Vec3d rp = new Vec3d(pos).subtract(event.getRenderPos()); + builder.setTranslation(rp.x, rp.y, rp.z); + + GeometryTessellator.drawLines( + builder, + 0.8, + 0.8, + 0.8, + 16.f - 0.16, + 16.f - 0.16, + 16.f - 0.16, + GeometryMasks.Line.ALL, + Colors.RED.toBuffer()); + }); + tessellator.draw(); - + GlStateManager.popMatrix(); - + builder.setTranslation(0, 0, 0); } - + GlStateManager.shadeModel(GL11.GL_FLAT); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); @@ -819,26 +862,28 @@ public void onRenderWorld(RenderEvent event) { } catch (Throwable t) { // ignore } + } } - + private static void handleException(RenderChunk renderChunk, Throwable t) { // throwable.printStackTrace(); Helper.getLog().error(t.toString()); t.printStackTrace(); } - + private static void handleException(Throwable t) { handleException(null, t); } - + static class BlockHolder { + final Entity entity; final Block block; final AxisAlignedBB boundingBox; - + BlockHolder(Entity entity) { this.entity = entity; - + if (entity instanceof EntityMinecart) { EntityMinecart ent = (EntityMinecart) entity; this.block = ent.getDefaultDisplayTile().getBlock(); @@ -852,19 +897,19 @@ static class BlockHolder { this.boundingBox = null; } } - + public boolean nonNull() { return block != null; } - + public Entity getEntity() { return entity; } - + public Block getBlock() { return block; } - + public AxisAlignedBB getBoundingBox() { return boundingBox; } diff --git a/src/main/java/com/matt/forgehax/mods/MatrixNotifications.java b/src/main/java/com/matt/forgehax/mods/MatrixNotifications.java index 03c2ddd62..f79826c63 100644 --- a/src/main/java/com/matt/forgehax/mods/MatrixNotifications.java +++ b/src/main/java/com/matt/forgehax/mods/MatrixNotifications.java @@ -1,7 +1,6 @@ package com.matt.forgehax.mods; import static com.matt.forgehax.Helper.getLocalPlayer; -import static com.matt.forgehax.Helper.getWorld; import static com.matt.forgehax.Helper.printError; import static com.matt.forgehax.asm.reflection.FastReflection.Fields.GuiDisconnected_message; @@ -16,25 +15,19 @@ import com.matt.forgehax.util.mod.loader.RegisterMod; import com.mojang.authlib.GameProfile; import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; import net.minecraft.client.gui.GuiDisconnected; import net.minecraft.network.play.server.SPacketChat; import net.minecraft.util.math.BlockPos; @@ -43,34 +36,28 @@ import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent; -import org.apache.http.HttpHost; import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpPost; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; -import org.apache.http.conn.ssl.AllowAllHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContextBuilder; import org.apache.http.conn.ssl.SSLContexts; -import org.apache.http.conn.ssl.TrustSelfSignedStrategy; -import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; -import org.apache.http.protocol.HttpContext; import sun.security.validator.ValidatorException; @RegisterMod public class MatrixNotifications extends ToggleMod { + private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor(); - + static { Runtime.getRuntime().addShutdownHook(new Thread(() -> { EXECUTOR.shutdown(); @@ -83,15 +70,17 @@ public class MatrixNotifications extends ToggleMod { } })); } + private static final Registry SOCKET_FACTORY_REGISTRY; - + static { Registry sf = null; try { SSLContextBuilder builder = SSLContexts.custom(); builder.loadTrustMaterial(null, (chain, authType) -> true); SSLContext sslContext = builder.build(); - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new AllowAllHostsVerifier()); + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, + new AllowAllHostsVerifier()); sf = RegistryBuilder.create().register("https", sslsf).build(); } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { e.printStackTrace(); @@ -99,99 +88,100 @@ public class MatrixNotifications extends ToggleMod { SOCKET_FACTORY_REGISTRY = sf; } } - + private final Setting url = - getCommandStub() - .builders() - .newSettingBuilder() - .name("url") - .description("URL to the Matrix web hook") - .defaultTo("") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("url") + .description("URL to the Matrix web hook") + .defaultTo("") + .build(); + private final Setting user = - getCommandStub() - .builders() - .newSettingBuilder() - .name("user") - .description("User to ping for high priority messages") - .defaultTo("") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("user") + .description("User to ping for high priority messages") + .defaultTo("") + .build(); + private final Setting skin_server_url = - getCommandStub() - .builders() - .newSettingBuilder() - .name("skin-server-url") - .description("URL to the skin server. If left empty then no image will be used.") - .defaultTo("https://visage.surgeplay.com/face/160/") - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("skin-server-url") + .description("URL to the skin server. If left empty then no image will be used.") + .defaultTo("https://visage.surgeplay.com/face/160/") + .build(); + private final Setting queue_notify_pos = - getCommandStub() - .builders() - .newSettingBuilder() - .name("queue-notify-pos") - .description("Position to start sending notifications at") - .defaultTo(5) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("queue-notify-pos") + .description("Position to start sending notifications at") + .defaultTo(5) + .build(); + private final Setting on_connected = - getCommandStub() - .builders() - .newSettingBuilder() - .name("on-connected") - .description("Message on connected to server") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("on-connected") + .description("Message on connected to server") + .defaultTo(true) + .build(); + private final Setting on_disconnected = - getCommandStub() - .builders() - .newSettingBuilder() - .name("on-disconnected") - .description("Message on disconnected from server") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("on-disconnected") + .description("Message on disconnected from server") + .defaultTo(true) + .build(); + private final Setting on_queue_move = - getCommandStub() - .builders() - .newSettingBuilder() - .name("on-queue-move") - .description("Message when player moves in the queue") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("on-queue-move") + .description("Message when player moves in the queue") + .defaultTo(true) + .build(); + public MatrixNotifications() { super(Category.MISC, "MatrixNotifications", false, "Matrix notifications"); } - + private boolean joined = false; private boolean once = false; private int position = 0; private String serverName = null; - + private static CloseableHttpClient createHttpClient() { final RequestConfig req = RequestConfig.custom() - .setConnectTimeout(30 * 1000) - .setConnectionRequestTimeout(30 * 1000) - .build(); - - if(SOCKET_FACTORY_REGISTRY == null) + .setConnectTimeout(30 * 1000) + .setConnectionRequestTimeout(30 * 1000) + .build(); + + if (SOCKET_FACTORY_REGISTRY == null) { return HttpClientBuilder.create() - .setDefaultRequestConfig(req) - .build(); - else + .setDefaultRequestConfig(req) + .build(); + } else { return HttpClients.custom() - .setDefaultRequestConfig(req) - .setConnectionManager(new PoolingHttpClientConnectionManager(SOCKET_FACTORY_REGISTRY)) - .build(); + .setDefaultRequestConfig(req) + .setConnectionManager(new PoolingHttpClientConnectionManager(SOCKET_FACTORY_REGISTRY)) + .build(); + } } - + private static HttpResponse post(final String url, final JsonElement json) throws IOException { final Gson gson = new Gson(); - try(CloseableHttpClient client = createHttpClient()) { + try (CloseableHttpClient client = createHttpClient()) { final HttpPost post = new HttpPost(url); StringEntity entity = new StringEntity(gson.toJson(json)); post.setEntity(entity); @@ -199,121 +189,130 @@ private static HttpResponse post(final String url, final JsonElement json) throw return client.execute(post); } } - + private static void postAsync(final String url, final JsonElement json) { EXECUTOR.submit(() -> { try { HttpResponse res = post(url, json); - if(res.getStatusLine().getStatusCode() != 200) + if (res.getStatusLine().getStatusCode() != 200) { throw new Error("got response code " + res.getStatusLine().getStatusCode()); + } } catch (Throwable t) { - if(t.getCause() instanceof ValidatorException) + if (t.getCause() instanceof ValidatorException) { printError("Java JRE outdated. Change games to use the latest JRE."); - else + } else { printError("Failed to send message to url: " + t.getMessage()); + } t.printStackTrace(); } }); } - + private static String getServerName() { return Optional.ofNullable(MC.getCurrentServerData()) - .map(data -> data.serverName) - .orElse("server"); + .map(data -> data.serverName) + .orElse("server"); } - + private static String getUriUuid() { return Optional.of(MC.getSession().getProfile()) - .map(GameProfile::getId) - .map(UUID::toString) - .map(id -> id.replaceAll("-", "")) - .orElse(null); + .map(GameProfile::getId) + .map(UUID::toString) + .map(id -> id.replaceAll("-", "")) + .orElse(null); } - + private void notify(String message) { JsonObject object = new JsonObject(); object.addProperty("text", message); object.addProperty("format", "plain"); object.addProperty("displayName", MC.getSession().getUsername()); - + String id = getUriUuid(); - if(!skin_server_url.get().isEmpty() && id != null) + if (!skin_server_url.get().isEmpty() && id != null) { object.addProperty("avatarUrl", skin_server_url.get() + id); - + } + postAsync(url.get(), object); } - + private void notify(String message, Object... args) { notify(String.format(message, args)); } - + private void ping(String message, Object... args) { String msg = String.format(message, args); - if(user.get().isEmpty()) + if (user.get().isEmpty()) { notify(msg); - else + } else { notify("@" + user.get() + " " + msg); + } } - + @Override protected void onEnabled() { joined = once = false; position = 0; - - if(url.get().isEmpty()) + + if (url.get().isEmpty()) { printError("Missing url"); - - if(SOCKET_FACTORY_REGISTRY == null) { - printError("Custom socket factory has not been registered. All host SSL certificates must be trusted with the current JRE"); + } + + if (SOCKET_FACTORY_REGISTRY == null) { + printError( + "Custom socket factory has not been registered. All host SSL certificates must be trusted with the current JRE"); } } - + @SubscribeEvent public void onTick(LocalPlayerUpdateEvent event) { joined = true; - - if(!once) { + + if (!once) { once = true; - - if(on_connected.get()) { + + if (on_connected.get()) { BlockPos pos = getLocalPlayer().getPosition(); - if (pos.getX() != 0 && pos.getZ() != 0) + if (pos.getX() != 0 && pos.getZ() != 0) { ping("Connected to %s", getServerName()); - else + } else { notify("Connected to %s queue", getServerName()); + } } } } - + @SubscribeEvent public void onWorldUnload(WorldEvent.Unload event) { once = false; position = 0; - - if(MC.getCurrentServerData() != null) + + if (MC.getCurrentServerData() != null) { serverName = getServerName(); + } } - + @SubscribeEvent public void onGuiOpened(GuiOpenEvent event) { - if(event.getGui() instanceof GuiDisconnected && joined) { + if (event.getGui() instanceof GuiDisconnected && joined) { joined = false; - - if(on_disconnected.get()) { + + if (on_disconnected.get()) { String reason = Optional.ofNullable(GuiDisconnected_message.get(event.getGui())) - .map(ITextComponent::getUnformattedText) - .orElse(""); - if(reason.isEmpty()) + .map(ITextComponent::getUnformattedText) + .orElse(""); + if (reason.isEmpty()) { notify("Disconnected from %s", serverName); - else + } else { notify("Disconnected from %s. Reason: %s", serverName, reason); + } } } } - + @SubscribeEvent public void onPacketRecieve(PacketEvent.Incoming.Pre event) { - if(event.getPacket() instanceof SPacketChat) { + if (event.getPacket() instanceof SPacketChat) { SPacketChat packet = event.getPacket(); if (packet.getType() == ChatType.SYSTEM) { ITextComponent comp = packet.getChatComponent(); @@ -324,11 +323,12 @@ public void onPacketRecieve(PacketEvent.Incoming.Pre event) { int pos = Integer.valueOf(comp.getSiblings().get(1).getUnformattedText()); if (pos != position) { position = pos; - if(on_queue_move.get() && position <= queue_notify_pos.get()) { - if(position == 1) + if (on_queue_move.get() && position <= queue_notify_pos.get()) { + if (position == 1) { ping("Position 1 in queue"); - else + } else { notify("Position %d in queue", position); + } } } } catch (Throwable t) { @@ -339,17 +339,21 @@ public void onPacketRecieve(PacketEvent.Incoming.Pre event) { } } } - + private static class AllowAllHostsVerifier implements X509HostnameVerifier { + @Override - public void verify(String host, SSLSocket ssl) throws IOException {} - + public void verify(String host, SSLSocket ssl) throws IOException { + } + @Override - public void verify(String host, X509Certificate cert) throws SSLException {} - + public void verify(String host, X509Certificate cert) throws SSLException { + } + @Override - public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {} - + public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException { + } + @Override public boolean verify(String s, SSLSession sslSession) { return true; diff --git a/src/main/java/com/matt/forgehax/mods/NoCaveCulling.java b/src/main/java/com/matt/forgehax/mods/NoCaveCulling.java index 6ad4e1c9f..4570dd256 100644 --- a/src/main/java/com/matt/forgehax/mods/NoCaveCulling.java +++ b/src/main/java/com/matt/forgehax/mods/NoCaveCulling.java @@ -7,15 +7,16 @@ @RegisterMod public class NoCaveCulling extends ToggleMod { + public NoCaveCulling() { super(Category.RENDER, "NoCaveCulling", false, "Disables mojangs dumb cave culling shit"); } - + @Override public void onEnabled() { ForgeHaxHooks.SHOULD_DISABLE_CAVE_CULLING.enable("NoCaveCulling"); } - + @Override public void onDisabled() { ForgeHaxHooks.SHOULD_DISABLE_CAVE_CULLING.disable("NoCaveCulling"); diff --git a/src/main/java/com/matt/forgehax/mods/NoFallMod.java b/src/main/java/com/matt/forgehax/mods/NoFallMod.java index 5bce21e76..4f3e9031f 100644 --- a/src/main/java/com/matt/forgehax/mods/NoFallMod.java +++ b/src/main/java/com/matt/forgehax/mods/NoFallMod.java @@ -14,35 +14,36 @@ @RegisterMod public class NoFallMod extends ToggleMod { + public NoFallMod() { super(Category.PLAYER, "NoFall", false, "Prevents fall damage from being taken"); } - + private float lastFallDistance = 0; - + @SubscribeEvent public void onPacketSend(PacketEvent.Outgoing.Pre event) { if (event.getPacket() instanceof CPacketPlayer - && !(event.getPacket() instanceof CPacketPlayer.Rotation) - && !PacketHelper.isIgnored(event.getPacket())) { + && !(event.getPacket() instanceof CPacketPlayer.Rotation) + && !PacketHelper.isIgnored(event.getPacket())) { CPacketPlayer packetPlayer = (CPacketPlayer) event.getPacket(); if (FastReflection.Fields.CPacketPlayer_onGround.get(packetPlayer) && lastFallDistance >= 4) { CPacketPlayer packet = - new CPacketPlayer.PositionRotation( - ((CPacketPlayer) event.getPacket()).getX(0), - 1337 + ((CPacketPlayer) event.getPacket()).getY(0), - ((CPacketPlayer) event.getPacket()).getZ(0), - ((CPacketPlayer) event.getPacket()).getYaw(0), - ((CPacketPlayer) event.getPacket()).getPitch(0), - true); + new CPacketPlayer.PositionRotation( + ((CPacketPlayer) event.getPacket()).getX(0), + 1337 + ((CPacketPlayer) event.getPacket()).getY(0), + ((CPacketPlayer) event.getPacket()).getZ(0), + ((CPacketPlayer) event.getPacket()).getYaw(0), + ((CPacketPlayer) event.getPacket()).getPitch(0), + true); CPacketPlayer reposition = - new CPacketPlayer.PositionRotation( - ((CPacketPlayer) event.getPacket()).getX(0), - ((CPacketPlayer) event.getPacket()).getY(0), - ((CPacketPlayer) event.getPacket()).getZ(0), - ((CPacketPlayer) event.getPacket()).getYaw(0), - ((CPacketPlayer) event.getPacket()).getPitch(0), - true); + new CPacketPlayer.PositionRotation( + ((CPacketPlayer) event.getPacket()).getX(0), + ((CPacketPlayer) event.getPacket()).getY(0), + ((CPacketPlayer) event.getPacket()).getZ(0), + ((CPacketPlayer) event.getPacket()).getYaw(0), + ((CPacketPlayer) event.getPacket()).getPitch(0), + true); PacketHelper.ignore(packet); PacketHelper.ignore(reposition); getNetworkManager().sendPacket(packet); diff --git a/src/main/java/com/matt/forgehax/mods/NoRender.java b/src/main/java/com/matt/forgehax/mods/NoRender.java index 7b2b0966e..7ec346a99 100644 --- a/src/main/java/com/matt/forgehax/mods/NoRender.java +++ b/src/main/java/com/matt/forgehax/mods/NoRender.java @@ -1,5 +1,8 @@ package com.matt.forgehax.mods; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getWorld; + import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; @@ -9,27 +12,27 @@ import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; -import static com.matt.forgehax.Helper.getLocalPlayer; -import static com.matt.forgehax.Helper.getWorld; - @RegisterMod public class NoRender extends ToggleMod { - - public NoRender() { - super(Category.RENDER, "NoRender", false, "Stops rendering items on ground"); + + public NoRender() { + super(Category.RENDER, "NoRender", false, "Stops rendering items on ground"); + } + + @SubscribeEvent + public void onClientTick(ClientTickEvent event) { + if (getWorld() == null || getLocalPlayer() == null) { + return; } - - @SubscribeEvent - public void onClientTick(ClientTickEvent event) { - if (getWorld() == null || getLocalPlayer() == null) return; - - if(event.phase == TickEvent.Phase.START) - getWorld() - .loadedEntityList - .stream() - .filter(EntityItem.class::isInstance) - .map(EntityItem.class::cast) - .forEach(Entity::setDead); + + if (event.phase == TickEvent.Phase.START) { + getWorld() + .loadedEntityList + .stream() + .filter(EntityItem.class::isInstance) + .map(EntityItem.class::cast) + .forEach(Entity::setDead); } + } } diff --git a/src/main/java/com/matt/forgehax/mods/NoRotate.java b/src/main/java/com/matt/forgehax/mods/NoRotate.java index 1f8286f3c..9c3394f8b 100644 --- a/src/main/java/com/matt/forgehax/mods/NoRotate.java +++ b/src/main/java/com/matt/forgehax/mods/NoRotate.java @@ -10,19 +10,21 @@ @RegisterMod public class NoRotate extends ToggleMod { + public NoRotate() { super(Category.PLAYER, "NoRotate", false, "dont let server set pitch and yaw"); } - + @SubscribeEvent public void onPacketRecieved(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketPlayerPosLook) { SPacketPlayerPosLook packet = (SPacketPlayerPosLook) event.getPacket(); - if (MC.player != null) + if (MC.player != null) { if (MC.player.rotationYaw != -180 && MC.player.rotationPitch != 0) { FastReflection.Fields.SPacketPlayer_yaw.set(packet, MC.player.rotationYaw); FastReflection.Fields.SPacketPlayer_pitch.set(packet, MC.player.rotationPitch); } + } } } } diff --git a/src/main/java/com/matt/forgehax/mods/NoSkylightUpdates.java b/src/main/java/com/matt/forgehax/mods/NoSkylightUpdates.java index 1c145f44a..58267b831 100644 --- a/src/main/java/com/matt/forgehax/mods/NoSkylightUpdates.java +++ b/src/main/java/com/matt/forgehax/mods/NoSkylightUpdates.java @@ -7,15 +7,20 @@ import net.minecraft.world.EnumSkyBlock; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 2/10/2018 by fr1kin */ +/** + * Created on 2/10/2018 by fr1kin + */ @RegisterMod public class NoSkylightUpdates extends ToggleMod { + public NoSkylightUpdates() { super(Category.RENDER, "NoSkylightUpdates", false, "Prevents skylight updates"); } - + @SubscribeEvent public void onLightingUpdate(WorldCheckLightForEvent event) { - if (event.getEnumSkyBlock() == EnumSkyBlock.SKY) event.setCanceled(true); + if (event.getEnumSkyBlock() == EnumSkyBlock.SKY) { + event.setCanceled(true); + } } } diff --git a/src/main/java/com/matt/forgehax/mods/NoSlowdown.java b/src/main/java/com/matt/forgehax/mods/NoSlowdown.java index e4dfd7196..3264192d1 100644 --- a/src/main/java/com/matt/forgehax/mods/NoSlowdown.java +++ b/src/main/java/com/matt/forgehax/mods/NoSlowdown.java @@ -13,10 +13,11 @@ @RegisterMod public class NoSlowdown extends ToggleMod { + public NoSlowdown() { super(Category.PLAYER, "NoSlowDown", false, "Disables block slowdown"); } - + @Override public void onEnabled() { ForgeHaxHooks.isNoSlowDownActivated = true; @@ -25,7 +26,7 @@ public void onEnabled() { } catch (Exception e) { } } - + @Override public void onDisabled() { ForgeHaxHooks.isNoSlowDownActivated = false; @@ -34,7 +35,7 @@ public void onDisabled() { } catch (Exception e) { } } - + @SubscribeEvent public void onDoApplyBlockMovement(DoBlockCollisionsEvent event) { if (event.getEntity().equals(getLocalPlayer())) { diff --git a/src/main/java/com/matt/forgehax/mods/NoSoundLagMod.java b/src/main/java/com/matt/forgehax/mods/NoSoundLagMod.java index ae99a1532..715cd22ef 100644 --- a/src/main/java/com/matt/forgehax/mods/NoSoundLagMod.java +++ b/src/main/java/com/matt/forgehax/mods/NoSoundLagMod.java @@ -5,38 +5,37 @@ import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; +import java.util.Set; import net.minecraft.init.SoundEvents; import net.minecraft.network.play.server.SPacketSoundEffect; import net.minecraft.util.SoundEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import java.util.Set; - @RegisterMod public class NoSoundLagMod extends ToggleMod { - - private static final Set BLACKLIST = Sets.newHashSet( - SoundEvents.ITEM_ARMOR_EQUIP_GENERIC, - SoundEvents.ITEM_ARMOR_EQIIP_ELYTRA, - SoundEvents.ITEM_ARMOR_EQUIP_DIAMOND, - SoundEvents.ITEM_ARMOR_EQUIP_IRON, - SoundEvents.ITEM_ARMOR_EQUIP_GOLD, - SoundEvents.ITEM_ARMOR_EQUIP_CHAIN, - SoundEvents.ITEM_ARMOR_EQUIP_LEATHER - ); - - public NoSoundLagMod() { - super(Category.MISC, "NoSoundLag", false, "lag exploit fix"); - } - - @SubscribeEvent - public void onPacketReceived(PacketEvent.Incoming.Pre event) { - if (event.getPacket() instanceof SPacketSoundEffect) { - SPacketSoundEffect packet = event.getPacket(); - if (BLACKLIST.contains(packet.getSound())) { - event.setCanceled(true); - } - - } + + private static final Set BLACKLIST = Sets.newHashSet( + SoundEvents.ITEM_ARMOR_EQUIP_GENERIC, + SoundEvents.ITEM_ARMOR_EQIIP_ELYTRA, + SoundEvents.ITEM_ARMOR_EQUIP_DIAMOND, + SoundEvents.ITEM_ARMOR_EQUIP_IRON, + SoundEvents.ITEM_ARMOR_EQUIP_GOLD, + SoundEvents.ITEM_ARMOR_EQUIP_CHAIN, + SoundEvents.ITEM_ARMOR_EQUIP_LEATHER + ); + + public NoSoundLagMod() { + super(Category.MISC, "NoSoundLag", false, "lag exploit fix"); + } + + @SubscribeEvent + public void onPacketReceived(PacketEvent.Incoming.Pre event) { + if (event.getPacket() instanceof SPacketSoundEffect) { + SPacketSoundEffect packet = event.getPacket(); + if (BLACKLIST.contains(packet.getSound())) { + event.setCanceled(true); + } + } + } } diff --git a/src/main/java/com/matt/forgehax/mods/NoWeather.java b/src/main/java/com/matt/forgehax/mods/NoWeather.java index 287ca0b78..ca4e8bbf5 100644 --- a/src/main/java/com/matt/forgehax/mods/NoWeather.java +++ b/src/main/java/com/matt/forgehax/mods/NoWeather.java @@ -14,19 +14,21 @@ import net.minecraft.world.biome.Biome; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.TickEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent.Phase; -/** Created on 5/16/2017 by fr1kin */ +/** + * Created on 5/16/2017 by fr1kin + */ @RegisterMod public class NoWeather extends ToggleMod { + private boolean isRaining = false; private float rainStrength = 0.f; private float previousRainStrength = 0.f; - + public NoWeather() { super(Category.WORLD, "NoWeather", false, "Disables weather"); } - + private final Setting showStatus = getCommandStub() .builders() @@ -35,30 +37,32 @@ public NoWeather() { .description("show info about suppressed weather") .defaultTo(true) .build(); - + private void saveState(World world) { - if (world != null) + if (world != null) { setState(world.getWorldInfo().isRaining(), world.rainingStrength, world.prevRainingStrength); - else setState(false, 1.f, 1.f); + } else { + setState(false, 1.f, 1.f); + } } - + private void setState(boolean raining, float rainStrength, float previousRainStrength) { this.isRaining = raining; setState(rainStrength, previousRainStrength); } - + private void setState(float rainStrength, float previousRainStrength) { this.rainStrength = rainStrength; this.previousRainStrength = previousRainStrength; } - + private void disableRain() { if (getWorld() != null) { getWorld().getWorldInfo().setRaining(false); getWorld().setRainStrength(0.f); } } - + public void resetState() { if (getWorld() != null) { getWorld().getWorldInfo().setRaining(isRaining); @@ -66,27 +70,27 @@ public void resetState() { getWorld().prevRainingStrength = previousRainStrength; } } - + @Override public void onEnabled() { saveState(getWorld()); } - + @Override public void onDisabled() { resetState(); } - + @SubscribeEvent public void onWorldChange(WorldChangeEvent event) { saveState(event.getWorld()); } - + @SubscribeEvent public void onWorldTick(TickEvent.ClientTickEvent event) { disableRain(); } - + @SubscribeEvent public void onPacketIncoming(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketChangeGameState) { @@ -112,7 +116,7 @@ public void onPacketIncoming(PacketEvent.Incoming.Pre event) { } } } - + @Override public String getDisplayText() { if (isRaining @@ -120,9 +124,9 @@ public String getDisplayText() { Biome biome = getWorld().getBiome(getLocalPlayer().getPosition()); boolean canRain = biome.canRain(); boolean canSnow = biome.getEnableSnow(); - + String status; - + if (getWorld().isThundering()) { status = "[Thunder]"; } else if (canSnow) { @@ -132,7 +136,7 @@ public String getDisplayText() { } else { status = "[Raining]"; } - + return super.getDisplayText() + status; } else { return super.getDisplayText(); diff --git a/src/main/java/com/matt/forgehax/mods/NoclipMod.java b/src/main/java/com/matt/forgehax/mods/NoclipMod.java index 4e09bfa19..1032043ce 100644 --- a/src/main/java/com/matt/forgehax/mods/NoclipMod.java +++ b/src/main/java/com/matt/forgehax/mods/NoclipMod.java @@ -1,6 +1,6 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getRidingOrPlayer; import com.matt.forgehax.events.LocalPlayerUpdateEvent; import com.matt.forgehax.util.mod.Category; @@ -11,16 +11,19 @@ @RegisterMod public class NoclipMod extends ToggleMod { + public NoclipMod() { super(Category.PLAYER, "Noclip", false, "Enables player noclip"); } - + @Override public void onDisabled() { Entity local = getRidingOrPlayer(); - if (local != null) local.noClip = false; + if (local != null) { + local.noClip = false; + } } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { Entity local = getRidingOrPlayer(); diff --git a/src/main/java/com/matt/forgehax/mods/Nuker.java b/src/main/java/com/matt/forgehax/mods/Nuker.java index 4e50db67c..caa05165e 100644 --- a/src/main/java/com/matt/forgehax/mods/Nuker.java +++ b/src/main/java/com/matt/forgehax/mods/Nuker.java @@ -48,176 +48,183 @@ @RegisterMod public class Nuker extends ToggleMod implements PositionRotationManager.MovementUpdateListener { + private final KeyBinding bindSelect = new KeyBinding("Nuker Selection", -98, "ForgeHax"); - + private final List targets = Lists.newArrayList(); private final AtomicBoolean attackToggle = new AtomicBoolean(false); - + private BlockPos currentTarget = null; - + private final Setting client_angles = - getCommandStub() - .builders() - .newSettingBuilder() - .name("client-angles") - .description("Sort the blocks to break by the clients angle instead of the servers") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("client-angles") + .description("Sort the blocks to break by the clients angle instead of the servers") + .defaultTo(false) + .build(); + private final Setting bounded = - getCommandStub() - .builders() - .newSettingBuilder() - .name("bounded") - .description("Bound the nuker to a limited radius from the player") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("bounded") + .description("Bound the nuker to a limited radius from the player") + .defaultTo(false) + .build(); + private final Setting height_upper = - getCommandStub() - .builders() - .newSettingBuilder() - .name("height-upper") - .description("Upper height (Y axis) limit") - .defaultTo(10.D) - .min(0.D) - .max(10.D) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("height-upper") + .description("Upper height (Y axis) limit") + .defaultTo(10.D) + .min(0.D) + .max(10.D) + .build(); private final Setting height_lower = - getCommandStub() - .builders() - .newSettingBuilder() - .name("height-lower") - .description("Lower height (Y axis) limit") - .defaultTo(10.D) - .min(0.D) - .max(10.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("height-lower") + .description("Lower height (Y axis) limit") + .defaultTo(10.D) + .min(0.D) + .max(10.D) + .build(); + private final Setting width_upper = - getCommandStub() - .builders() - .newSettingBuilder() - .name("width-upper") - .description("Upper width (X and Z axis) limit") - .defaultTo(10.D) - .min(0.D) - .max(10.D) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("width-upper") + .description("Upper width (X and Z axis) limit") + .defaultTo(10.D) + .min(0.D) + .max(10.D) + .build(); private final Setting width_lower = - getCommandStub() - .builders() - .newSettingBuilder() - .name("width-lower") - .description("Lower width (X and Z axis) limit") - .defaultTo(10.D) - .min(0.D) - .max(10.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("width-lower") + .description("Lower width (X and Z axis) limit") + .defaultTo(10.D) + .min(0.D) + .max(10.D) + .build(); + private final Setting filter_liquids = - getCommandStub() - .builders() - .newSettingBuilder() - .name("filter-liquids") - .description("Will not mine blocks that is a neighbors to a liquid block.") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("filter-liquids") + .description("Will not mine blocks that is a neighbors to a liquid block.") + .defaultTo(false) + .build(); + private final Setting y_bias = - getCommandStub() - .builders() - .newSettingBuilder() - .name("y-bias") - .description("Will prefer higher blocks (good for mining sand).") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("y-bias") + .description("Will prefer higher blocks (good for mining sand).") + .defaultTo(false) + .build(); + public Nuker() { super(Category.PLAYER, "Nuker", false, "Mine blocks around yourself"); this.bindSelect.setKeyConflictContext(BindingHelper.getEmptyKeyConflictContext()); ClientRegistry.registerKeyBinding(this.bindSelect); } - + private boolean isTargeting(UniqueBlock ub) { return targets.stream().anyMatch(ub::equals); } - + private boolean isInBoundary(UniqueBlock ub) { - if (!bounded.get()) return true; - else { + if (!bounded.get()) { + return true; + } else { Vec3d pos = ub.getCenteredPos().subtract(getLocalPlayer().getPositionVector()); return pos.x < width_upper.get() - && pos.x > -width_lower.get() - && pos.y < height_upper.get() - && pos.y > -height_lower.get() - && pos.z < width_upper.get() - && pos.z > -width_lower.get(); + && pos.x > -width_lower.get() + && pos.y < height_upper.get() + && pos.y > -height_lower.get() + && pos.z < width_upper.get() + && pos.z > -width_lower.get(); } } - + private boolean isNeighborsLiquid(UniqueBlock ub) { return filter_liquids.get() - && Arrays.stream(EnumFacing.values()) - .map(side -> ub.getPos().offset(side)) - .map(pos -> getWorld().getBlockState(pos).getBlock()) - .anyMatch(BlockLiquid.class::isInstance); + && Arrays.stream(EnumFacing.values()) + .map(side -> ub.getPos().offset(side)) + .map(pos -> getWorld().getBlockState(pos).getBlock()) + .anyMatch(BlockLiquid.class::isInstance); } - + private double getHeightBias(UniqueBlock ub) { return !y_bias.get() ? 0.D : -ub.getCenteredPos().y; } - + private float getBlockBreakAmount() { return Fields.PlayerControllerMP_curBlockDamageMP.get(getPlayerController()); } - + private void updateBlockBreaking(BlockPos target) { - if (target == null && currentTarget != null) resetBlockBreaking(); - else if (target != null && currentTarget == null) { + if (target == null && currentTarget != null) { + resetBlockBreaking(); + } else if (target != null && currentTarget == null) { getPlayerController().resetBlockRemoving(); currentTarget = target; } } - + private void resetBlockBreaking() { if (currentTarget != null) { getPlayerController().resetBlockRemoving(); currentTarget = null; } } - + @Override protected void onEnabled() { PositionRotationManager.getManager().register(this, PriorityEnum.HIGH); printInform( - "Select blocks by looking at it and pressing %s", BindingHelper.getIndexName(bindSelect)); + "Select blocks by looking at it and pressing %s", BindingHelper.getIndexName(bindSelect)); } - + @Override protected void onDisabled() { PositionRotationManager.getManager().unregister(this); } - + @SubscribeEvent public void onUpdate(LocalPlayerUpdateEvent event) { if (bindSelect.isKeyDown() && attackToggle.compareAndSet(false, true)) { UniqueBlock info = null; RayTraceResult tr = LocalPlayerUtils.getMouseOverBlockTrace(); - + if (tr == null && !targets.isEmpty()) { UniqueBlock ub = targets.remove(targets.size() - 1); printInform("Removed latest block %s", ub.toString()); return; - } else if (tr != null) info = BlockHelper.newUniqueBlock(tr.getBlockPos()); - - if (info == null) return; - + } else if (tr != null) { + info = BlockHelper.newUniqueBlock(tr.getBlockPos()); + } + + if (info == null) { + return; + } + if (info.isInvalid()) { printWarning("Invalid block selected!"); return; } - + if (!targets.contains(info) && targets.add(info)) { printInform("Added block %s", info.toString()); } else if (targets.remove(info)) { @@ -229,86 +236,91 @@ public void onUpdate(LocalPlayerUpdateEvent event) { attackToggle.set(false); } } - + @SubscribeEvent public void onBlockClick(BlockControllerProcessEvent event) { - if (currentTarget != null) + if (currentTarget != null) { event.setLeftClicked(false); // no block manual breaking while the nuker is running + } } - + @Override public void onLocalPlayerMovementUpdate(Local state) { if (targets.isEmpty()) { resetBlockBreaking(); return; } - + final Vec3d eyes = EntityUtils.getEyePos(getLocalPlayer()); final Vec3d dir = - client_angles.get() - ? LocalPlayerUtils.getDirectionVector() - : LocalPlayerUtils.getServerDirectionVector(); - + client_angles.get() + ? LocalPlayerUtils.getDirectionVector() + : LocalPlayerUtils.getServerDirectionVector(); + BlockTraceInfo trace = null; - + if (currentTarget != null) { // verify the current target is still valid trace = - Optional.of(currentTarget) - .filter(pos -> !getWorld().isAirBlock(pos)) - .map(BlockHelper::newUniqueBlock) - .filter(this::isTargeting) - .filter(this::isInBoundary) - .filter(ub -> !isNeighborsLiquid(ub)) - .map(ub -> BlockHelper.getVisibleBlockSideTrace(eyes, dir, ub.getPos())) - .orElse(null); - if (trace == null) resetBlockBreaking(); + Optional.of(currentTarget) + .filter(pos -> !getWorld().isAirBlock(pos)) + .map(BlockHelper::newUniqueBlock) + .filter(this::isTargeting) + .filter(this::isInBoundary) + .filter(ub -> !isNeighborsLiquid(ub)) + .map(ub -> BlockHelper.getVisibleBlockSideTrace(eyes, dir, ub.getPos())) + .orElse(null); + if (trace == null) { + resetBlockBreaking(); + } } - + if (currentTarget == null) { List blocks = - BlockHelper.getBlocksInRadius(eyes, getPlayerController().getBlockReachDistance()) - .stream() - .filter(pos -> !getWorld().isAirBlock(pos)) - .map(BlockHelper::newUniqueBlock) - .filter(this::isTargeting) - .filter(this::isInBoundary) - .filter(ub -> !isNeighborsLiquid(ub)) - .sorted( - Comparator.comparingDouble(this::getHeightBias) - .thenComparing( - ub -> VectorUtils.getCrosshairDistance(eyes, dir, ub.getCenteredPos()))) - .collect(Collectors.toList()); - + BlockHelper.getBlocksInRadius(eyes, getPlayerController().getBlockReachDistance()) + .stream() + .filter(pos -> !getWorld().isAirBlock(pos)) + .map(BlockHelper::newUniqueBlock) + .filter(this::isTargeting) + .filter(this::isInBoundary) + .filter(ub -> !isNeighborsLiquid(ub)) + .sorted( + Comparator.comparingDouble(this::getHeightBias) + .thenComparing( + ub -> VectorUtils.getCrosshairDistance(eyes, dir, ub.getCenteredPos()))) + .collect(Collectors.toList()); + if (blocks.isEmpty()) { resetBlockBreaking(); return; } - + trace = - blocks - .stream() - .map(ub -> BlockHelper.getVisibleBlockSideTrace(eyes, dir, ub.getPos())) - .filter(Objects::nonNull) - .findFirst() - .orElse(null); + blocks + .stream() + .map(ub -> BlockHelper.getVisibleBlockSideTrace(eyes, dir, ub.getPos())) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); } - + if (trace == null) { resetBlockBreaking(); return; } - + Angle va = Utils.getLookAtAngles(trace.getHitVec()); state.setServerAngles(va); - + final BlockTraceInfo tr = trace; state.invokeLater( - rs -> { - if (getPlayerController().onPlayerDamageBlock(tr.getPos(), tr.getOppositeSide())) { - getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); - updateBlockBreaking(tr.getPos()); - } else resetBlockBreaking(); - }); + rs -> { + if (getPlayerController().onPlayerDamageBlock(tr.getPos(), tr.getOppositeSide())) { + getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); + updateBlockBreaking(tr.getPos()); + } else { + resetBlockBreaking(); + } + }); } } diff --git a/src/main/java/com/matt/forgehax/mods/PacketLogger.java b/src/main/java/com/matt/forgehax/mods/PacketLogger.java index 33df7843c..411e88883 100644 --- a/src/main/java/com/matt/forgehax/mods/PacketLogger.java +++ b/src/main/java/com/matt/forgehax/mods/PacketLogger.java @@ -18,7 +18,6 @@ import com.matt.forgehax.util.mod.loader.RegisterMod; import com.matt.forgehax.util.serialization.GsonConstant; import io.netty.buffer.ByteBuf; - import java.io.BufferedWriter; import java.io.FileOutputStream; import java.io.OutputStreamWriter; @@ -29,7 +28,15 @@ import java.nio.file.Files; import java.nio.file.Path; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Vector; import javax.annotation.Nonnull; import javax.annotation.Nullable; import joptsimple.internal.Strings; @@ -38,149 +45,160 @@ import net.minecraft.util.text.ITextComponent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 10/12/2017 by fr1kin */ +/** + * Created on 10/12/2017 by fr1kin + */ @RegisterMod public class PacketLogger extends ToggleMod implements GsonConstant { + private static final String DATE = new SimpleDateFormat("yyyy.MM.dd-HH.mm.ss").format(new Date()); private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS"); - + private static final Path INBOUND = - getFileManager().getMkBaseResolve("logs/packets/IN-" + DATE + ".log"); + getFileManager().getMkBaseResolve("logs/packets/IN-" + DATE + ".log"); private static final Path OUTBOUND = - getFileManager().getMkBaseResolve("logs/packets/OUT-" + DATE + ".log"); - + getFileManager().getMkBaseResolve("logs/packets/OUT-" + DATE + ".log"); + private volatile BufferedWriter stream_packet_in = null; private volatile BufferedWriter stream_packet_out = null; - + private final Setting blacklist_on = - getCommandStub() - .builders() - .newSettingBuilder() - .name("blacklist_on") - .description("Enables the blacklist") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("blacklist_on") + .description("Enables the blacklist") + .defaultTo(false) + .build(); + private final Options blacklist = - getCommandStub() - .builders() - .newOptionsBuilder() - .name("blacklist") - .description("Classes to ignore") - .factory(ClassEntry::new) - .supplier(Sets::newConcurrentHashSet) - .build(); - + getCommandStub() + .builders() + .newOptionsBuilder() + .name("blacklist") + .description("Classes to ignore") + .factory(ClassEntry::new) + .supplier(Sets::newConcurrentHashSet) + .build(); + public PacketLogger() { super(Category.MISC, "PacketLogger", false, "Logs all packets to file"); } - + @Override protected void onLoad() { blacklist - .builders() - .newCommandBuilder() - .name("add") - .description("Add class") - .processor( - data -> { - data.requiredArguments(1); - final String className = data.getArgumentAsString(0).toLowerCase(); - - if (Strings.isNullOrEmpty(className)) - throw new CommandExecuteException("Empty or null argument"); - - Optional> match = - getLoadedClasses(Launch.classLoader) - .stream() - .filter(Packet.class::isAssignableFrom) - .filter(clazz -> clazz.getCanonicalName().toLowerCase().contains(className)) - .sorted( - (o1, o2) -> - String.CASE_INSENSITIVE_ORDER.compare( - o1.getCanonicalName(), o2.getCanonicalName())) - .findFirst(); - - if (match.isPresent()) { - Class clazz = match.get(); - blacklist.add(new ClassEntry(clazz)); - data.write(String.format("Added class \"%s\"", clazz.getName())); - data.markSuccess(); - } else { - data.write( - String.format("Could not find any class name matching \"%s\"", className)); - data.markFailed(); - } - }) - .success(cb -> blacklist.serialize()) - .build(); - - blacklist - .builders() - .newCommandBuilder() - .name("remove") - .description("Remove class") - .processor( - data -> { - data.requiredArguments(1); - final String className = data.getArgumentAsString(0).toLowerCase(); - - if (Strings.isNullOrEmpty(className)) - throw new CommandExecuteException("Empty or null argument"); - - Optional match = - blacklist - .stream() - .filter(entry -> className.contains(entry.getClassName().toLowerCase())) - .sorted( - (o1, o2) -> - String.CASE_INSENSITIVE_ORDER.compare( - o1.getClassName(), o2.getClassName())) - .findFirst(); - - if (match.isPresent()) { - ClassEntry entry = match.get(); - if (blacklist.remove(entry)) { - data.write(String.format("Removed class \"%s\"", entry.getClassName())); - data.markSuccess(); - } else { - data.write(String.format("Could not remove class \"%s\"", entry.getClassName())); - data.markFailed(); - } - } else { - data.write( - String.format("Could not find any class name matching \"%s\"", className)); - data.markFailed(); - } - }) - .success(cb -> blacklist.serialize()) - .build(); - + .builders() + .newCommandBuilder() + .name("add") + .description("Add class") + .processor( + data -> { + data.requiredArguments(1); + final String className = data.getArgumentAsString(0).toLowerCase(); + + if (Strings.isNullOrEmpty(className)) { + throw new CommandExecuteException("Empty or null argument"); + } + + Optional> match = + getLoadedClasses(Launch.classLoader) + .stream() + .filter(Packet.class::isAssignableFrom) + .filter(clazz -> clazz.getCanonicalName().toLowerCase().contains(className)) + .sorted( + (o1, o2) -> + String.CASE_INSENSITIVE_ORDER.compare( + o1.getCanonicalName(), o2.getCanonicalName())) + .findFirst(); + + if (match.isPresent()) { + Class clazz = match.get(); + blacklist.add(new ClassEntry(clazz)); + data.write(String.format("Added class \"%s\"", clazz.getName())); + data.markSuccess(); + } else { + data.write( + String.format("Could not find any class name matching \"%s\"", className)); + data.markFailed(); + } + }) + .success(cb -> blacklist.serialize()) + .build(); + blacklist - .builders() - .newCommandBuilder() - .name("list") - .description("List current contents") - .processor( - data -> { - StringBuilder builder = new StringBuilder(); - Iterator it = blacklist.iterator(); - if (it.hasNext()) { - builder.append(it.next().getClassName()); - if (it.hasNext()) builder.append(", "); - } - data.write(builder.toString()); + .builders() + .newCommandBuilder() + .name("remove") + .description("Remove class") + .processor( + data -> { + data.requiredArguments(1); + final String className = data.getArgumentAsString(0).toLowerCase(); + + if (Strings.isNullOrEmpty(className)) { + throw new CommandExecuteException("Empty or null argument"); + } + + Optional match = + blacklist + .stream() + .filter(entry -> className.contains(entry.getClassName().toLowerCase())) + .sorted( + (o1, o2) -> + String.CASE_INSENSITIVE_ORDER.compare( + o1.getClassName(), o2.getClassName())) + .findFirst(); + + if (match.isPresent()) { + ClassEntry entry = match.get(); + if (blacklist.remove(entry)) { + data.write(String.format("Removed class \"%s\"", entry.getClassName())); data.markSuccess(); - }) - .build(); + } else { + data.write(String.format("Could not remove class \"%s\"", entry.getClassName())); + data.markFailed(); + } + } else { + data.write( + String.format("Could not find any class name matching \"%s\"", className)); + data.markFailed(); + } + }) + .success(cb -> blacklist.serialize()) + .build(); + + blacklist + .builders() + .newCommandBuilder() + .name("list") + .description("List current contents") + .processor( + data -> { + StringBuilder builder = new StringBuilder(); + Iterator it = blacklist.iterator(); + if (it.hasNext()) { + builder.append(it.next().getClassName()); + if (it.hasNext()) { + builder.append(", "); + } + } + data.write(builder.toString()); + data.markSuccess(); + }) + .build(); } - + @Override protected void onEnabled() { try { - if (!Files.exists(INBOUND)) Files.createFile(INBOUND); - if (!Files.exists(OUTBOUND)) Files.createFile(OUTBOUND); - + if (!Files.exists(INBOUND)) { + Files.createFile(INBOUND); + } + if (!Files.exists(OUTBOUND)) { + Files.createFile(OUTBOUND); + } + stream_packet_in = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(INBOUND.toFile(), true), StandardCharsets.UTF_8)); stream_packet_out = new BufferedWriter(new OutputStreamWriter( @@ -188,68 +206,74 @@ protected void onEnabled() { } catch (Throwable t) { } } - + @Override protected void onDisabled() { - if (stream_packet_in != null) + if (stream_packet_in != null) { try { stream_packet_in.close(); stream_packet_in = null; } catch (Throwable t) { } - - if (stream_packet_out != null) + } + + if (stream_packet_out != null) { try { stream_packet_out.close(); stream_packet_out = null; } catch (Throwable t) { } + } } - + @Override protected void onUnload() { onDisabled(); } - + @SubscribeEvent public void onPacketInbound(PacketEvent.Incoming.Pre event) { - if (!blacklist_on.get() || blacklist.get(event.getPacket().getClass()) == null) + if (!blacklist_on.get() || blacklist.get(event.getPacket().getClass()) == null) { logPacket(stream_packet_in, event.getPacket()); + } } - + @SubscribeEvent public void onPacketOutbound(PacketEvent.Outgoing.Pre event) { - if (!blacklist_on.get() || blacklist.get(event.getPacket().getClass()) == null) + if (!blacklist_on.get() || blacklist.get(event.getPacket().getClass()) == null) { logPacket(stream_packet_out, event.getPacket()); + } } - + // // // - + private static void logPacket(BufferedWriter stream, Packet packet) { - if (stream == null || packet == null) return; - + if (stream == null || packet == null) { + return; + } + try { stream.write( - String.format( - "[%s][%s] %s\n", - TIME_FORMAT.format(new Date()), - packet.getClass().getSimpleName(), - GSON_PRETTY.toJson(objectToElement(packet, true, null, Lists.newArrayList())) - ) + String.format( + "[%s][%s] %s\n", + TIME_FORMAT.format(new Date()), + packet.getClass().getSimpleName(), + GSON_PRETTY.toJson(objectToElement(packet, true, null, Lists.newArrayList())) + ) ); stream.flush(); } catch (Throwable t) { t.printStackTrace(); } } - + private static JsonElement objectToElement( - Object obj, - boolean deep, - @Nullable Class superClassLimit, - @Nonnull final List dejaVu) { + Object obj, + boolean deep, + @Nullable Class superClassLimit, + @Nonnull final List dejaVu) { JsonObject json = new JsonObject(); dejaVu.add(obj); if (obj != null) { @@ -265,35 +289,44 @@ private static JsonElement objectToElement( try { value = field.get(obj); name = - clazz.getSimpleName() - + "." - + field.getName() - + "@" - + Integer.toHexString(Objects.hashCode(value)); + clazz.getSimpleName() + + "." + + field.getName() + + "@" + + Integer.toHexString(Objects.hashCode(value)); } catch (Throwable t) { name = "null@0"; } - if (dejaVu.contains(value)) json.addProperty(name, Objects.toString(value)); - else json.add(name, objectAsJson(value, dejaVu)); + if (dejaVu.contains(value)) { + json.addProperty(name, Objects.toString(value)); + } else { + json.add(name, objectAsJson(value, dejaVu)); + } } } catch (Throwable t) { } } } catch (Throwable t) { } finally { - if (!deep || (superClassLimit != null && clazz.equals(superClassLimit))) clazz = null; - else clazz = clazz.getSuperclass(); + if (!deep || (superClassLimit != null && clazz.equals(superClassLimit))) { + clazz = null; + } else { + clazz = clazz.getSuperclass(); + } } } while (clazz != null && !Object.class.equals(clazz)); } return json; } - + private static JsonElement objectAsJson(Object obj, @Nonnull final List dejaVu) { - if (obj == null) return new JsonPrimitive("null"); + if (obj == null) { + return new JsonPrimitive("null"); + } try { - if (obj.getClass().isPrimitive() || obj instanceof String) + if (obj.getClass().isPrimitive() || obj instanceof String) { return new JsonPrimitive(obj.toString()); + } if (obj.getClass().isArray()) { JsonArray array = new JsonArray(); for (Object child : (Object[]) obj) { @@ -324,7 +357,7 @@ private static JsonElement objectAsJson(Object obj, @Nonnull final List } return new JsonPrimitive(obj.toString()); } - + private static String defaultToString(Object o) { try { return o.getClass().getName() + "@" + Integer.toHexString(Objects.hashCode(o)); @@ -332,12 +365,14 @@ private static String defaultToString(Object o) { return "null@0"; } } - + private static Collection> getLoadedClasses(ClassLoader loader) { try { Objects.requireNonNull(loader); Class mclass = loader.getClass(); - while (mclass != ClassLoader.class) mclass = mclass.getSuperclass(); + while (mclass != ClassLoader.class) { + mclass = mclass.getSuperclass(); + } Field classes = mclass.getDeclaredField("classes"); classes.setAccessible(true); return (Vector>) classes.get(loader); diff --git a/src/main/java/com/matt/forgehax/mods/PayloadSpoofer.java b/src/main/java/com/matt/forgehax/mods/PayloadSpoofer.java index 83b6a2c3c..93d8ff37e 100644 --- a/src/main/java/com/matt/forgehax/mods/PayloadSpoofer.java +++ b/src/main/java/com/matt/forgehax/mods/PayloadSpoofer.java @@ -14,21 +14,24 @@ import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 6/2/2017 by fr1kin */ +/** + * Created on 6/2/2017 by fr1kin + */ @RegisterMod public class PayloadSpoofer extends ToggleMod { + private static final Set IGNORE_LIST = Sets.newHashSet(); - + static { IGNORE_LIST.add("WDL|INIT"); IGNORE_LIST.add("WDL|CONTROL"); IGNORE_LIST.add("WDL|REQUEST"); } - + public PayloadSpoofer() { super(Category.MISC, "PayloadSpoofer", false, "Will cancel packets sent by some mods"); } - + private boolean isBlockedPacket(String channel, PacketBuffer buffer) { if (IGNORE_LIST.contains(channel)) { return true; @@ -37,27 +40,33 @@ private boolean isBlockedPacket(String channel, PacketBuffer buffer) { scanner.useDelimiter("\\u0000"); if (scanner.hasNext()) { String next = scanner.next(); - if (!Strings.isNullOrEmpty(next) && IGNORE_LIST.contains(next)) return true; + if (!Strings.isNullOrEmpty(next) && IGNORE_LIST.contains(next)) { + return true; + } } } return false; } - + @SubscribeEvent(priority = EventPriority.HIGHEST) public void onIncomingPacket(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketCustomPayload) { String channel = ((SPacketCustomPayload) event.getPacket()).getChannelName(); PacketBuffer packetBuffer = ((SPacketCustomPayload) event.getPacket()).getBufferData(); - if (isBlockedPacket(channel, packetBuffer)) event.setCanceled(true); + if (isBlockedPacket(channel, packetBuffer)) { + event.setCanceled(true); + } } } - + @SubscribeEvent(priority = EventPriority.HIGHEST) public void onOutgoingPacket(PacketEvent.Outgoing.Pre event) { if (event.getPacket() instanceof CPacketCustomPayload) { String channel = ((CPacketCustomPayload) event.getPacket()).getChannelName(); PacketBuffer packetBuffer = ((CPacketCustomPayload) event.getPacket()).getBufferData(); - if (isBlockedPacket(channel, packetBuffer)) event.setCanceled(true); + if (isBlockedPacket(channel, packetBuffer)) { + event.setCanceled(true); + } } } } diff --git a/src/main/java/com/matt/forgehax/mods/PortalGui.java b/src/main/java/com/matt/forgehax/mods/PortalGui.java index a8bbd2743..99d9e3cc7 100644 --- a/src/main/java/com/matt/forgehax/mods/PortalGui.java +++ b/src/main/java/com/matt/forgehax/mods/PortalGui.java @@ -8,13 +8,16 @@ import com.matt.forgehax.util.mod.loader.RegisterMod; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created by Babbaj on 8/28/2017. */ +/** + * Created by Babbaj on 8/28/2017. + */ @RegisterMod public class PortalGui extends ToggleMod { + public PortalGui() { super(Category.PLAYER, "PortalGui", false, "Guis work while in portals"); } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { FastReflection.Fields.Entity_inPortal.set(Helper.getLocalPlayer(), false); diff --git a/src/main/java/com/matt/forgehax/mods/RiderDesync.java b/src/main/java/com/matt/forgehax/mods/RiderDesync.java index 9cefb4f8e..c816058f0 100644 --- a/src/main/java/com/matt/forgehax/mods/RiderDesync.java +++ b/src/main/java/com/matt/forgehax/mods/RiderDesync.java @@ -18,141 +18,144 @@ @RegisterMod public class RiderDesync extends ToggleMod { + private final Setting auto_update = - getCommandStub() - .builders() - .newSettingBuilder() - .name("auto-update") - .description("Automatically update entity on dismount") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("auto-update") + .description("Automatically update entity on dismount") + .defaultTo(true) + .build(); + private Entity dismountedEntity = null; private boolean forceUpdate = false; - + public RiderDesync() { super(Category.PLAYER, "RiderDesync", false, "For entity force dismounting"); } - + @Override public String getDebugDisplayText() { return super.getDebugDisplayText() + String.format(" [e = %s fu = %s]", - dismountedEntity == null ? "null" : dismountedEntity.getName(), - forceUpdate ? "true" : "false"); + dismountedEntity == null ? "null" : dismountedEntity.getName(), + forceUpdate ? "true" : "false"); } - + @Override protected void onLoad() { getCommandStub().builders().newCommandBuilder() - .name("remount") - .description("Remount entity") - .processor(data -> MC.addScheduledTask(() -> { - if(!isEnabled()) { - printWarning("Mod not enabled"); - return; - } - - if(getLocalPlayer() == null || getWorld() == null) { - printWarning("Must be ingame to use this command."); - return; - } - - if(dismountedEntity == null) { - printWarning("No entity mounted"); - return; - } - - dismountedEntity.isDead = false; - getWorld().spawnEntity(dismountedEntity); - getLocalPlayer().startRiding(dismountedEntity); - - printInform("Remounted entity " + dismountedEntity.getName()); - })) - .build(); - + .name("remount") + .description("Remount entity") + .processor(data -> MC.addScheduledTask(() -> { + if (!isEnabled()) { + printWarning("Mod not enabled"); + return; + } + + if (getLocalPlayer() == null || getWorld() == null) { + printWarning("Must be ingame to use this command."); + return; + } + + if (dismountedEntity == null) { + printWarning("No entity mounted"); + return; + } + + dismountedEntity.isDead = false; + getWorld().spawnEntity(dismountedEntity); + getLocalPlayer().startRiding(dismountedEntity); + + printInform("Remounted entity " + dismountedEntity.getName()); + })) + .build(); + getCommandStub().builders().newCommandBuilder() - .name("dismount") - .description("Dismount entity") - .processor(data -> MC.addScheduledTask(() -> { - if(!isEnabled()) { - printWarning("Mod not enabled"); - return; - } - - if(getLocalPlayer() == null || getWorld() == null) { - printWarning("Must be ingame to use this command."); - return; - } - - Entity mounted = getLocalPlayer().getRidingEntity(); - - if(mounted == null) { - printWarning("No entity mounted"); - return; - } - - dismountedEntity = mounted; - getLocalPlayer().dismountRidingEntity(); - getWorld().removeEntity(mounted); - - if(auto_update.get()) { - forceUpdate = true; - printInform("Dismounted entity " + mounted.getName() + " and forcing entity updates"); - } else - printInform("Dismounted entity " + mounted.getName()); - })) - .build(); - + .name("dismount") + .description("Dismount entity") + .processor(data -> MC.addScheduledTask(() -> { + if (!isEnabled()) { + printWarning("Mod not enabled"); + return; + } + + if (getLocalPlayer() == null || getWorld() == null) { + printWarning("Must be ingame to use this command."); + return; + } + + Entity mounted = getLocalPlayer().getRidingEntity(); + + if (mounted == null) { + printWarning("No entity mounted"); + return; + } + + dismountedEntity = mounted; + getLocalPlayer().dismountRidingEntity(); + getWorld().removeEntity(mounted); + + if (auto_update.get()) { + forceUpdate = true; + printInform("Dismounted entity " + mounted.getName() + " and forcing entity updates"); + } else { + printInform("Dismounted entity " + mounted.getName()); + } + })) + .build(); + getCommandStub().builders().newCommandBuilder() - .name("force-update") - .description("Force dismount entity") - .processor(data -> MC.addScheduledTask(() -> { - if(!isEnabled()) { - printWarning("Mod not enabled"); - return; - } - - if(getLocalPlayer() == null || getWorld() == null) { - printWarning("Must be ingame to use this command."); - return; - } - - if(dismountedEntity == null) { - printWarning("No entity to force remount"); - return; - } - - forceUpdate = !forceUpdate; - - printInform("Force mounted entity = %s", forceUpdate ? "true" : "false"); - })) - .build(); - + .name("force-update") + .description("Force dismount entity") + .processor(data -> MC.addScheduledTask(() -> { + if (!isEnabled()) { + printWarning("Mod not enabled"); + return; + } + + if (getLocalPlayer() == null || getWorld() == null) { + printWarning("Must be ingame to use this command."); + return; + } + + if (dismountedEntity == null) { + printWarning("No entity to force remount"); + return; + } + + forceUpdate = !forceUpdate; + + printInform("Force mounted entity = %s", forceUpdate ? "true" : "false"); + })) + .build(); + getCommandStub().builders().newCommandBuilder() - .name("reset") - .description("Reset the currently stored riding entity") - .processor(data -> MC.addScheduledTask(() -> { - this.dismountedEntity = null; - this.forceUpdate = false; - printInform("Saved riding entity reset"); - })) - .build(); + .name("reset") + .description("Reset the currently stored riding entity") + .processor(data -> MC.addScheduledTask(() -> { + this.dismountedEntity = null; + this.forceUpdate = false; + printInform("Saved riding entity reset"); + })) + .build(); } - + @SubscribeEvent public void onTick(LocalPlayerUpdateEvent event) { - if(dismountedEntity == null || getLocalPlayer().isRiding()) { + if (dismountedEntity == null || getLocalPlayer().isRiding()) { this.dismountedEntity = null; this.forceUpdate = false; return; } - - if(forceUpdate && dismountedEntity != null) { - dismountedEntity.setPosition(getLocalPlayer().posX, getLocalPlayer().posY, getLocalPlayer().posZ); + + if (forceUpdate && dismountedEntity != null) { + dismountedEntity + .setPosition(getLocalPlayer().posX, getLocalPlayer().posY, getLocalPlayer().posZ); getNetworkManager().sendPacket(new CPacketVehicleMove(dismountedEntity)); } } - + @SubscribeEvent public void onWorldUnload(WorldEvent.Unload event) { this.dismountedEntity = null; diff --git a/src/main/java/com/matt/forgehax/mods/SafeWalkMod.java b/src/main/java/com/matt/forgehax/mods/SafeWalkMod.java index e0e4d22d0..ee984b776 100644 --- a/src/main/java/com/matt/forgehax/mods/SafeWalkMod.java +++ b/src/main/java/com/matt/forgehax/mods/SafeWalkMod.java @@ -13,70 +13,77 @@ import net.minecraft.util.math.BlockPos; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 9/4/2016 by fr1kin */ +/** + * Created on 9/4/2016 by fr1kin + */ @RegisterMod public class SafeWalkMod extends ToggleMod { + public SafeWalkMod() { super(Category.PLAYER, "SafeWalk", false, "Prevents you from falling off blocks"); } - + private final Setting collisions = - getCommandStub() - .builders() - .newSettingBuilder() - .name("collisions") - .description("Give air collision boxes") - .defaultTo(false) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("collisions") + .description("Give air collision boxes") + .defaultTo(false) + .build(); private final Setting min_height = - getCommandStub() - .builders() - .newSettingBuilder() - .name("min-height") - .description("Minimum height above ground for collisions") - .defaultTo(15) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("min-height") + .description("Minimum height above ground for collisions") + .defaultTo(15) + .build(); + @SubscribeEvent public void onAddCollisionBox(AddCollisionBoxToListEvent event) { - if (!collisions.get()) return; - + if (!collisions.get()) { + return; + } + if (getLocalPlayer() != null && - (EntityUtils.isDrivenByPlayer(event.getEntity()) || event.getEntity() == getLocalPlayer())) { - + (EntityUtils.isDrivenByPlayer(event.getEntity()) || event.getEntity() == getLocalPlayer())) { + AxisAlignedBB axisalignedbb = new AxisAlignedBB(event.getPos()).shrink(0.3D); if (event.getEntityBox().intersects(axisalignedbb)) { if (isAbovePlayer(event.getPos()) && - !hasCollisionBox(event.getPos()) && - !isAboveBlock(event.getPos(), min_height.get())) { - + !hasCollisionBox(event.getPos()) && + !isAboveBlock(event.getPos(), min_height.get())) { + event.getCollidingBoxes().add(axisalignedbb); } } } } - + private boolean isAbovePlayer(BlockPos pos) { return pos.getY() >= getLocalPlayer().posY; } - - + + private boolean isAboveBlock(BlockPos pos, int minHeight) { for (int i = 0; i < minHeight; i++) { - if (hasCollisionBox(pos.down(i))) return true; + if (hasCollisionBox(pos.down(i))) { + return true; + } } return false; } - + private boolean hasCollisionBox(BlockPos pos) { return MC.world.getBlockState(pos).getCollisionBoundingBox(MC.world, pos) != null; } - + @Override public void onEnabled() { ForgeHaxHooks.isSafeWalkActivated = true; } - + @Override public void onDisabled() { ForgeHaxHooks.isSafeWalkActivated = false; diff --git a/src/main/java/com/matt/forgehax/mods/Scaffold.java b/src/main/java/com/matt/forgehax/mods/Scaffold.java index 4d2e144e2..2e68bcd1d 100644 --- a/src/main/java/com/matt/forgehax/mods/Scaffold.java +++ b/src/main/java/com/matt/forgehax/mods/Scaffold.java @@ -38,115 +38,124 @@ @RegisterMod public class Scaffold extends ToggleMod implements PositionRotationManager.MovementUpdateListener { + private static final EnumSet NEIGHBORS = - EnumSet.of(EnumFacing.NORTH, EnumFacing.EAST, EnumFacing.SOUTH, EnumFacing.WEST); - + EnumSet.of(EnumFacing.NORTH, EnumFacing.EAST, EnumFacing.SOUTH, EnumFacing.WEST); + private int tickCount = 0; private boolean placing = false; private Angle previousAngles = Angle.ZERO; - + public Scaffold() { super(Category.PLAYER, "Scaffold", false, "Place blocks under yourself"); } - + @Override protected void onEnabled() { PositionRotationManager.getManager().register(this, PriorityEnum.HIGHEST); } - + @Override protected void onDisabled() { PositionRotationManager.getManager().unregister(this); } - + @Override public void onLocalPlayerMovementUpdate(Local state) { - if (placing) ++tickCount; - + if (placing) { + ++tickCount; + } + if (LocalPlayerUtils.getVelocity().normalize().lengthVector() > 1.D && placing) { state.setServerAngles(previousAngles); } else { placing = false; tickCount = 0; } - + BlockPos below = new BlockPos(getLocalPlayer()).down(); - - if (!getWorld().getBlockState(below).getMaterial().isReplaceable()) return; - + + if (!getWorld().getBlockState(below).getMaterial().isReplaceable()) { + return; + } + InvItem items = - LocalPlayerInventory.getHotbarInventory() - .stream() - .filter(InvItem::nonNull) - .filter(item -> item.getItem() instanceof ItemBlock) - .filter(item -> Block.getBlockFromItem(item.getItem()).getDefaultState().isFullBlock()) - .max(Comparator.comparingInt(LocalPlayerInventory::getHotbarDistance)) - .orElse(InvItem.EMPTY); - - if (items.isNull()) return; - + LocalPlayerInventory.getHotbarInventory() + .stream() + .filter(InvItem::nonNull) + .filter(item -> item.getItem() instanceof ItemBlock) + .filter(item -> Block.getBlockFromItem(item.getItem()).getDefaultState().isFullBlock()) + .max(Comparator.comparingInt(LocalPlayerInventory::getHotbarDistance)) + .orElse(InvItem.EMPTY); + + if (items.isNull()) { + return; + } + final Vec3d eyes = EntityUtils.getEyePos(getLocalPlayer()); final Vec3d dir = LocalPlayerUtils.getViewAngles().getDirectionVector(); - + BlockTraceInfo trace = - Optional.ofNullable(BlockHelper.getPlaceableBlockSideTrace(eyes, dir, below)) - .filter(tr -> tr.isPlaceable(items)) - .orElseGet( - () -> - NEIGHBORS - .stream() - .map(below::offset) - .filter(BlockHelper::isBlockReplaceable) - .map(bp -> BlockHelper.getPlaceableBlockSideTrace(eyes, dir, bp)) - .filter(Objects::nonNull) - .filter(tr -> tr.isPlaceable(items)) - .max(Comparator.comparing(BlockTraceInfo::isSneakRequired)) - .orElse(null)); - - if (trace == null) return; - + Optional.ofNullable(BlockHelper.getPlaceableBlockSideTrace(eyes, dir, below)) + .filter(tr -> tr.isPlaceable(items)) + .orElseGet( + () -> + NEIGHBORS + .stream() + .map(below::offset) + .filter(BlockHelper::isBlockReplaceable) + .map(bp -> BlockHelper.getPlaceableBlockSideTrace(eyes, dir, bp)) + .filter(Objects::nonNull) + .filter(tr -> tr.isPlaceable(items)) + .max(Comparator.comparing(BlockTraceInfo::isSneakRequired)) + .orElse(null)); + + if (trace == null) { + return; + } + Vec3d hit = trace.getHitVec(); state.setServerAngles(previousAngles = Utils.getLookAtAngles(hit)); - + final BlockTraceInfo tr = trace; state.invokeLater( - rs -> { - ResetFunction func = LocalPlayerInventory.setSelected(items); - - boolean sneak = tr.isSneakRequired() && !LocalPlayerUtils.isSneaking(); - if (sneak) { - // send start sneaking packet - PacketHelper.ignoreAndSend( - new CPacketEntityAction(getLocalPlayer(), Action.START_SNEAKING)); - - LocalPlayerUtils.setSneaking(true); - LocalPlayerUtils.setSneakingSuppression(true); - } - - getPlayerController() - .processRightClickBlock( - getLocalPlayer(), - getWorld(), - tr.getPos(), - tr.getOppositeSide(), - hit, - EnumHand.MAIN_HAND); - - getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); - - if (sneak) { - LocalPlayerUtils.setSneaking(false); - LocalPlayerUtils.setSneakingSuppression(false); - - getNetworkManager() - .sendPacket(new CPacketEntityAction(getLocalPlayer(), Action.STOP_SNEAKING)); - } - - func.revert(); - - Fields.Minecraft_rightClickDelayTimer.set(MC, 4); - placing = true; - tickCount = 0; - }); + rs -> { + ResetFunction func = LocalPlayerInventory.setSelected(items); + + boolean sneak = tr.isSneakRequired() && !LocalPlayerUtils.isSneaking(); + if (sneak) { + // send start sneaking packet + PacketHelper.ignoreAndSend( + new CPacketEntityAction(getLocalPlayer(), Action.START_SNEAKING)); + + LocalPlayerUtils.setSneaking(true); + LocalPlayerUtils.setSneakingSuppression(true); + } + + getPlayerController() + .processRightClickBlock( + getLocalPlayer(), + getWorld(), + tr.getPos(), + tr.getOppositeSide(), + hit, + EnumHand.MAIN_HAND); + + getNetworkManager().sendPacket(new CPacketAnimation(EnumHand.MAIN_HAND)); + + if (sneak) { + LocalPlayerUtils.setSneaking(false); + LocalPlayerUtils.setSneakingSuppression(false); + + getNetworkManager() + .sendPacket(new CPacketEntityAction(getLocalPlayer(), Action.STOP_SNEAKING)); + } + + func.revert(); + + Fields.Minecraft_rightClickDelayTimer.set(MC, 4); + placing = true; + tickCount = 0; + }); } } diff --git a/src/main/java/com/matt/forgehax/mods/SchematicaPrinterBypass.java b/src/main/java/com/matt/forgehax/mods/SchematicaPrinterBypass.java index 8bb462b50..29b8d40a1 100644 --- a/src/main/java/com/matt/forgehax/mods/SchematicaPrinterBypass.java +++ b/src/main/java/com/matt/forgehax/mods/SchematicaPrinterBypass.java @@ -1,6 +1,7 @@ package com.matt.forgehax.mods; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getNetworkManager; import com.matt.forgehax.asm.events.SchematicaPlaceBlockEvent; import com.matt.forgehax.util.Utils; @@ -11,26 +12,28 @@ import net.minecraft.network.play.client.CPacketPlayer; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created by Babbaj on 9/20/2017. */ +/** + * Created by Babbaj on 9/20/2017. + */ @RegisterMod public class SchematicaPrinterBypass extends ToggleMod { - + public SchematicaPrinterBypass() { super(Category.MISC, "PrinterBypass", false, "Set silent angles for schematica printer"); } - + @Override public boolean isHidden() { return true; } - + @SubscribeEvent public void onPrinterBlockPlace(SchematicaPlaceBlockEvent event) { Angle lookAngle = Utils.getLookAtAngles(event.getVec()); getNetworkManager() - .sendPacket( - new CPacketPlayer.Rotation( - lookAngle.getYaw(), lookAngle.getPitch(), getLocalPlayer().onGround)); + .sendPacket( + new CPacketPlayer.Rotation( + lookAngle.getYaw(), lookAngle.getPitch(), getLocalPlayer().onGround)); // getLocalPlayer().rotationYaw = getLocalPlayer().prevRotationYaw = (float)lookAngle.getYaw(); // getLocalPlayer().rotationPitch = getLocalPlayer().prevRotationPitch = // (float)lookAngle.getPitch(); diff --git a/src/main/java/com/matt/forgehax/mods/ShulkerViewer.java b/src/main/java/com/matt/forgehax/mods/ShulkerViewer.java index b404e1eff..d7064f2e9 100644 --- a/src/main/java/com/matt/forgehax/mods/ShulkerViewer.java +++ b/src/main/java/com/matt/forgehax/mods/ShulkerViewer.java @@ -43,125 +43,131 @@ @RegisterMod public class ShulkerViewer extends ToggleMod { + private static final ResourceLocation SHULKER_GUI_TEXTURE = - new ResourceLocation("textures/gui/container/shulker_box.png"); + new ResourceLocation("textures/gui/container/shulker_box.png"); private static final int SHULKER_GUI_SIZE = 16 + 54 + 6; - + private static final int CACHE_HOVERING_INDEX = 0; private static final int CACHE_HOLDING_INDEX = 1; private static final int CACHE_RESERVE_SIZE = 2; - + private final Setting help_text = - getCommandStub() - .builders() - .newSettingBuilder() - .name("help-text") - .description( - "Text to inform new users that the shulker contents can be viewed by holding a key down") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("help-text") + .description( + "Text to inform new users that the shulker contents can be viewed by holding a key down") + .defaultTo(true) + .build(); + private final Setting toggle_lock = - getCommandStub() - .builders() - .newSettingBuilder() - .name("toggle-lock") - .description("GUI will remain locked in place until key is pressed again") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("toggle-lock") + .description("GUI will remain locked in place until key is pressed again") + .defaultTo(false) + .build(); + private final Setting tooltip_opacity = - getCommandStub() - .builders() - .newSettingBuilder() - .name("tooltip-opacity") - .description("Opacity of the Shulker GUI when displaying") - .defaultTo(200) - .min(0) - .max(255) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("tooltip-opacity") + .description("Opacity of the Shulker GUI when displaying") + .defaultTo(200) + .min(0) + .max(255) + .build(); + private final Setting locked_opacity = - getCommandStub() - .builders() - .newSettingBuilder() - .name("locked-opacity") - .description("Opacity of the Shulker GUI when locked in place") - .defaultTo(255) - .min(0) - .max(255) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("locked-opacity") + .description("Opacity of the Shulker GUI when locked in place") + .defaultTo(255) + .min(0) + .max(255) + .build(); + private final Setting x_offset = - getCommandStub() - .builders() - .newSettingBuilder() - .name("x-offset") - .description("X Offset for the tool tip") - .defaultTo(8) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("x-offset") + .description("X Offset for the tool tip") + .defaultTo(8) + .build(); + private final Setting y_offset = - getCommandStub() - .builders() - .newSettingBuilder() - .name("y-offset") - .description("Y Offset for the tool tip") - .defaultTo(0) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("y-offset") + .description("Y Offset for the tool tip") + .defaultTo(0) + .build(); + private final KeyBinding lockDownKey = - new KeyBinding("ShulkerViewer Lock", Keyboard.KEY_LSHIFT, "ForgeHax"); - + new KeyBinding("ShulkerViewer Lock", Keyboard.KEY_LSHIFT, "ForgeHax"); + private final List guiCache = - Lists.newArrayListWithExpectedSize(CACHE_RESERVE_SIZE); + Lists.newArrayListWithExpectedSize(CACHE_RESERVE_SIZE); private final Lock cacheLock = new ReentrantLock(); - + private boolean locked = false; private boolean updated = false; - + private boolean isKeySet = false; - + private boolean isMouseInShulkerGui = false; private boolean isModGeneratedToolTip = false; - + private int lastX = -1; private int lastY = -1; - + public ShulkerViewer() { super(Category.RENDER, "ShulkerViewer", false, "View the contents of a shulker box."); ClientRegistry.registerKeyBinding(lockDownKey); lockDownKey.setKeyConflictContext( - new IKeyConflictContext() { - @Override - public boolean isActive() { - return MC.currentScreen instanceof GuiContainer; - } - - @Override - public boolean conflicts(IKeyConflictContext other) { - return false; // this will never conflict as - } - }); + new IKeyConflictContext() { + @Override + public boolean isActive() { + return MC.currentScreen instanceof GuiContainer; + } + + @Override + public boolean conflicts(IKeyConflictContext other) { + return false; // this will never conflict as + } + }); } - + private boolean isLocked() { return locked && updated; } - + private boolean setInCache(int index, @Nullable GuiShulkerViewer viewer) { - if (index < 0) return false; - else if (viewer == null && index > (CACHE_RESERVE_SIZE - 1) && index == guiCache.size() - 1) { + if (index < 0) { + return false; + } else if (viewer == null && index > (CACHE_RESERVE_SIZE - 1) && index == guiCache.size() - 1) { guiCache.remove(index); // remove non-reserved extras int previous = index - 1; if (previous > (CACHE_RESERVE_SIZE - 1) - && !getInCache(previous) - .isPresent()) // check if previous entry is null and remove it recursively if it is - return setInCache(previous, null); - else return true; + && !getInCache(previous) + .isPresent()) // check if previous entry is null and remove it recursively if it is + { + return setInCache(previous, null); + } else { + return true; + } } else if (index > guiCache.size() - 1) { // array not big enough - for (int i = Math.max(guiCache.size(), 1); i < index; ++i) + for (int i = Math.max(guiCache.size(), 1); i < index; ++i) { guiCache.add(i, null); // fill with nulls up to the index + } guiCache.add(index, viewer); return true; } else { @@ -169,42 +175,44 @@ else if (viewer == null && index > (CACHE_RESERVE_SIZE - 1) && index == guiCache return true; } } - + private boolean appendInCache(@Nonnull GuiShulkerViewer viewer) { return setInCache(Math.max(guiCache.size() - 1, CACHE_RESERVE_SIZE), viewer); } - + private Optional getInCache(int index) { return Utils.isInRange(guiCache, index) - ? Optional.ofNullable(guiCache.get(index)) - : Optional.empty(); + ? Optional.ofNullable(guiCache.get(index)) + : Optional.empty(); } - + private void clearCache() { - for (int i = 0; i < CACHE_RESERVE_SIZE; ++i) + for (int i = 0; i < CACHE_RESERVE_SIZE; ++i) { setInCache( - i, null); // set all reserve slots to null, and add them if they don't already exist - while (guiCache.size() > CACHE_RESERVE_SIZE) + i, null); // set all reserve slots to null, and add them if they don't already exist + } + while (guiCache.size() > CACHE_RESERVE_SIZE) { setInCache(guiCache.size() - 1, null); // clear the rest + } } - + private void reset() { locked = updated = isKeySet = isMouseInShulkerGui = isModGeneratedToolTip = false; lastX = lastY = -1; clearCache(); } - + private GuiShulkerViewer newShulkerGui(ItemStack parentShulker, int priority) { return new GuiShulkerViewer( - new ShulkerContainer(new ShulkerInventory(Utils.getShulkerContents(parentShulker)), 27), - parentShulker, - priority); + new ShulkerContainer(new ShulkerInventory(Utils.getShulkerContents(parentShulker)), 27), + parentShulker, + priority); } - + private boolean isInRegion(int x, int y, int width, int height, int testingX, int testingY) { return testingX >= x && testingY >= y && testingX <= x + width && testingY <= y + height; } - + @Override protected void onEnabled() { cacheLock.lock(); @@ -214,17 +222,17 @@ protected void onEnabled() { cacheLock.unlock(); } } - + @Override protected void onDisabled() { onEnabled(); } - + @Override public String getDebugDisplayText() { return super.getDebugDisplayText() + " " + String.format("[size = %d]", guiCache.size()); } - + @SubscribeEvent public void onKeyboardInput(GuiScreenEvent.KeyboardInputEvent event) { if (Keyboard.getEventKey() == lockDownKey.getKeyCode()) { @@ -232,7 +240,9 @@ public void onKeyboardInput(GuiScreenEvent.KeyboardInputEvent event) { if (toggle_lock.get()) { if (!isKeySet) { locked = !locked; - if (!locked) updated = false; + if (!locked) { + updated = false; + } isKeySet = true; } } else { @@ -247,131 +257,144 @@ public void onKeyboardInput(GuiScreenEvent.KeyboardInputEvent event) { } } } - + @SubscribeEvent public void onPreTooptipRender(RenderTooltipEvent.Pre event) { - if (!(MC.currentScreen instanceof GuiContainer) || isModGeneratedToolTip) return; - + if (!(MC.currentScreen instanceof GuiContainer) || isModGeneratedToolTip) { + return; + } + if (isMouseInShulkerGui) { // do not render tool tips that are inside the region of our shulker gui event.setCanceled(true); - } else if (event.getStack().getItem() instanceof ItemShulkerBox) + } else if (event.getStack().getItem() instanceof ItemShulkerBox) { event.setCanceled(true); // do not draw normal tool tip + } } - + @SubscribeEvent public void onGuiChanged(GuiOpenEvent event) { - if (event.getGui() == null) reset(); + if (event.getGui() == null) { + reset(); + } } - + @SubscribeEvent(priority = EventPriority.LOWEST) public void onRender(GuiScreenEvent.DrawScreenEvent.Post event) { - if (!(MC.currentScreen instanceof GuiContainer)) return; - + if (!(MC.currentScreen instanceof GuiContainer)) { + return; + } + cacheLock.lock(); try { GuiContainer gui = (GuiContainer) event.getGui(); - + if (!isLocked()) { // show stats for the item being hovered over Slot slotUnder = gui.getSlotUnderMouse(); if (slotUnder == null - || !slotUnder.getHasStack() - || slotUnder.getStack().isEmpty() - || !(slotUnder.getStack().getItem() instanceof ItemShulkerBox)) + || !slotUnder.getHasStack() + || slotUnder.getStack().isEmpty() + || !(slotUnder.getStack().getItem() instanceof ItemShulkerBox)) { setInCache(CACHE_HOVERING_INDEX, null); - else if (!ItemStack.areItemStacksEqual( - getInCache(0).map(GuiShulkerViewer::getParentShulker).orElse(ItemStack.EMPTY), - slotUnder.getStack())) + } else if (!ItemStack.areItemStacksEqual( + getInCache(0).map(GuiShulkerViewer::getParentShulker).orElse(ItemStack.EMPTY), + slotUnder.getStack())) { setInCache(CACHE_HOVERING_INDEX, newShulkerGui(slotUnder.getStack(), 1)); - + } + // show stats for held item ItemStack stackHeld = LocalPlayerInventory.getInventory().getItemStack(); - if (stackHeld.isEmpty() || !(stackHeld.getItem() instanceof ItemShulkerBox)) + if (stackHeld.isEmpty() || !(stackHeld.getItem() instanceof ItemShulkerBox)) { setInCache(CACHE_HOLDING_INDEX, null); - else if (!ItemStack.areItemStacksEqual( - getInCache(1).map(GuiShulkerViewer::getParentShulker).orElse(ItemStack.EMPTY), - stackHeld)) setInCache(CACHE_HOLDING_INDEX, newShulkerGui(stackHeld, 0)); - - if (locked && !updated && guiCache.stream().anyMatch(Objects::nonNull)) updated = true; + } else if (!ItemStack.areItemStacksEqual( + getInCache(1).map(GuiShulkerViewer::getParentShulker).orElse(ItemStack.EMPTY), + stackHeld)) { + setInCache(CACHE_HOLDING_INDEX, newShulkerGui(stackHeld, 0)); + } + + if (locked && !updated && guiCache.stream().anyMatch(Objects::nonNull)) { + updated = true; + } } - + AtomicInteger renderX; AtomicInteger renderY; if (!isLocked() || (lastX == -1 && lastY == -1)) { int count = (int) guiCache.stream().filter(Objects::nonNull).count(); renderX = new AtomicInteger(lastX = event.getMouseX() + x_offset.get()); renderY = - new AtomicInteger( - lastY = event.getMouseY() - (SHULKER_GUI_SIZE * count) / 2 + y_offset.get()); + new AtomicInteger( + lastY = event.getMouseY() - (SHULKER_GUI_SIZE * count) / 2 + y_offset.get()); } else { renderX = new AtomicInteger(lastX); renderY = new AtomicInteger(lastY); } - + isMouseInShulkerGui = false; // recheck - + guiCache - .stream() - .filter(Objects::nonNull) - .sorted() - .forEach( - ui -> { - ui.posX = renderX.get(); - ui.posY = renderY.get(); - ui.drawScreen(event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks()); - renderY.set(renderY.get() + SHULKER_GUI_SIZE + 1); - }); + .stream() + .filter(Objects::nonNull) + .sorted() + .forEach( + ui -> { + ui.posX = renderX.get(); + ui.posY = renderY.get(); + ui.drawScreen(event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks()); + renderY.set(renderY.get() + SHULKER_GUI_SIZE + 1); + }); } finally { cacheLock.unlock(); } - + if (help_text.get()) { ScaledResolution resolution = new ScaledResolution(MC); GlStateManager.disableLighting(); GlStateManager.disableDepth(); SurfaceHelper.drawTextShadow( - "Hold " - + Keyboard.getKeyName(lockDownKey.getKeyCode()) - + " to view the tooltips of a Shulker boxes content!", - 5, - resolution.getScaledHeight() - (int) (SurfaceHelper.getStringHeight(null) + 2) * 3 - 2, - Colors.RED.toBuffer(), - 1); + "Hold " + + Keyboard.getKeyName(lockDownKey.getKeyCode()) + + " to view the tooltips of a Shulker boxes content!", + 5, + resolution.getScaledHeight() - (int) (SurfaceHelper.getStringHeight(null) + 2) * 3 - 2, + Colors.RED.toBuffer(), + 1); SurfaceHelper.drawTextShadow( - "The activation key can be configured under Minecraft's Options -> Controls -> ForgeHax -> ShulkerViewer Lock.", - 5, - resolution.getScaledHeight() - (int) (SurfaceHelper.getStringHeight(null) + 2) * 2 - 2, - Colors.GREEN.toBuffer(), - 1); + "The activation key can be configured under Minecraft's Options -> Controls -> ForgeHax -> ShulkerViewer Lock.", + 5, + resolution.getScaledHeight() - (int) (SurfaceHelper.getStringHeight(null) + 2) * 2 - 2, + Colors.GREEN.toBuffer(), + 1); SurfaceHelper.drawTextShadow( - "Type in chat \"" - + ChatCommandService.getActivationCharacter() - + getModName() - + "\" for more options, and \"" - + ChatCommandService.getActivationCharacter() - + getModName() - + " " - + help_text.getName() - + " false\" to disable this help message.", - 5, - resolution.getScaledHeight() - (int) (SurfaceHelper.getStringHeight(null) + 2) - 2, - Colors.YELLOW.toBuffer(), - 1); + "Type in chat \"" + + ChatCommandService.getActivationCharacter() + + getModName() + + "\" for more options, and \"" + + ChatCommandService.getActivationCharacter() + + getModName() + + " " + + help_text.getName() + + " false\" to disable this help message.", + 5, + resolution.getScaledHeight() - (int) (SurfaceHelper.getStringHeight(null) + 2) - 2, + Colors.YELLOW.toBuffer(), + 1); GlStateManager.enableDepth(); } - + GlStateManager.enableLighting(); GlStateManager.color(1.f, 1.f, 1.f, 1.0f); } - + class GuiShulkerViewer extends GuiContainer implements Comparable { + private final ItemStack parentShulker; private final int priority; - + public int posX = 0; public int posY = 0; - + public GuiShulkerViewer(Container inventorySlotsIn, ItemStack parentShulker, int priority) { super(inventorySlotsIn); this.parentShulker = parentShulker; @@ -383,53 +406,53 @@ public GuiShulkerViewer(Container inventorySlotsIn, ItemStack parentShulker, int this.xSize = 176; this.ySize = SHULKER_GUI_SIZE; } - + public ItemStack getParentShulker() { return parentShulker; } - + public int getPosX() { return posX; } - + public int getPosY() { return posY; } - + public int getWidth() { return xSize; } - + public int getHeight() { return ySize; } - + @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { final int DEPTH = 500; - + int x = posX; int y = posY; - + GlStateManager.enableTexture2D(); GlStateManager.disableLighting(); GlStateManager.color( - 1.f, - 1.f, - 1.f, - !isLocked() - ? (tooltip_opacity.getAsFloat() / 255.f) - : (locked_opacity.getAsFloat() / 255.f)); - + 1.f, + 1.f, + 1.f, + !isLocked() + ? (tooltip_opacity.getAsFloat() / 255.f) + : (locked_opacity.getAsFloat() / 255.f)); + GlStateManager.enableBlend(); GlStateManager.tryBlendFuncSeparate( - GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, - GlStateManager.SourceFactor.ONE, - GlStateManager.DestFactor.ZERO); - + GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); + MC.getTextureManager().bindTexture(SHULKER_GUI_TEXTURE); - + // width 176 = width of container // height 16 = top of the gui // height 54 = gui item boxes @@ -437,21 +460,21 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { SurfaceHelper.drawTexturedRect(x, y, 0, 0, 176, 16, DEPTH); SurfaceHelper.drawTexturedRect(x, y + 16, 0, 16, 176, 54, DEPTH); SurfaceHelper.drawTexturedRect(x, y + 16 + 54, 0, 160, 176, 6, DEPTH); - + GlStateManager.disableDepth(); SurfaceHelper.drawText(parentShulker.getDisplayName(), x + 8, y + 6, Colors.BLACK.toBuffer()); GlStateManager.enableDepth(); - + RenderHelper.enableGUIStandardItemLighting(); GlStateManager.enableRescaleNormal(); GlStateManager.enableColorMaterial(); GlStateManager.enableLighting(); - + Slot hoveringOver = null; - + int rx = x + 8; int ry = y - 1; - + for (Slot slot : inventorySlots.inventorySlots) { if (slot.getHasStack()) { int px = rx + slot.xPos; @@ -460,26 +483,28 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { SurfaceHelper.drawItem(slot.getStack(), px, py); SurfaceHelper.drawItemOverlay(slot.getStack(), px, py); MC.getRenderItem().zLevel = 0.f; - if (isPointInRegion(px, py, 16, 16, mouseX, mouseY)) hoveringOver = slot; + if (isPointInRegion(px, py, 16, 16, mouseX, mouseY)) { + hoveringOver = slot; + } } } - + GlStateManager.disableLighting(); - + if (hoveringOver != null) { // background of the gui GlStateManager.disableLighting(); GlStateManager.disableDepth(); GlStateManager.colorMask(true, true, true, false); this.drawGradientRect( - rx + hoveringOver.xPos, - ry + hoveringOver.yPos, - rx + hoveringOver.xPos + 16, - ry + hoveringOver.yPos + 16, - -2130706433, - -2130706433); + rx + hoveringOver.xPos, + ry + hoveringOver.yPos, + rx + hoveringOver.xPos + 16, + ry + hoveringOver.yPos + 16, + -2130706433, + -2130706433); GlStateManager.colorMask(true, true, true, true); - + // tool tip GlStateManager.color(1.f, 1.f, 1.f, 1.0f); GlStateManager.pushMatrix(); @@ -489,24 +514,27 @@ public void drawScreen(int mouseX, int mouseY, float partialTicks) { GlStateManager.popMatrix(); GlStateManager.enableDepth(); } - - if (isPointInRegion(this.posX, this.posY, getWidth(), getHeight(), mouseX, mouseY)) + + if (isPointInRegion(this.posX, this.posY, getWidth(), getHeight(), mouseX, mouseY)) { isMouseInShulkerGui = true; - + } + GlStateManager.disableBlend(); GlStateManager.color(1.f, 1.f, 1.f, 1.0f); } - + @Override - protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {} - + protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { + } + @Override public int compareTo(GuiShulkerViewer o) { return Integer.compare(priority, o.priority); } } - + static class ShulkerContainer extends Container { + public ShulkerContainer(ShulkerInventory inventory, int size) { for (int i = 0; i < size; ++i) { int x = i % 9 * 18; @@ -514,100 +542,106 @@ public ShulkerContainer(ShulkerInventory inventory, int size) { addSlotToContainer(new Slot(inventory, i, x, y)); } } - + @Override public boolean canInteractWith(EntityPlayer playerIn) { return false; } } - + static class ShulkerInventory implements IInventory { + private final List contents; - + public ShulkerInventory(List contents) { this.contents = contents; } - + @Override public int getSizeInventory() { return contents.size(); } - + @Override public boolean isEmpty() { return contents.isEmpty(); } - + @Override public ItemStack getStackInSlot(int index) { return contents.get(index); } - + @Override public ItemStack decrStackSize(int index, int count) { throw new UnsupportedOperationException(); } - + @Override public ItemStack removeStackFromSlot(int index) { throw new UnsupportedOperationException(); } - + @Override public void setInventorySlotContents(int index, ItemStack stack) { throw new UnsupportedOperationException(); } - + @Override public int getInventoryStackLimit() { return 27; } - + @Override - public void markDirty() {} - + public void markDirty() { + } + @Override public boolean isUsableByPlayer(EntityPlayer player) { return false; } - + @Override - public void openInventory(EntityPlayer player) {} - + public void openInventory(EntityPlayer player) { + } + @Override - public void closeInventory(EntityPlayer player) {} - + public void closeInventory(EntityPlayer player) { + } + @Override public boolean isItemValidForSlot(int index, ItemStack stack) { return index > 0 && index < contents.size() && contents.get(index).equals(stack); } - + @Override public int getField(int id) { return 0; } - + @Override - public void setField(int id, int value) {} - + public void setField(int id, int value) { + } + @Override public int getFieldCount() { return 0; } - + @Override - public void clear() {} - + public void clear() { + } + @Override public String getName() { return ""; } - + @Override public boolean hasCustomName() { return false; } - + @Override public ITextComponent getDisplayName() { return new TextComponentString(""); diff --git a/src/main/java/com/matt/forgehax/mods/SignTextMod.java b/src/main/java/com/matt/forgehax/mods/SignTextMod.java index bafc10a3d..ff3b054c7 100644 --- a/src/main/java/com/matt/forgehax/mods/SignTextMod.java +++ b/src/main/java/com/matt/forgehax/mods/SignTextMod.java @@ -4,7 +4,7 @@ import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; -import java.awt.*; +import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntitySign; @@ -14,24 +14,29 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.input.Mouse; -/** Created by Babbaj on 9/16/2017. */ +/** + * Created by Babbaj on 9/16/2017. + */ @RegisterMod public class SignTextMod extends ToggleMod { + public SignTextMod() { super(Category.MISC, "SignText", false, "get sign text"); } - + @SubscribeEvent public void onInput(MouseEvent event) { if (event.getButton() == 2 && Mouse.getEventButtonState()) { // on middle click RayTraceResult result = MC.player.rayTrace(999, 0); - if (result == null) return; + if (result == null) { + return; + } if (result.typeOfHit == RayTraceResult.Type.BLOCK) { TileEntity tileEntity = MC.world.getTileEntity(result.getBlockPos()); - + if (tileEntity instanceof TileEntitySign) { TileEntitySign sign = (TileEntitySign) tileEntity; - + int signTextLength = 0; // find the first line from the bottom that isn't empty for (int i = 3; i >= 0; i--) { @@ -40,24 +45,26 @@ public void onInput(MouseEvent event) { break; } } - if (signTextLength == 0) return; // if the sign is empty don't do anything - + if (signTextLength == 0) { + return; // if the sign is empty don't do anything + } + String[] lines = new String[signTextLength]; - + for (int i = 0; i < signTextLength; i++) { lines[i] = - sign.signText[i].getFormattedText().replace(TextFormatting.RESET.toString(), ""); + sign.signText[i].getFormattedText().replace(TextFormatting.RESET.toString(), ""); } - + String fullText = String.join("\n", lines); - + Helper.printMessage("Copied sign"); setClipboardString(fullText); } } } } - + private static void setClipboardString(String stringIn) { StringSelection selection = new StringSelection(stringIn); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null); diff --git a/src/main/java/com/matt/forgehax/mods/SpawnerEspMod.java b/src/main/java/com/matt/forgehax/mods/SpawnerEspMod.java index f47657f58..c61781f16 100644 --- a/src/main/java/com/matt/forgehax/mods/SpawnerEspMod.java +++ b/src/main/java/com/matt/forgehax/mods/SpawnerEspMod.java @@ -2,13 +2,13 @@ import static com.matt.forgehax.Helper.getWorld; -import com.github.lunatrius.core.client.renderer.unique.GeometryMasks; -import com.github.lunatrius.core.client.renderer.unique.GeometryTessellator; import com.matt.forgehax.events.RenderEvent; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; +import com.matt.forgehax.util.tesselation.GeometryMasks; +import com.matt.forgehax.util.tesselation.GeometryTessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityMobSpawner; @@ -16,25 +16,28 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.opengl.GL11; -/** Created on 9/29/2016 by fr1kin */ +/** + * Created on 9/29/2016 by fr1kin + */ @RegisterMod public class SpawnerEspMod extends ToggleMod { + public SpawnerEspMod() { super(Category.RENDER, "SpawnerESP", false, "Spawner esp"); } - + @SubscribeEvent public void onRender(RenderEvent event) { event.getBuffer().begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); - + for (TileEntity tileEntity : getWorld().loadedTileEntityList) { if (tileEntity instanceof TileEntityMobSpawner) { BlockPos pos = tileEntity.getPos(); GeometryTessellator.drawCuboid( - event.getBuffer(), pos, GeometryMasks.Line.ALL, Utils.Colors.RED); + event.getBuffer(), pos, GeometryMasks.Line.ALL, Colors.RED.toBuffer()); } } - + event.getTessellator().draw(); } } diff --git a/src/main/java/com/matt/forgehax/mods/StepMod.java b/src/main/java/com/matt/forgehax/mods/StepMod.java index b266ac424..f64d7fffc 100644 --- a/src/main/java/com/matt/forgehax/mods/StepMod.java +++ b/src/main/java/com/matt/forgehax/mods/StepMod.java @@ -1,5 +1,8 @@ package com.matt.forgehax.mods; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getNetworkManager; + import com.google.common.collect.Lists; import com.matt.forgehax.asm.events.PacketEvent; import com.matt.forgehax.events.LocalPlayerUpdateEvent; @@ -8,80 +11,86 @@ import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.Packet; import net.minecraft.network.play.client.CPacketPlayer; import net.minecraft.util.math.AxisAlignedBB; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - -import static com.matt.forgehax.Helper.getLocalPlayer; -import static com.matt.forgehax.Helper.getNetworkManager; - @RegisterMod public class StepMod extends ToggleMod { + public static final float DEFAULT_STEP_HEIGHT = 0.6f; - + public final Setting stepHeight = - getCommandStub() - .builders() - .newSettingBuilder() - .name("height") - .description("how high you can step") - .defaultTo(1.2f) - .min(0f) - .changed(__ -> MC.addScheduledTask(() -> { - if (isEnabled()) { - EntityPlayer player = getLocalPlayer(); - if (player != null) updateStepHeight(player); - } - })) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("height") + .description("how high you can step") + .defaultTo(1.2f) + .min(0f) + .changed(__ -> MC.addScheduledTask(() -> { + if (isEnabled()) { + EntityPlayer player = getLocalPlayer(); + if (player != null) { + updateStepHeight(player); + } + } + })) + .build(); + public final Setting unstep = - getCommandStub() - .builders() - .newSettingBuilder() - .name("unstep") - .description("step down instead of falling") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("unstep") + .description("step down instead of falling") + .defaultTo(false) + .build(); + public StepMod() { super(Category.PLAYER, "Step", false, "Step up blocks"); } - + @Override protected void onEnabled() { EntityPlayer player = getLocalPlayer(); - if (player != null) wasOnGround = player.onGround; + if (player != null) { + wasOnGround = player.onGround; + } } - + @Override public void onDisabled() { EntityPlayer player = getLocalPlayer(); - if (player != null) player.stepHeight = DEFAULT_STEP_HEIGHT; + if (player != null) { + player.stepHeight = DEFAULT_STEP_HEIGHT; + } } - + private void updateStepHeight(EntityPlayer player) { player.stepHeight = player.onGround ? stepHeight.get() : DEFAULT_STEP_HEIGHT; } - + private boolean wasOnGround = false; - + private void unstep(EntityPlayer player) { - AxisAlignedBB range = player.getEntityBoundingBox().expand(0, -stepHeight.get(), 0).contract(0, player.height, 0); - - if (!player.world.collidesWithAnyBlock(range)) return; - + AxisAlignedBB range = player.getEntityBoundingBox().expand(0, -stepHeight.get(), 0) + .contract(0, player.height, 0); + + if (!player.world.collidesWithAnyBlock(range)) { + return; + } + List collisionBoxes = player.world.getCollisionBoxes(player, range); AtomicReference newY = new AtomicReference<>(0D); collisionBoxes.forEach(box -> newY.set(Math.max(newY.get(), box.maxY))); player.setPositionAndUpdate(player.posX, newY.get(), player.posZ); } - + private void updateUnstep(EntityPlayer player) { try { if (unstep.get() && wasOnGround && !player.onGround && player.motionY <= 0) { @@ -91,22 +100,24 @@ private void updateUnstep(EntityPlayer player) { wasOnGround = player.onGround; } } - + @SubscribeEvent public void onLocalPlayerUpdate(LocalPlayerUpdateEvent event) { EntityPlayer player = (EntityPlayer) event.getEntityLiving(); - if (player == null) return; - + if (player == null) { + return; + } + updateStepHeight(player); updateUnstep(player); } - + private CPacketPlayer previousPositionPacket = null; - + @SubscribeEvent public void onPacketSending(PacketEvent.Outgoing.Pre event) { if (event.getPacket() instanceof CPacketPlayer.Position - || event.getPacket() instanceof CPacketPlayer.PositionRotation) { + || event.getPacket() instanceof CPacketPlayer.PositionRotation) { CPacketPlayer packetPlayer = (CPacketPlayer) event.getPacket(); if (previousPositionPacket != null && !PacketHelper.isIgnored(event.getPacket())) { double diffY = packetPlayer.getY(0.f) - previousPositionPacket.getY(0.f); @@ -122,11 +133,11 @@ public void onPacketSending(PacketEvent.Outgoing.Pre event) { sendList.add(new CPacketPlayer.Position(x, y + 0.4199999869D, z, true)); sendList.add(new CPacketPlayer.Position(x, y + 0.7531999805D, z, true)); sendList.add( - new CPacketPlayer.Position( - packetPlayer.getX(0.f), - packetPlayer.getY(0.f), - packetPlayer.getZ(0.f), - packetPlayer.isOnGround())); + new CPacketPlayer.Position( + packetPlayer.getX(0.f), + packetPlayer.getY(0.f), + packetPlayer.getZ(0.f), + packetPlayer.isOnGround())); for (Packet toSend : sendList) { PacketHelper.ignore(toSend); getNetworkManager().sendPacket(toSend); @@ -137,14 +148,14 @@ public void onPacketSending(PacketEvent.Outgoing.Pre event) { previousPositionPacket = (CPacketPlayer) event.getPacket(); } } - + @Override public String getDebugDisplayText() { return String.format( - "%s[%s%s]", - super.getDisplayText(), - stepHeight.get().toString(), - unstep.get() ? "+unstep" : "" + "%s[%s%s]", + super.getDisplayText(), + stepHeight.get().toString(), + unstep.get() ? "+unstep" : "" ); } } diff --git a/src/main/java/com/matt/forgehax/mods/StopEntityUpdates.java b/src/main/java/com/matt/forgehax/mods/StopEntityUpdates.java index 6882ad094..9208a0332 100644 --- a/src/main/java/com/matt/forgehax/mods/StopEntityUpdates.java +++ b/src/main/java/com/matt/forgehax/mods/StopEntityUpdates.java @@ -9,14 +9,15 @@ @RegisterMod public class StopEntityUpdates extends ToggleMod { + public StopEntityUpdates() { super( - Category.MISC, - "StopEntityUpdates", - false, - "Prevent entity metadata update packets from being processed"); + Category.MISC, + "StopEntityUpdates", + false, + "Prevent entity metadata update packets from being processed"); } - + @SubscribeEvent public void onPacketIn(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketEntityMetadata) { diff --git a/src/main/java/com/matt/forgehax/mods/StorageESPMod.java b/src/main/java/com/matt/forgehax/mods/StorageESPMod.java index aed716334..520ccb663 100644 --- a/src/main/java/com/matt/forgehax/mods/StorageESPMod.java +++ b/src/main/java/com/matt/forgehax/mods/StorageESPMod.java @@ -2,72 +2,91 @@ import static com.matt.forgehax.Helper.getWorld; -import com.github.lunatrius.core.client.renderer.unique.GeometryMasks; -import com.github.lunatrius.core.client.renderer.unique.GeometryTessellator; import com.matt.forgehax.events.RenderEvent; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.mod.Category; import com.matt.forgehax.util.mod.ToggleMod; import com.matt.forgehax.util.mod.loader.RegisterMod; +import com.matt.forgehax.util.tesselation.GeometryMasks; +import com.matt.forgehax.util.tesselation.GeometryTessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; import net.minecraft.entity.item.EntityItemFrame; import net.minecraft.entity.item.EntityMinecartChest; import net.minecraft.item.ItemShulkerBox; -import net.minecraft.tileentity.*; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.tileentity.TileEntityDispenser; +import net.minecraft.tileentity.TileEntityEnderChest; +import net.minecraft.tileentity.TileEntityFurnace; +import net.minecraft.tileentity.TileEntityHopper; +import net.minecraft.tileentity.TileEntityShulkerBox; import net.minecraft.util.math.BlockPos; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.opengl.GL11; -/** Created on 9/4/2016 by fr1kin */ +/** + * Created on 9/4/2016 by fr1kin + */ @RegisterMod public class StorageESPMod extends ToggleMod { - + public StorageESPMod() { super(Category.RENDER, "StorageESP", false, "Shows storage"); } - + private int getTileEntityColor(TileEntity tileEntity) { if (tileEntity instanceof TileEntityChest - || tileEntity instanceof TileEntityDispenser - || tileEntity instanceof TileEntityShulkerBox) return Utils.Colors.ORANGE; - else if (tileEntity instanceof TileEntityEnderChest) return Utils.Colors.PURPLE; - else if (tileEntity instanceof TileEntityFurnace) return Utils.Colors.GRAY; - else if (tileEntity instanceof TileEntityHopper) return Utils.Colors.DARK_RED; - else return -1; + || tileEntity instanceof TileEntityDispenser + || tileEntity instanceof TileEntityShulkerBox) { + return Colors.ORANGE.toBuffer(); + } else if (tileEntity instanceof TileEntityEnderChest) { + return Colors.PURPLE.toBuffer(); + } else if (tileEntity instanceof TileEntityFurnace) { + return Colors.GRAY.toBuffer(); + } else if (tileEntity instanceof TileEntityHopper) { + return Colors.DARK_RED.toBuffer(); + } else { + return -1; + } } - + private int getEntityColor(Entity entity) { - if (entity instanceof EntityMinecartChest) return Utils.Colors.ORANGE; - else if (entity instanceof EntityItemFrame - && ((EntityItemFrame) entity).getDisplayedItem().getItem() instanceof ItemShulkerBox) - return Utils.Colors.YELLOW; - else return -1; + if (entity instanceof EntityMinecartChest) { + return Colors.ORANGE.toBuffer(); + } else if (entity instanceof EntityItemFrame + && ((EntityItemFrame) entity).getDisplayedItem().getItem() instanceof ItemShulkerBox) { + return Colors.YELLOW.toBuffer(); + } else { + return -1; + } } - + @SubscribeEvent public void onRender(RenderEvent event) { event.getBuffer().begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); - + for (TileEntity tileEntity : getWorld().loadedTileEntityList) { BlockPos pos = tileEntity.getPos(); - + int color = getTileEntityColor(tileEntity); - if (color != -1) + if (color != -1) { GeometryTessellator.drawCuboid(event.getBuffer(), pos, GeometryMasks.Line.ALL, color); + } } - + for (Entity entity : getWorld().loadedEntityList) { BlockPos pos = entity.getPosition(); int color = getEntityColor(entity); - if (color != -1) + if (color != -1) { GeometryTessellator.drawCuboid( - event.getBuffer(), - entity instanceof EntityItemFrame ? pos.add(0, -1, 0) : pos, - GeometryMasks.Line.ALL, - color); + event.getBuffer(), + entity instanceof EntityItemFrame ? pos.add(0, -1, 0) : pos, + GeometryMasks.Line.ALL, + color); + } } - + event.getTessellator().draw(); } } diff --git a/src/main/java/com/matt/forgehax/mods/TimerMod.java b/src/main/java/com/matt/forgehax/mods/TimerMod.java index 9a1cc4be5..f8500cc70 100644 --- a/src/main/java/com/matt/forgehax/mods/TimerMod.java +++ b/src/main/java/com/matt/forgehax/mods/TimerMod.java @@ -11,82 +11,87 @@ import net.minecraft.util.Timer; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created by Babbaj on 1/24/2018. */ +/** + * Created by Babbaj on 1/24/2018. + */ @RegisterMod public class TimerMod extends ToggleMod { - + public TimerMod() { super(Category.MISC, "Timer", false, "Speed up game time"); } - + public final Setting factor = - getCommandStub() - .builders() - .newSettingBuilder() - .name("speed") - .description("how fast to make the game run") - .defaultTo(1f) - .min(0f) - .success(__ -> { - if (this.isEnabled()) updateTimer(); - }) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("speed") + .description("how fast to make the game run") + .defaultTo(1f) + .min(0f) + .success(__ -> { + if (this.isEnabled()) { + updateTimer(); + } + }) + .build(); + public final Setting tpsSync = - getCommandStub() - .builders() - .newSettingBuilder() - .name("tps-sync") - .description("sync timer to tps") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("tps-sync") + .description("sync timer to tps") + .defaultTo(false) + .build(); + private final float DEFAULT_SPEED = 1000f / 20; // default speed - 50 ms - + @Override public void onEnabled() { updateTimer(); } - + @Override public void onDisabled() { setSpeed(DEFAULT_SPEED); } - + private void updateTimer() { - if (!tpsSync.getAsBoolean()) { - setSpeed(DEFAULT_SPEED / factor.getAsFloat()); - } + if (!tpsSync.getAsBoolean()) { + setSpeed(DEFAULT_SPEED / factor.getAsFloat()); + } } - - @SubscribeEvent - public void onPacketPreceived (PacketEvent.Incoming.Pre event){ - if (event.getPacket() instanceof SPacketTimeUpdate && tpsSync.getAsBoolean()) { - TickRateService.TickRateData data = TickRateService.getTickData(); - if (data.getSampleSize() > 0) { - TickRateService.TickRateData.CalculationData point = data.getPoint(); - setSpeed((float) (DEFAULT_SPEED / (point.getAverage() / 20))); - } - }else { - updateTimer(); - } + + @SubscribeEvent + public void onPacketPreceived(PacketEvent.Incoming.Pre event) { + if (event.getPacket() instanceof SPacketTimeUpdate && tpsSync.getAsBoolean()) { + TickRateService.TickRateData data = TickRateService.getTickData(); + if (data.getSampleSize() > 0) { + TickRateService.TickRateData.CalculationData point = data.getPoint(); + setSpeed((float) (DEFAULT_SPEED / (point.getAverage() / 20))); + } + } else { + updateTimer(); } - + } + private void setSpeed(float value) { Timer timer = FastReflection.Fields.Minecraft_timer.get(MC); FastReflection.Fields.Timer_tickLength.set(timer, value); } - + @Override public String getDisplayText() { - if (tpsSync.getAsBoolean()) { - TickRateService.TickRateData data = TickRateService.getTickData(); - if (data.getSampleSize() > 0) { - TickRateService.TickRateData.CalculationData point = data.getPoint(); - return String.format("%s[%.2f]", super.getDisplayText(), point.getAverage() / 20); - } - }else { - return String.format("%s[%.2f]", super.getDisplayText(), factor.get()); - } return super.getDisplayText(); + if (tpsSync.getAsBoolean()) { + TickRateService.TickRateData data = TickRateService.getTickData(); + if (data.getSampleSize() > 0) { + TickRateService.TickRateData.CalculationData point = data.getPoint(); + return String.format("%s[%.2f]", super.getDisplayText(), point.getAverage() / 20); + } + } else { + return String.format("%s[%.2f]", super.getDisplayText(), factor.get()); + } + return super.getDisplayText(); } } diff --git a/src/main/java/com/matt/forgehax/mods/Tracers.java b/src/main/java/com/matt/forgehax/mods/Tracers.java index c6183ebd4..4a9d2b166 100644 --- a/src/main/java/com/matt/forgehax/mods/Tracers.java +++ b/src/main/java/com/matt/forgehax/mods/Tracers.java @@ -23,252 +23,260 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.opengl.GL11; -/** Created on 8/6/2017 by fr1kin */ +/** + * Created on 8/6/2017 by fr1kin + */ @RegisterMod public class Tracers extends ToggleMod implements Colors { + enum Mode { ARROWS, LINES, BOTH, ; } - + public Tracers() { super(Category.RENDER, "Tracers", false, "See where other players are"); } - + public final Setting mode = - getCommandStub() - .builders() - .newSettingEnumBuilder() - .name("mode") - .description("Tracer drawing mode") - .defaultTo(Mode.ARROWS) - .build(); - + getCommandStub() + .builders() + .newSettingEnumBuilder() + .name("mode") + .description("Tracer drawing mode") + .defaultTo(Mode.ARROWS) + .build(); + public final Setting alpha = - getCommandStub() - .builders() - .newSettingBuilder() - .name("alpha") - .description("Alpha value of the tracer color") - .defaultTo(255) - .min(0) - .max(255) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("alpha") + .description("Alpha value of the tracer color") + .defaultTo(255) + .min(0) + .max(255) + .build(); + public final Setting antialias = - getCommandStub() - .builders() - .newSettingBuilder() - .name("antialias") - .description("Makes lines and triangles more smooth, but may hurt performance") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("antialias") + .description("Makes lines and triangles more smooth, but may hurt performance") + .defaultTo(true) + .build(); + public final Setting players = - getCommandStub() - .builders() - .newSettingBuilder() - .name("players") - .description("trace players") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("players") + .description("trace players") + .defaultTo(true) + .build(); + public final Setting hostile = - getCommandStub() - .builders() - .newSettingBuilder() - .name("hostile") - .description("trace hostile mobs") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("hostile") + .description("trace hostile mobs") + .defaultTo(true) + .build(); + public final Setting neutral = - getCommandStub() - .builders() - .newSettingBuilder() - .name("neutral") - .description("trace neutral mobs") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("neutral") + .description("trace neutral mobs") + .defaultTo(true) + .build(); + public final Setting friendly = - getCommandStub() - .builders() - .newSettingBuilder() - .name("friendly") - .description("trace friendly mobs") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("friendly") + .description("trace friendly mobs") + .defaultTo(true) + .build(); + @SubscribeEvent public void onDrawScreen(Render2DEvent event) { GlStateManager.enableBlend(); GlStateManager.tryBlendFuncSeparate( - GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, - GlStateManager.SourceFactor.ONE, - GlStateManager.DestFactor.ZERO); + GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); GlStateManager.disableTexture2D(); - + if (antialias.get()) { GL11.glEnable(GL11.GL_POLYGON_SMOOTH); GL11.glEnable(GL11.GL_LINE_SMOOTH); } - + final Mode dm = mode.get(); - + final double cx = event.getScreenWidth() / 2.f; final double cy = event.getScreenHeight() / 2.f; - + getWorld() - .loadedEntityList - .stream() - .filter(entity -> !Objects.equals(entity, getLocalPlayer())) - .filter(entity -> entity instanceof EntityLivingBase) - .map(EntityRelations::new) - .filter(er -> !er.getRelationship().equals(MobTypeEnum.INVALID)) - .filter(EntityRelations::isOptionEnabled) - .forEach( - er -> { - Entity entity = er.getEntity(); - MobTypeEnum relationship = er.getRelationship(); - - Vec3d entityPos = - EntityUtils.getInterpolatedEyePos(entity, MC.getRenderPartialTicks()); - Plane screenPos = VectorUtils.toScreen(entityPos); - - Color color = er.getColor().setAlpha(alpha.get()); - GlStateManager.color( - color.getRedAsFloat(), - color.getGreenAsFloat(), - color.getBlueAsFloat(), - color.getAlphaAsFloat()); - - GlStateManager.translate(0, 0, er.getDepth()); - - if (dm.equals(Mode.BOTH) || dm.equals(Mode.ARROWS)) { - if (!screenPos.isVisible()) { - // get position on ellipse - - // dimensions of the ellipse - final double dx = cx - 2; - final double dy = cy - 20; - - // ellipse = x^2/a^2 + y^2/b^2 = 1 - // e = (pos - C) / d - // C = center vector - // d = dimensions - double ex = (screenPos.getX() - cx) / dx; - double ey = (screenPos.getY() - cy) / dy; - - // normalize - // n = u/|u| - double m = Math.abs(Math.sqrt(ex * ex + ey * ey)); - double nx = ex / m; - double ny = ey / m; - - // scale - // p = C + dot(n,d) - double x = cx + nx * dx; - double y = cy + ny * dy; - - // -------------------- - // now rotate triangle - - // point - center - // w = - double wx = x - cx; - double wy = y - cy; - - // u = - double ux = event.getScreenWidth(); - double uy = 0.D; - - // |u| - double mu = Math.sqrt(ux * ux + uy * uy); - // |w| - double mw = Math.sqrt(wx * wx + wy * wy); - - // theta = dot(u,w)/(|u|*|w|) - double ang = Math.toDegrees(Math.acos((ux * wx + uy * wy) / (mu * mw))); - - // don't allow NaN angles - if (ang == Float.NaN) ang = 0; - - // invert - if (y < cy) ang *= -1; - - // normalize - ang = (float) AngleHelper.normalizeInDegrees(ang); - - // -------------------- - - int size = relationship.equals(MobTypeEnum.PLAYER) ? 8 : 5; - - GlStateManager.pushMatrix(); - - GlStateManager.translate(x, y, 0); - GlStateManager.rotate((float) ang, 0.f, 0.f, size / 2.f); - - GlStateManager.color( - color.getRedAsFloat(), - color.getGreenAsFloat(), - color.getBlueAsFloat(), - color.getAlphaAsFloat()); - - GlStateManager.glBegin(GL11.GL_TRIANGLES); - { - GL11.glVertex2d(0, 0); - GL11.glVertex2d(-size, -size); - GL11.glVertex2d(-size, size); - } - GlStateManager.glEnd(); - - GlStateManager.popMatrix(); - } + .loadedEntityList + .stream() + .filter(entity -> !Objects.equals(entity, getLocalPlayer())) + .filter(entity -> entity instanceof EntityLivingBase) + .map(EntityRelations::new) + .filter(er -> !er.getRelationship().equals(MobTypeEnum.INVALID)) + .filter(EntityRelations::isOptionEnabled) + .forEach( + er -> { + Entity entity = er.getEntity(); + MobTypeEnum relationship = er.getRelationship(); + + Vec3d entityPos = + EntityUtils.getInterpolatedEyePos(entity, MC.getRenderPartialTicks()); + Plane screenPos = VectorUtils.toScreen(entityPos); + + Color color = er.getColor().setAlpha(alpha.get()); + GlStateManager.color( + color.getRedAsFloat(), + color.getGreenAsFloat(), + color.getBlueAsFloat(), + color.getAlphaAsFloat()); + + GlStateManager.translate(0, 0, er.getDepth()); + + if (dm.equals(Mode.BOTH) || dm.equals(Mode.ARROWS)) { + if (!screenPos.isVisible()) { + // get position on ellipse + + // dimensions of the ellipse + final double dx = cx - 2; + final double dy = cy - 20; + + // ellipse = x^2/a^2 + y^2/b^2 = 1 + // e = (pos - C) / d + // C = center vector + // d = dimensions + double ex = (screenPos.getX() - cx) / dx; + double ey = (screenPos.getY() - cy) / dy; + + // normalize + // n = u/|u| + double m = Math.abs(Math.sqrt(ex * ex + ey * ey)); + double nx = ex / m; + double ny = ey / m; + + // scale + // p = C + dot(n,d) + double x = cx + nx * dx; + double y = cy + ny * dy; + + // -------------------- + // now rotate triangle + + // point - center + // w = + double wx = x - cx; + double wy = y - cy; + + // u = + double ux = event.getScreenWidth(); + double uy = 0.D; + + // |u| + double mu = Math.sqrt(ux * ux + uy * uy); + // |w| + double mw = Math.sqrt(wx * wx + wy * wy); + + // theta = dot(u,w)/(|u|*|w|) + double ang = Math.toDegrees(Math.acos((ux * wx + uy * wy) / (mu * mw))); + + // don't allow NaN angles + if (ang == Float.NaN) { + ang = 0; } - - if (dm.equals(Mode.BOTH) || dm.equals(Mode.LINES)) { - GlStateManager.glBegin(GL11.GL_LINES); - { - GL11.glVertex2d(cx, cy); - GL11.glVertex2d(screenPos.getX(), screenPos.getY()); - } - GlStateManager.glEnd(); + + // invert + if (y < cy) { + ang *= -1; } - - GlStateManager.translate(0, 0, -er.getDepth()); - }); - + + // normalize + ang = (float) AngleHelper.normalizeInDegrees(ang); + + // -------------------- + + int size = relationship.equals(MobTypeEnum.PLAYER) ? 8 : 5; + + GlStateManager.pushMatrix(); + + GlStateManager.translate(x, y, 0); + GlStateManager.rotate((float) ang, 0.f, 0.f, size / 2.f); + + GlStateManager.color( + color.getRedAsFloat(), + color.getGreenAsFloat(), + color.getBlueAsFloat(), + color.getAlphaAsFloat()); + + GlStateManager.glBegin(GL11.GL_TRIANGLES); + { + GL11.glVertex2d(0, 0); + GL11.glVertex2d(-size, -size); + GL11.glVertex2d(-size, size); + } + GlStateManager.glEnd(); + + GlStateManager.popMatrix(); + } + } + + if (dm.equals(Mode.BOTH) || dm.equals(Mode.LINES)) { + GlStateManager.glBegin(GL11.GL_LINES); + { + GL11.glVertex2d(cx, cy); + GL11.glVertex2d(screenPos.getX(), screenPos.getY()); + } + GlStateManager.glEnd(); + } + + GlStateManager.translate(0, 0, -er.getDepth()); + }); + GlStateManager.enableTexture2D(); GlStateManager.disableBlend(); - + GL11.glDisable(GL11.GL_POLYGON_SMOOTH); GL11.glDisable(GL11.GL_LINE_SMOOTH); - + GlStateManager.color(1.f, 1.f, 1.f, 1.f); } - + private class EntityRelations implements Comparable { + private final Entity entity; private final MobTypeEnum relationship; - + public EntityRelations(Entity entity) { Objects.requireNonNull(entity); this.entity = entity; this.relationship = EntityUtils.getRelationship(entity); } - + public Entity getEntity() { return entity; } - + public MobTypeEnum getRelationship() { return relationship; } - + public Color getColor() { switch (relationship) { case PLAYER: @@ -281,7 +289,7 @@ public Color getColor() { return GREEN; } } - + public float getDepth() { switch (relationship) { case PLAYER: @@ -294,7 +302,7 @@ public float getDepth() { return 0.f; } } - + public boolean isOptionEnabled() { switch (relationship) { case PLAYER: @@ -307,7 +315,7 @@ public boolean isOptionEnabled() { return friendly.get(); } } - + @Override public int compareTo(EntityRelations o) { return getRelationship().compareTo(o.getRelationship()); diff --git a/src/main/java/com/matt/forgehax/mods/TrajectoryMod.java b/src/main/java/com/matt/forgehax/mods/TrajectoryMod.java index b1faac9d0..db8547d18 100644 --- a/src/main/java/com/matt/forgehax/mods/TrajectoryMod.java +++ b/src/main/java/com/matt/forgehax/mods/TrajectoryMod.java @@ -18,53 +18,56 @@ @RegisterMod public class TrajectoryMod extends ToggleMod { + public TrajectoryMod() { super(Category.RENDER, "Trajectory", false, "Draws projectile trajectory"); } - + @SubscribeEvent public void onRender(RenderEvent event) { Projectile projectile = - Projectile.getProjectileByItemStack(getLocalPlayer().getHeldItemMainhand()); + Projectile.getProjectileByItemStack(getLocalPlayer().getHeldItemMainhand()); if (!projectile.isNull()) { SimulationResult result = - projectile.getSimulatedTrajectoryFromEntity( - getLocalPlayer(), - PositionRotationManager.getState().getRenderServerViewAngles(), - projectile.getForce( - getLocalPlayer().getHeldItemMainhand().getMaxItemUseDuration() - - getLocalPlayer().getItemInUseCount()), - 0); - if (result == null) return; - + projectile.getSimulatedTrajectoryFromEntity( + getLocalPlayer(), + PositionRotationManager.getState().getRenderServerViewAngles(), + projectile.getForce( + getLocalPlayer().getHeldItemMainhand().getMaxItemUseDuration() + - getLocalPlayer().getItemInUseCount()), + 0); + if (result == null) { + return; + } + if (result.getPathTraveled().size() > 1) { event.setTranslation(getLocalPlayer().getPositionVector()); - + GlStateManager.enableDepth(); GlStateManager.glLineWidth(2.0f); - + GL11.glEnable(GL11.GL_LINE_SMOOTH); event.getBuffer().begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); - + Iterator it = result.getPathTraveled().iterator(); Vec3d previous = it.next(); while (it.hasNext()) { Vec3d next = it.next(); event - .getBuffer() - .pos(previous.x, previous.y, previous.z) - .color(255, 255, 255, 255) - .endVertex(); + .getBuffer() + .pos(previous.x, previous.y, previous.z) + .color(255, 255, 255, 255) + .endVertex(); event.getBuffer().pos(next.x, next.y, next.z).color(255, 255, 255, 255).endVertex(); previous = next; } - + event.getTessellator().draw(); GL11.glDisable(GL11.GL_LINE_SMOOTH); - + GlStateManager.glLineWidth(1.0f); GlStateManager.disableDepth(); - + event.resetTranslation(); } } diff --git a/src/main/java/com/matt/forgehax/mods/WaifuESP.java b/src/main/java/com/matt/forgehax/mods/WaifuESP.java index 83110bf2e..93522eb00 100644 --- a/src/main/java/com/matt/forgehax/mods/WaifuESP.java +++ b/src/main/java/com/matt/forgehax/mods/WaifuESP.java @@ -26,28 +26,28 @@ @RegisterMod public class WaifuESP extends ToggleMod { + public WaifuESP() { super(Category.RENDER, "WaifuESP", false, "overlay cute animes over players"); } - + public final Setting noRenderPlayers = - getCommandStub() - .builders() - .newSettingBuilder() - .name("noRenderPlayers") - .description("render other players") - .defaultTo(false) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("noRenderPlayers") + .description("render other players") + .defaultTo(false) + .build(); + // private final ResourceLocation waifu = new ResourceLocation("textures/forgehax/waifu1.png"); private ResourceLocation waifu; - - private final String waifuUrl = - "https://raw.githubusercontent.com/fr1kin/ForgeHax/master/src/main/resources/assets/minecraft/textures/forgehax/waifu1.png"; - + + private final String waifuUrl = "https://raw.githubusercontent.com/forgehax/assets/master/img/waifu_v01.png"; + private final File waifuCache = - Helper.getFileManager().getBaseResolve("cache/waifu.png").toFile(); - + Helper.getFileManager().getBaseResolve("cache/waifu.png").toFile(); + private BufferedImage getImage(T source, ThrowingFunction readFunction) { try { return readFunction.apply(source); @@ -56,87 +56,90 @@ private BufferedImage getImage(T source, ThrowingFunction return null; } } - + private boolean shouldDraw(EntityLivingBase entity) { return (!entity.equals(MC.player) - && EntityUtils.isAlive(entity) - && EntityUtils.isValidEntity(entity) - && (EntityUtils.isPlayer(entity))); + && EntityUtils.isAlive(entity) + && EntityUtils.isValidEntity(entity) + && (EntityUtils.isPlayer(entity))); } - + @SubscribeEvent(priority = EventPriority.LOWEST) public void onRenderGameOverlayEvent(RenderGameOverlayEvent.Text event) { - if (waifu == null) return; - + if (waifu == null) { + return; + } + for (Entity entity : MC.world.loadedEntityList) { if (EntityUtils.isLiving(entity) && shouldDraw((EntityLivingBase) entity)) { EntityLivingBase living = (EntityLivingBase) (entity); Vec3d bottomVec = EntityUtils.getInterpolatedPos(living, event.getPartialTicks()); Vec3d topVec = - bottomVec.add(new Vec3d(0, (entity.getRenderBoundingBox().maxY - entity.posY), 0)); + bottomVec.add(new Vec3d(0, (entity.getRenderBoundingBox().maxY - entity.posY), 0)); VectorUtils.ScreenPos top = VectorUtils._toScreen(topVec.x, topVec.y, topVec.z); VectorUtils.ScreenPos bot = VectorUtils._toScreen(bottomVec.x, bottomVec.y, bottomVec.z); if (top.isVisible || bot.isVisible) { - + int height = (bot.y - top.y); int width = height; - + int x = - (int) (top.x - (width / 1.8)); // normally 2.0 but lowering it shifts it to the left + (int) (top.x - (width / 1.8)); // normally 2.0 but lowering it shifts it to the left int y = top.y; - + // draw waifu MC.renderEngine.bindTexture(waifu); - + GlStateManager.color(255, 255, 255); Gui.drawScaledCustomSizeModalRect( - x, y, 0, 0, width, height, width, height, width, height); + x, y, 0, 0, width, height, width, height, width, height); } } } } - + @SubscribeEvent public void onRenderPlayer(RenderPlayerEvent.Pre event) { if (noRenderPlayers.getAsBoolean() && !event.getEntity().equals(MC.player)) { event.setCanceled(true); } } - + @Override public void onLoad() { MC.addScheduledTask( - () -> { - try { - BufferedImage image; - if (waifuCache.exists()) { // TODO: download async - image = getImage(waifuCache, ImageIO::read); // from cache - } else { - image = getImage(new URL(waifuUrl), ImageIO::read); // from internet - if (image != null) { - try { - ImageIO.write(image, "png", waifuCache); - } catch (IOException ex) { - ex.printStackTrace(); - } + () -> { + try { + BufferedImage image; + if (waifuCache.exists()) { // TODO: download async + image = getImage(waifuCache, ImageIO::read); // from cache + } else { + image = getImage(new URL(waifuUrl), ImageIO::read); // from internet + if (image != null) { + try { + ImageIO.write(image, "png", waifuCache); + } catch (IOException ex) { + ex.printStackTrace(); } } - if (image == null) { - LOGGER.warn("Failed to download waifu image"); - return; - } - - DynamicTexture dynamicTexture = new DynamicTexture(image); - dynamicTexture.loadTexture(MC.getResourceManager()); - waifu = MC.getTextureManager().getDynamicTextureLocation("WAIFU", dynamicTexture); - } catch (Exception e) { - e.printStackTrace(); } - }); + if (image == null) { + LOGGER.warn("Failed to download waifu image"); + return; + } + + DynamicTexture dynamicTexture = new DynamicTexture(image); + dynamicTexture.loadTexture(MC.getResourceManager()); + waifu = MC.getTextureManager().getDynamicTextureLocation("WAIFU", dynamicTexture); + } catch (Exception e) { + e.printStackTrace(); + } + }); } - + @FunctionalInterface private interface ThrowingFunction { + R apply(T obj) throws IOException; } } diff --git a/src/main/java/com/matt/forgehax/mods/XrayMod.java b/src/main/java/com/matt/forgehax/mods/XrayMod.java index 986cbe532..7e3f73245 100644 --- a/src/main/java/com/matt/forgehax/mods/XrayMod.java +++ b/src/main/java/com/matt/forgehax/mods/XrayMod.java @@ -18,28 +18,29 @@ @RegisterMod public class XrayMod extends ToggleMod { + public final Setting opacity = - getCommandStub() - .builders() - .newSettingBuilder() - .name("opacity") - .description("Xray opacity") - .defaultTo(150) - .min(0) - .max(255) - .changed( - cb -> { - ForgeHaxHooks.COLOR_MULTIPLIER_ALPHA = (cb.getTo().floatValue() / 255.f); - reloadChunks(); - }) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("opacity") + .description("Xray opacity") + .defaultTo(150) + .min(0) + .max(255) + .changed( + cb -> { + ForgeHaxHooks.COLOR_MULTIPLIER_ALPHA = (cb.getTo().floatValue() / 255.f); + reloadChunks(); + }) + .build(); + private boolean previousForgeLightPipelineEnabled = false; - + public XrayMod() { super(Category.WORLD, "Xray", false, "See blocks through walls"); } - + @Override public void onEnabled() { previousForgeLightPipelineEnabled = ForgeModContainer.forgeLightPipelineEnabled; @@ -49,7 +50,7 @@ public void onEnabled() { reloadChunks(); ForgeHaxHooks.SHOULD_DISABLE_CAVE_CULLING.enable("Xray"); } - + @Override public void onDisabled() { ForgeModContainer.forgeLightPipelineEnabled = previousForgeLightPipelineEnabled; @@ -57,9 +58,9 @@ public void onDisabled() { reloadChunks(); ForgeHaxHooks.SHOULD_DISABLE_CAVE_CULLING.disable("Xray"); } - + private boolean isInternalCall = false; - + @SubscribeEvent public void onPreRenderBlockLayer(RenderBlockLayerEvent.Pre event) { if (!isInternalCall) { @@ -70,27 +71,28 @@ public void onPreRenderBlockLayer(RenderBlockLayerEvent.Pre event) { Entity renderEntity = MC.getRenderViewEntity(); GlStateManager.disableAlpha(); MC.renderGlobal.renderBlockLayer( - BlockRenderLayer.SOLID, event.getPartialTicks(), 0, renderEntity); + BlockRenderLayer.SOLID, event.getPartialTicks(), 0, renderEntity); GlStateManager.enableAlpha(); MC.renderGlobal.renderBlockLayer( - BlockRenderLayer.CUTOUT_MIPPED, event.getPartialTicks(), 0, renderEntity); + BlockRenderLayer.CUTOUT_MIPPED, event.getPartialTicks(), 0, renderEntity); MC.getTextureManager() - .getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE) - .setBlurMipmap(false, false); + .getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE) + .setBlurMipmap(false, false); MC.renderGlobal.renderBlockLayer( - BlockRenderLayer.CUTOUT, event.getPartialTicks(), 0, renderEntity); + BlockRenderLayer.CUTOUT, event.getPartialTicks(), 0, renderEntity); MC.getTextureManager() - .getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE) - .restoreLastBlurMipmap(); + .getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE) + .restoreLastBlurMipmap(); GlStateManager.disableAlpha(); isInternalCall = false; } } } - + @SubscribeEvent - public void onPostRenderBlockLayer(RenderBlockLayerEvent.Post event) {} - + public void onPostRenderBlockLayer(RenderBlockLayerEvent.Post event) { + } + @SubscribeEvent public void onRenderBlockInLayer(RenderBlockInLayerEvent event) { if (event.getCompareToLayer().equals(BlockRenderLayer.TRANSLUCENT)) { diff --git a/src/main/java/com/matt/forgehax/mods/YawLockMod.java b/src/main/java/com/matt/forgehax/mods/YawLockMod.java index 298986e4f..e7f23802b 100644 --- a/src/main/java/com/matt/forgehax/mods/YawLockMod.java +++ b/src/main/java/com/matt/forgehax/mods/YawLockMod.java @@ -16,78 +16,81 @@ @RegisterMod public class YawLockMod extends ToggleMod - implements PositionRotationManager.MovementUpdateListener { + implements PositionRotationManager.MovementUpdateListener { + public final Setting auto = - getCommandStub() - .builders() - .newSettingBuilder() - .name("auto") - .description("Automatically finds angle to snap to based on the direction you're facing") - .defaultTo(true) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("auto") + .description("Automatically finds angle to snap to based on the direction you're facing") + .defaultTo(true) + .build(); + public final Setting angle = - getCommandStub() - .builders() - .newSettingBuilder() - .name("angle") - .description("Angle to snap too") - .defaultTo(0.0D) - .min(-180D) - .max(180D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("angle") + .description("Angle to snap too") + .defaultTo(0.0D) + .min(-180D) + .max(180D) + .build(); + public YawLockMod() { super(Category.PLAYER, "YawLock", false, "Locks yaw to prevent moving into walls"); } - + private double getYawDirection() { return (int) (Math.round((LocalPlayerUtils.getViewAngles().getYaw() + 1.f) / 45.f) * 45.f); } - + private Angle getSnapAngle() { return Angle.degrees( - LocalPlayerUtils.getViewAngles().getPitch(), - auto.get() ? getYawDirection() : angle.get()) - .normalize(); + LocalPlayerUtils.getViewAngles().getPitch(), + auto.get() ? getYawDirection() : angle.get()) + .normalize(); } - + @Override protected void onLoad() { getCommandStub() - .builders() - .newCommandBuilder() - .name("snap") - .description("Snap once to a certain direction") - .processor( - data -> { - if (getLocalPlayer() == null || getWorld() == null) return; - - final double angle = - data.getArgumentCount() == 0 - ? getYawDirection() - : AngleHelper.normalizeInDegrees( - SafeConverter.toDouble(data.getArgumentAsString(0))); - - PositionRotationManager.getManager() - .registerTemporary( - state -> - state.setViewAngles( - Angle.degrees(state.getClientAngles().getPitch(), angle))); - }) - .build(); + .builders() + .newCommandBuilder() + .name("snap") + .description("Snap once to a certain direction") + .processor( + data -> { + if (getLocalPlayer() == null || getWorld() == null) { + return; + } + + final double angle = + data.getArgumentCount() == 0 + ? getYawDirection() + : AngleHelper.normalizeInDegrees( + SafeConverter.toDouble(data.getArgumentAsString(0))); + + PositionRotationManager.getManager() + .registerTemporary( + state -> + state.setViewAngles( + Angle.degrees(state.getClientAngles().getPitch(), angle))); + }) + .build(); } - + @Override protected void onEnabled() { PositionRotationManager.getManager().register(this); } - + @Override protected void onDisabled() { PositionRotationManager.getManager().unregister(this); } - + @Override public void onLocalPlayerMovementUpdate(RotationState.Local state) { state.setClientAngles(getSnapAngle()); diff --git a/src/main/java/com/matt/forgehax/mods/commands/BlocksCommand.java b/src/main/java/com/matt/forgehax/mods/commands/BlocksCommand.java index ff0942304..cc6dc8f06 100644 --- a/src/main/java/com/matt/forgehax/mods/commands/BlocksCommand.java +++ b/src/main/java/com/matt/forgehax/mods/commands/BlocksCommand.java @@ -8,9 +8,12 @@ import java.util.concurrent.atomic.AtomicBoolean; import net.minecraft.block.Block; -/** Created on 5/27/2017 by fr1kin */ +/** + * Created on 5/27/2017 by fr1kin + */ @RegisterMod public class BlocksCommand extends CommandMod { + public BlocksCommand() { super("BlocksCommand"); } @@ -18,52 +21,52 @@ public BlocksCommand() { @RegisterCommand public Command blocks(CommandBuilders builders) { return builders - .newCommandBuilder() - .name("blocks") - .description("Find block(s) with matching name") - .processor( - data -> { - data.requiredArguments(1); - final String find = data.getArgumentAsString(0).toLowerCase(); - final StringBuilder builder = new StringBuilder("Search results:\n"); - Block.REGISTRY.forEach( - block -> { - final int id = Block.getIdFromBlock(block); - final boolean resourceMatches = - block.getRegistryName() != null - && block.getRegistryName().toString().toLowerCase().contains(find); - final AtomicBoolean addedResource = new AtomicBoolean(resourceMatches); - BlockOptionHelper.getAllBlocks(block) - .forEach( - stack -> { - String localized = stack.getDisplayName(); - String unlocalized = stack.getUnlocalizedName(); - if (resourceMatches - || unlocalized.toLowerCase().contains(find) - || localized.toLowerCase().contains(find)) { - if (addedResource.compareAndSet(false, true)) { - builder.append( - String.format( - "[%03d:%02d] ", - id, block.getMetaFromState(block.getDefaultState()))); - builder.append( - block.getRegistryName() != null - ? block.getRegistryName().toString() - : block.getLocalizedName()); - builder.append('\n'); - } - builder.append( - String.format("[%03d:%02d]> ", id, stack.getMetadata())); - builder.append(localized); - builder.append(" | "); - builder.append(unlocalized); - builder.append('\n'); - } - }); + .newCommandBuilder() + .name("blocks") + .description("Find block(s) with matching name") + .processor( + data -> { + data.requiredArguments(1); + final String find = data.getArgumentAsString(0).toLowerCase(); + final StringBuilder builder = new StringBuilder("Search results:\n"); + Block.REGISTRY.forEach( + block -> { + final int id = Block.getIdFromBlock(block); + final boolean resourceMatches = + block.getRegistryName() != null + && block.getRegistryName().toString().toLowerCase().contains(find); + final AtomicBoolean addedResource = new AtomicBoolean(resourceMatches); + BlockOptionHelper.getAllBlocks(block) + .forEach( + stack -> { + String localized = stack.getDisplayName(); + String unlocalized = stack.getUnlocalizedName(); + if (resourceMatches + || unlocalized.toLowerCase().contains(find) + || localized.toLowerCase().contains(find)) { + if (addedResource.compareAndSet(false, true)) { + builder.append( + String.format( + "[%03d:%02d] ", + id, block.getMetaFromState(block.getDefaultState()))); + builder.append( + block.getRegistryName() != null + ? block.getRegistryName().toString() + : block.getLocalizedName()); + builder.append('\n'); + } + builder.append( + String.format("[%03d:%02d]> ", id, stack.getMetadata())); + builder.append(localized); + builder.append(" | "); + builder.append(unlocalized); + builder.append('\n'); + } }); - data.write(builder.toString()); - data.markSuccess(); - }) - .build(); + }); + data.write(builder.toString()); + data.markSuccess(); + }) + .build(); } } diff --git a/src/main/java/com/matt/forgehax/mods/commands/ClipCommand.java b/src/main/java/com/matt/forgehax/mods/commands/ClipCommand.java index 13fe7d248..e71127ae4 100644 --- a/src/main/java/com/matt/forgehax/mods/commands/ClipCommand.java +++ b/src/main/java/com/matt/forgehax/mods/commands/ClipCommand.java @@ -2,7 +2,6 @@ import static com.matt.forgehax.Helper.getLocalPlayer; import static com.matt.forgehax.Helper.getNetworkManager; -import static com.matt.forgehax.Helper.getRidingEntity; import static com.matt.forgehax.Helper.getRidingOrPlayer; import static com.matt.forgehax.Helper.getWorld; import static com.matt.forgehax.Helper.printWarning; @@ -19,7 +18,9 @@ import net.minecraft.network.play.client.CPacketVehicleMove; import net.minecraft.util.math.Vec3d; -/** Created by Babbaj on 4/12/2018. */ +/** + * Created by Babbaj on 4/12/2018. + */ @RegisterMod public class ClipCommand extends CommandMod { @@ -33,8 +34,8 @@ private void setPosition(double x, double y, double z) { local.setPositionAndUpdate(x, y, z); if (local instanceof EntityPlayerSP) { getNetworkManager() - .sendPacket( - new CPacketPlayer.Position(local.posX, local.posY, local.posZ, MC.player.onGround)); + .sendPacket( + new CPacketPlayer.Position(local.posX, local.posY, local.posZ, MC.player.onGround)); } else { getNetworkManager().sendPacket(new CPacketVehicleMove(local)); } @@ -49,88 +50,93 @@ private void offsetY(double yOffset) { @RegisterCommand public Command clip(CommandBuilders builders) { return builders - .newCommandBuilder() - .name("clip") - .description("Teleport vertically") - // .requiredArgs(1) - .processor( - data -> { - try { - switch (data.getArgumentCount()) { - case 1: { - final double y = Double.parseDouble(data.getArgumentAsString(0)); - MC.addScheduledTask(() -> { - if (getWorld() == null || getLocalPlayer() == null) - return; - - Entity local = getRidingOrPlayer(); - if (local == null) - return; - - setPosition(0, local.posY + y, 0); - }); - break; + .newCommandBuilder() + .name("clip") + .description("Teleport vertically") + // .requiredArgs(1) + .processor( + data -> { + try { + switch (data.getArgumentCount()) { + case 1: { + final double y = Double.parseDouble(data.getArgumentAsString(0)); + MC.addScheduledTask(() -> { + if (getWorld() == null || getLocalPlayer() == null) { + return; } - case 3: { - final double x = Double.parseDouble(data.getArgumentAsString(0)); - final double y = Double.parseDouble(data.getArgumentAsString(1)); - final double z = Double.parseDouble(data.getArgumentAsString(2)); - MC.addScheduledTask(() -> { - if (getWorld() == null || getLocalPlayer() == null) - return; - - Entity local = getRidingOrPlayer(); - if (local == null) - return; - - setPosition(local.posX + x, local.posY + y, local.posZ + z); - }); - break; + + Entity local = getRidingOrPlayer(); + if (local == null) { + return; + } + + setPosition(0, local.posY + y, 0); + }); + break; + } + case 3: { + final double x = Double.parseDouble(data.getArgumentAsString(0)); + final double y = Double.parseDouble(data.getArgumentAsString(1)); + final double z = Double.parseDouble(data.getArgumentAsString(2)); + MC.addScheduledTask(() -> { + if (getWorld() == null || getLocalPlayer() == null) { + return; + } + + Entity local = getRidingOrPlayer(); + if (local == null) { + return; } - default: - Helper.printMessage("Invalid number of arguments: expected 1 or 3"); - } - } catch (NumberFormatException e) { - Helper.printMessage("Failed to parse input"); + + setPosition(local.posX + x, local.posY + y, local.posZ + z); + }); + break; } - }) - .build(); + default: + Helper.printMessage("Invalid number of arguments: expected 1 or 3"); + } + } catch (NumberFormatException e) { + Helper.printMessage("Failed to parse input"); + } + }) + .build(); } @RegisterCommand public Command vclip(CommandBuilders builders) { return builders.newCommandBuilder() - .name("vclip") - .description("Vertical clip") - .requiredArgs(1) - .processor(data -> { - if(getWorld() == null || getLocalPlayer() == null) { - printWarning("Not in game"); - return; - } - final double y = SafeConverter.toDouble(data.getArgumentAsString(0)); - MC.addScheduledTask(() -> offsetY(y)); - }) - .build(); + .name("vclip") + .description("Vertical clip") + .requiredArgs(1) + .processor(data -> { + if (getWorld() == null || getLocalPlayer() == null) { + printWarning("Not in game"); + return; + } + final double y = SafeConverter.toDouble(data.getArgumentAsString(0)); + MC.addScheduledTask(() -> offsetY(y)); + }) + .build(); } @RegisterCommand public Command forward(CommandBuilders builders) { return builders.newCommandBuilder() - .name("forward") - .description("Forward clip") - .requiredArgs(1) - .processor(data -> { - if(getWorld() == null || getLocalPlayer() == null) { - printWarning("Not in game"); - return; - } - final double units = SafeConverter.toDouble(data.getArgumentAsString(0)); - MC.addScheduledTask(() -> { - Vec3d dir = getLocalPlayer().getLookVec().normalize(); - setPosition(getLocalPlayer().posX + (dir.x * units), getLocalPlayer().posY, getLocalPlayer().posZ + (dir.z * units)); - }); - }) - .build(); + .name("forward") + .description("Forward clip") + .requiredArgs(1) + .processor(data -> { + if (getWorld() == null || getLocalPlayer() == null) { + printWarning("Not in game"); + return; + } + final double units = SafeConverter.toDouble(data.getArgumentAsString(0)); + MC.addScheduledTask(() -> { + Vec3d dir = getLocalPlayer().getLookVec().normalize(); + setPosition(getLocalPlayer().posX + (dir.x * units), getLocalPlayer().posY, + getLocalPlayer().posZ + (dir.z * units)); + }); + }) + .build(); } } diff --git a/src/main/java/com/matt/forgehax/mods/commands/GuiCommand.java b/src/main/java/com/matt/forgehax/mods/commands/GuiCommand.java deleted file mode 100644 index 9cb2a2bd1..000000000 --- a/src/main/java/com/matt/forgehax/mods/commands/GuiCommand.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.matt.forgehax.mods.commands; - -import com.matt.forgehax.util.command.Command; -import com.matt.forgehax.util.command.CommandBuilders; -import com.matt.forgehax.util.gui.mc.MinecraftGuiProxy; -import com.matt.forgehax.util.gui.test.GuiTestMain; -import com.matt.forgehax.util.mod.CommandMod; -import org.lwjgl.input.Keyboard; - -/** Created on 9/12/2017 by fr1kin */ -// @RegisterMod -public class GuiCommand extends CommandMod { - private final MinecraftGuiProxy gui = new MinecraftGuiProxy(new GuiTestMain()); - - private MinecraftGuiProxy getGui() { - return new MinecraftGuiProxy(new GuiTestMain()); // gui; - } - - public GuiCommand() { - super("GuiCommand"); - } - - @RegisterCommand - public Command gui(CommandBuilders builders) { - return builders - .newStubBuilder() - .name("gui") - .description("Forgehax gui") - .bind(Keyboard.KEY_INSERT) - .kpressed(cb -> MC.displayGuiScreen(getGui())) - .build(); - } -} diff --git a/src/main/java/com/matt/forgehax/mods/commands/HelpCommand.java b/src/main/java/com/matt/forgehax/mods/commands/HelpCommand.java index 20e266df5..6dda02b7f 100644 --- a/src/main/java/com/matt/forgehax/mods/commands/HelpCommand.java +++ b/src/main/java/com/matt/forgehax/mods/commands/HelpCommand.java @@ -18,9 +18,12 @@ import javax.annotation.Nullable; import joptsimple.internal.Strings; -/** Created on 6/1/2017 by fr1kin */ +/** + * Created on 6/1/2017 by fr1kin + */ @RegisterMod public class HelpCommand extends CommandMod { + public HelpCommand() { super("HelpCommand"); } @@ -28,209 +31,216 @@ public HelpCommand() { @RegisterCommand public Command save(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("save") - .description("Save all configurations") - .processor(data -> getGlobalCommand().serializeAll()) - .build(); + .newCommandBuilder() + .name("save") + .description("Save all configurations") + .processor(data -> getGlobalCommand().serializeAll()) + .build(); } @RegisterCommand public Command help(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("help") - .description("Help text for mod syntax and command list") - .processor( - data -> { - final StringBuilder build = new StringBuilder(); - build.append("Type \".search \" for list of mods\n"); - build.append("Use -? or --help after command to see command options\n"); - build.append("See the FAQ for details\n"); - build.append("https://github.com/fr1kin/ForgeHax#faq"); - data.write(build.toString()); - data.markSuccess(); - }) - .build(); + .newCommandBuilder() + .name("help") + .description("Help text for mod syntax and command list") + .processor( + data -> { + final StringBuilder build = new StringBuilder(); + build.append("Type \".search \" for list of mods\n"); + build.append("Use -? or --help after command to see command options\n"); + build.append("See the FAQ for details\n"); + build.append("https://github.com/fr1kin/ForgeHax#faq"); + data.write(build.toString()); + data.markSuccess(); + }) + .build(); } @RegisterCommand public Command search(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("search") - .description("Lists all the mods or all the mods containing the given argument") - .options( - parser -> { - parser.acceptsAll(Arrays.asList("details", "d"), "Gives description"); - parser.acceptsAll(Arrays.asList("hidden", "h"), "Show hidden mods"); - }) - .processor( - data -> { - final StringBuilder build = new StringBuilder(); - final String arg = data.getArgumentCount() > 0 ? data.getArgumentAsString(0) : null; - boolean showDetails = data.hasOption("details"); - boolean showHidden = data.hasOption("hidden"); - getGlobalCommand() - .getChildren() - .stream() - .sorted( - (o1, o2) -> String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName())) - .forEach( - command -> { - @Nullable BaseMod mod = getModManager().get(command.getName()).orElse(null); - if ((Strings.isNullOrEmpty(arg) - || command.getName().toLowerCase().contains(arg.toLowerCase())) - && (mod == null || showHidden || !mod.isHidden())) { - build.append(command.getName()); - if (showDetails) { - build.append(" - "); - build.append(command.getDescription()); - } - build.append('\n'); - } - }); - data.write(build.toString()); - data.markSuccess(); - }) - .build(); + .newCommandBuilder() + .name("search") + .description("Lists all the mods or all the mods containing the given argument") + .options( + parser -> { + parser.acceptsAll(Arrays.asList("details", "d"), "Gives description"); + parser.acceptsAll(Arrays.asList("hidden", "h"), "Show hidden mods"); + }) + .processor( + data -> { + final StringBuilder build = new StringBuilder(); + final String arg = data.getArgumentCount() > 0 ? data.getArgumentAsString(0) : null; + boolean showDetails = data.hasOption("details"); + boolean showHidden = data.hasOption("hidden"); + getGlobalCommand() + .getChildren() + .stream() + .sorted( + (o1, o2) -> String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName())) + .forEach( + command -> { + @Nullable BaseMod mod = getModManager().get(command.getName()).orElse(null); + if ((Strings.isNullOrEmpty(arg) + || command.getName().toLowerCase().contains(arg.toLowerCase())) + && (mod == null || showHidden || !mod.isHidden())) { + build.append(command.getName()); + if (showDetails) { + build.append(" - "); + build.append(command.getDescription()); + } + build.append('\n'); + } + }); + data.write(build.toString()); + data.markSuccess(); + }) + .build(); } @RegisterCommand public Command history(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("history") - .description("Lists name history of given player") - .processor( - data -> { - data.requiredArguments(1); - final StringBuilder build = new StringBuilder(); - final String arg = data.getArgumentAsString(0); - final int indents = ConsoleIO.getIndents(); - PlayerInfoHelper.registerWithCallback( - arg, - new FutureCallback() { - @Override - public void onSuccess(@Nullable PlayerInfo result) { - if (result == null) return; - int previousIndents = ConsoleIO.getIndents(); - ConsoleIO.setIndents(indents); - if (result.isOfflinePlayer()) { - ConsoleIO.write( - String.format("\"%s\" is not a registered username", result.getName())); - } else { - if (result.getNameHistory().size() > 1) - ConsoleIO.write( - String.format( - "%s's name history (newest-oldest): %s", - result.getName(), result.getNameHistoryAsString())); - else - ConsoleIO.write( - String.format("%s has never changed their name", result.getName())); - } - ConsoleIO.setIndents(previousIndents); - } - - @Override - public void onFailure(Throwable t) {} - }); - data.write(build.toString()); - data.markSuccess(); - }) - .build(); + .newCommandBuilder() + .name("history") + .description("Lists name history of given player") + .processor( + data -> { + data.requiredArguments(1); + final StringBuilder build = new StringBuilder(); + final String arg = data.getArgumentAsString(0); + final int indents = ConsoleIO.getIndents(); + PlayerInfoHelper.registerWithCallback( + arg, + new FutureCallback() { + @Override + public void onSuccess(@Nullable PlayerInfo result) { + if (result == null) { + return; + } + int previousIndents = ConsoleIO.getIndents(); + ConsoleIO.setIndents(indents); + if (result.isOfflinePlayer()) { + ConsoleIO.write( + String.format("\"%s\" is not a registered username", result.getName())); + } else { + if (result.getNameHistory().size() > 1) { + ConsoleIO.write( + String.format( + "%s's name history (newest-oldest): %s", + result.getName(), result.getNameHistoryAsString())); + } else { + ConsoleIO.write( + String.format("%s has never changed their name", result.getName())); + } + } + ConsoleIO.setIndents(previousIndents); + } + + @Override + public void onFailure(Throwable t) { + } + }); + data.write(build.toString()); + data.markSuccess(); + }) + .build(); } @RegisterCommand public Command loaded(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("loaded") - .description("Loaded plugin list") - .processor( - data -> { - final StringBuilder build = new StringBuilder(); - getModManager() - .getLoadedClasses() - .stream() - .sorted( - (o1, o2) -> - String.CASE_INSENSITIVE_ORDER.compare( - o1.getSimpleName(), o2.getSimpleName())) - .forEach( - clazz -> { - build.append(clazz.getSimpleName()); - build.append('\n'); - }); - data.write(build.toString()); - }) - .build(); + .newCommandBuilder() + .name("loaded") + .description("Loaded plugin list") + .processor( + data -> { + final StringBuilder build = new StringBuilder(); + getModManager() + .getLoadedClasses() + .stream() + .sorted( + (o1, o2) -> + String.CASE_INSENSITIVE_ORDER.compare( + o1.getSimpleName(), o2.getSimpleName())) + .forEach( + clazz -> { + build.append(clazz.getSimpleName()); + build.append('\n'); + }); + data.write(build.toString()); + }) + .build(); } @RegisterCommand public Command online(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("online") - .description("List of online players. Optionally with an argument to match") - .processor( - data -> { - List players = PlayerInfoHelper.getOnlinePlayers(); - - if (players.size() > 0) { - final String match = - data.getArgumentCount() > 0 ? data.getArgumentAsString(0).toLowerCase() : ""; - - StringBuilder str = new StringBuilder(); - str.append(players.size()); - if (match.isEmpty()) str.append(" players online: "); - else { - str.append(" players online matching '"); - str.append(match); - str.append("': "); + .newCommandBuilder() + .name("online") + .description("List of online players. Optionally with an argument to match") + .processor( + data -> { + List players = PlayerInfoHelper.getOnlinePlayers(); + + if (players.size() > 0) { + final String match = + data.getArgumentCount() > 0 ? data.getArgumentAsString(0).toLowerCase() : ""; + + StringBuilder str = new StringBuilder(); + str.append(players.size()); + if (match.isEmpty()) { + str.append(" players online: "); + } else { + str.append(" players online matching '"); + str.append(match); + str.append("': "); + } + players.forEach( + pl -> { + if (match.isEmpty() || pl.getName().toLowerCase().contains(match)) { + str.append(pl.isOfflinePlayer() ? "!" : ""); + str.append(pl.getName()); + str.append(", "); } - players.forEach( - pl -> { - if (match.isEmpty() || pl.getName().toLowerCase().contains(match)) { - str.append(pl.isOfflinePlayer() ? "!" : ""); - str.append(pl.getName()); - str.append(", "); - } - }); - data.write(str.substring(0, str.length() - ", ".length())); - } else { - data.write("No players online."); - } - }) - .build(); + }); + data.write(str.substring(0, str.length() - ", ".length())); + } else { + data.write("No players online."); + } + }) + .build(); } @RegisterCommand public Command respawn(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("respawn") - .description("Send respawn packet") - .processor( - data -> { - if (getLocalPlayer() != null) { - getLocalPlayer().respawnPlayer(); - data.write("Respawn packet sent"); - } else data.write("Failed to send respawn packet (player is null)"); - }) - .build(); + .newCommandBuilder() + .name("respawn") + .description("Send respawn packet") + .processor( + data -> { + if (getLocalPlayer() != null) { + getLocalPlayer().respawnPlayer(); + data.write("Respawn packet sent"); + } else { + data.write("Failed to send respawn packet (player is null)"); + } + }) + .build(); + } + + @RegisterCommand + public Command clearChat(CommandBuilders builders) { + return builders + .newCommandBuilder() + .name("clear") + .description("Clears chat") + .options(p -> p.acceptsAll(Arrays.asList("all", "a"), "Also clear sent message history")) + .processor(d -> MC.addScheduledTask( + () -> MC.ingameGUI.getChatGUI().clearChatMessages(d.hasOption("all"))) + ) + .build(); } - -@RegisterCommand - public Command clearChat(CommandBuilders builders) { - return builders - .newCommandBuilder() - .name("clear") - .description("Clears chat") - .options(p -> p.acceptsAll(Arrays.asList("all", "a"), "Also clear sent message history")) - .processor(d -> MC.addScheduledTask( - () -> MC.ingameGUI.getChatGUI().clearChatMessages(d.hasOption("all"))) - ) - .build(); - } } diff --git a/src/main/java/com/matt/forgehax/mods/commands/MacroCommand.java b/src/main/java/com/matt/forgehax/mods/commands/MacroCommand.java index f99188676..9a7305720 100644 --- a/src/main/java/com/matt/forgehax/mods/commands/MacroCommand.java +++ b/src/main/java/com/matt/forgehax/mods/commands/MacroCommand.java @@ -10,13 +10,22 @@ import com.google.gson.stream.JsonWriter; import com.matt.forgehax.Helper; import com.matt.forgehax.mods.services.ChatCommandService; -import com.matt.forgehax.util.command.*; +import com.matt.forgehax.util.command.Command; +import com.matt.forgehax.util.command.CommandBuilders; +import com.matt.forgehax.util.command.ExecuteData; +import com.matt.forgehax.util.command.Options; import com.matt.forgehax.util.command.exception.CommandExecuteException; import com.matt.forgehax.util.mod.CommandMod; import com.matt.forgehax.util.mod.loader.RegisterMod; import com.matt.forgehax.util.serialization.ISerializableJson; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import javax.annotation.Nullable; import joptsimple.OptionParser; @@ -30,50 +39,50 @@ // TODO: hold macros @RegisterMod public class MacroCommand extends CommandMod { - + public MacroCommand() { super("MacroCommand"); } - + public final Options MACROS = - GLOBAL_COMMAND - .builders() - .newOptionsBuilder() - .name("macros") - .description("Registered macros") - .supplier(ArrayList::new) - .factory(MacroEntry::new) - .build(); - + GLOBAL_COMMAND + .builders() + .newOptionsBuilder() + .name("macros") + .description("Registered macros") + .supplier(ArrayList::new) + .factory(MacroEntry::new) + .build(); + // which command in the list of commands to execute next private final Map macroIndex = new HashMap<>(); - + @SubscribeEvent public void onKeyboardEvent(InputEvent.KeyInputEvent event) { MACROS - .stream() - .filter(macro -> !macro.isAnonymous()) - .filter(macro -> macro.getBind().isPressed()) - .forEach(this::executeMacro); - + .stream() + .filter(macro -> !macro.isAnonymous()) + .filter(macro -> macro.getBind().isPressed()) + .forEach(this::executeMacro); + // execute anonymous macros if (Keyboard.getEventKeyState()) { // on press MACROS - .stream() - .filter(MacroEntry::isAnonymous) - .filter(macro -> macro.getKey() == Keyboard.getEventKey()) - .forEach(this::executeMacro); + .stream() + .filter(MacroEntry::isAnonymous) + .filter(macro -> macro.getKey() == Keyboard.getEventKey()) + .forEach(this::executeMacro); } } - + private void removeMacro(MacroEntry macro) { MACROS.remove(macro); - + if (macro.name.isPresent()) { MC.gameSettings.keyBindings = - ArrayUtils.remove( - MC.gameSettings.keyBindings, - ArrayUtils.indexOf(MC.gameSettings.keyBindings, macro.getBind())); + ArrayUtils.remove( + MC.gameSettings.keyBindings, + ArrayUtils.indexOf(MC.gameSettings.keyBindings, macro.getBind())); } // remove the category if there are no named macros to prevent crash // TODO: fix crash when a category is empty @@ -81,261 +90,273 @@ private void removeMacro(MacroEntry macro) { KeyBinding.getKeybinds().remove("Macros"); } } - + @Override public void onLoad() { super.onLoad(); MACROS.deserializeAll(); - + MACROS - .builders() - .newCommandBuilder() - .name("remove") - .description("Remove a macro (Usage: \".macros remove --name hack (and/or) --key f\") ") - .options(MacroBuilders::keyOption) - .options(MacroBuilders::nameOption) - .processor(data -> { - if (!data.hasOption("key") && !data.hasOption("name")) { - // jopt doesn't seem to allow options to depend on each other - throw new CommandExecuteException("Missing required option(s) [k/key], [n/name]"); - } - - if (data.hasOption("key")) { - // remove by key - final int key = Keyboard.getKeyIndex(data.getOptionAsString("key").toUpperCase()); - MACROS - .stream() - .filter(macro -> macro.getKey() == key) - .peek( - __ -> - Helper.printMessage( - "Removing bind for key \"%s\"", Keyboard.getKeyName(key))) - .forEach(this::removeMacro); - } - if (data.hasOption("name")) { - // remove by name - final String name = data.getOptionAsString("name"); - MACROS - .stream() - .filter(macro -> macro.getName().map(name::equals).orElseGet(name::isEmpty)) - .peek(__ -> Helper.printMessage("Removing bind \"%s\"", name)) - .forEach(this::removeMacro); - } - }) - .build(); - + .builders() + .newCommandBuilder() + .name("remove") + .description("Remove a macro (Usage: \".macros remove --name hack (and/or) --key f\") ") + .options(MacroBuilders::keyOption) + .options(MacroBuilders::nameOption) + .processor(data -> { + if (!data.hasOption("key") && !data.hasOption("name")) { + // jopt doesn't seem to allow options to depend on each other + throw new CommandExecuteException("Missing required option(s) [k/key], [n/name]"); + } + + if (data.hasOption("key")) { + // remove by key + final int key = Keyboard.getKeyIndex(data.getOptionAsString("key").toUpperCase()); + MACROS + .stream() + .filter(macro -> macro.getKey() == key) + .peek( + __ -> + Helper.printMessage( + "Removing bind for key \"%s\"", Keyboard.getKeyName(key))) + .forEach(this::removeMacro); + } + if (data.hasOption("name")) { + // remove by name + final String name = data.getOptionAsString("name"); + MACROS + .stream() + .filter(macro -> macro.getName().map(name::equals).orElseGet(name::isEmpty)) + .peek(__ -> Helper.printMessage("Removing bind \"%s\"", name)) + .forEach(this::removeMacro); + } + }) + .build(); + MACROS - .builders() - .newCommandBuilder() - .name("list") - .description("List all the macros") - .options(MacroBuilders::fullOption) - .processor(data -> { - Helper.printMessage("Macros (%d):", MACROS.size()); - for (MacroEntry macro : MACROS) { - data.write(macro.name.map(name -> '\"' + name + '\"').orElse("anonymous") + ": " + Keyboard.getKeyName(macro.key)); - if (data.hasOption("full")) { - data.incrementIndent(); - data.write(this.rawMacroString(macro)); - data.decrementIndent(); - } + .builders() + .newCommandBuilder() + .name("list") + .description("List all the macros") + .options(MacroBuilders::fullOption) + .processor(data -> { + Helper.printMessage("Macros (%d):", MACROS.size()); + for (MacroEntry macro : MACROS) { + data.write( + macro.name.map(name -> '\"' + name + '\"').orElse("anonymous") + ": " + Keyboard + .getKeyName(macro.key)); + if (data.hasOption("full")) { + data.incrementIndent(); + data.write(this.rawMacroString(macro)); + data.decrementIndent(); } - }) - .build(); + } + }) + .build(); } - + // TODO: split into separate lines if too long private String rawMacroString(MacroEntry macro) { return macro.commands.stream() - .map(nested -> - nested.stream() - .collect(Collectors.joining(";", "(", ")")) - ) - .collect(Collectors.joining(" ")); + .map(nested -> + nested.stream() + .collect(Collectors.joining(";", "(", ")")) + ) + .collect(Collectors.joining(" ")); } - + @Override public void onUnload() { MACROS.serializeAll(); } - + @RegisterCommand public Command executeMacro(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("exec") - .description("Execute a named macro") - .requiredArgs(1) - .processor( - data -> { - final String name = data.getArgumentAsString(0); - final MacroEntry macro = - MACROS - .stream() - .filter(entry -> entry.getName().map(name::equals).orElse(false)) - .findFirst() - .orElseThrow(() -> new CommandExecuteException(String.format("Unknown macro: \"%s\"", name))); - - executeMacro(macro); - }) - .build(); + .newCommandBuilder() + .name("exec") + .description("Execute a named macro") + .requiredArgs(1) + .processor( + data -> { + final String name = data.getArgumentAsString(0); + final MacroEntry macro = + MACROS + .stream() + .filter(entry -> entry.getName().map(name::equals).orElse(false)) + .findFirst() + .orElseThrow( + () -> new CommandExecuteException(String.format("Unknown macro: \"%s\"", name))); + + executeMacro(macro); + }) + .build(); } - + private void executeMacro(MacroEntry macro) { final int currentIndex = Optional.ofNullable(macroIndex.putIfAbsent(macro, 0)).orElse(0); macro.getCommands().get(currentIndex).forEach(ChatCommandService::handleCommand); macroIndex.replace(macro, rotate(currentIndex, 0, macro.getCommands().size() - 1)); } - + private int rotate(int i, int min, int max) { return (i >= max) ? min : i + 1; } - + @RegisterCommand public Command bindMacro(CommandBuilders builder) { return builder - .newCommandBuilder() - .name("bindmacro") - .description("Usage: .bindmacro f \"clip 5; ; ...\" --name cool_macro") - .options(MacroBuilders::nameOption) - .processor(MacroBuilders::parseName) - .processor( - data -> { - data.requiredArguments(2); - final int key = Keyboard.getKeyIndex(data.getArgumentAsString(0).toUpperCase()); - if (data.getOption("name") == null && key == Keyboard.KEY_NONE) { - throw new CommandExecuteException("A macro must have a name and/or a valid key"); - } - - final List> commands = - data.arguments() - .stream() - .skip(1) // skip key - .map(Object::toString) - .map(this::parseCommand) - .collect(Collectors.toList()); - - final MacroEntry macro = - new MacroEntry((String) data.getOption("name"), key, commands); - MACROS - .stream() - .filter(m -> m.getName().isPresent() && m.getName().equals(macro.getName())) - .findFirst() - .ifPresent(alreadyExists -> { - throw new CommandExecuteException(String.format("Command \"%s\" already exists!", alreadyExists.getName().get())); - }); - MACROS.add(macro); - - if (!macro.isAnonymous()) macro.registerBind(); - - Helper.printMessage("Successfully bound to %s", Keyboard.getKeyName(key)); - }) - .build(); + .newCommandBuilder() + .name("bindmacro") + .description("Usage: .bindmacro f \"clip 5; ; ...\" --name cool_macro") + .options(MacroBuilders::nameOption) + .processor(MacroBuilders::parseName) + .processor( + data -> { + data.requiredArguments(2); + final int key = Keyboard.getKeyIndex(data.getArgumentAsString(0).toUpperCase()); + if (data.getOption("name") == null && key == Keyboard.KEY_NONE) { + throw new CommandExecuteException("A macro must have a name and/or a valid key"); + } + + final List> commands = + data.arguments() + .stream() + .skip(1) // skip key + .map(Object::toString) + .map(this::parseCommand) + .collect(Collectors.toList()); + + final MacroEntry macro = + new MacroEntry((String) data.getOption("name"), key, commands); + MACROS + .stream() + .filter(m -> m.getName().isPresent() && m.getName().equals(macro.getName())) + .findFirst() + .ifPresent(alreadyExists -> { + throw new CommandExecuteException( + String.format("Command \"%s\" already exists!", alreadyExists.getName().get())); + }); + MACROS.add(macro); + + if (!macro.isAnonymous()) { + macro.registerBind(); + } + + Helper.printMessage("Successfully bound to %s", Keyboard.getKeyName(key)); + }) + .build(); } - + private ImmutableList parseCommand(String input) { - return ImmutableList.copyOf(Arrays.asList(input.split(";"))); // TODO: don't split semicolons in quotes and allow escaped semicolons + return ImmutableList.copyOf(Arrays.asList( + input.split(";"))); // TODO: don't split semicolons in quotes and allow escaped semicolons } - + public static class MacroEntry implements ISerializableJson { - + private Optional name; private int key = Keyboard.KEY_NONE; private final List> commands = new ArrayList<>(); - + @Nullable // null if this is an anonymous macro (ie !name.isPresent()) private transient KeyBinding bind; - + public MacroEntry(String name) { this.name = name.isEmpty() ? Optional.empty() : Optional.of(name); } - + public MacroEntry(@Nullable String name, int key, List> commands) { this.name = Optional.ofNullable(name); this.key = key; this.commands.addAll(commands); } - + public int getKey() { return Optional.ofNullable(bind).map(KeyBinding::getKeyCode).orElse(this.key); } - + public Optional getName() { return this.name; } - + public boolean isAnonymous() { return !getName().isPresent(); } - + public List> getCommands() { return commands; } - + public KeyBinding getBind() { return this.bind; } - + // only done for named macros private void registerBind() { KeyBinding bind = new KeyBinding(name.get(), this.getKey(), "Macros"); ClientRegistry.registerKeyBinding(bind); // TODO: listen for key pressed for anonymous macros this.bind = bind; } - + @Override public void serialize(JsonWriter writer) throws IOException { writer.beginObject(); writer.name("key"); writer.value(getKey()); - + writer.name("commands"); writer.beginArray(); for (final List list : commands) { writer.beginArray(); - for (final String cmd : list) writer.value(cmd); + for (final String cmd : list) { + writer.value(cmd); + } writer.endArray(); } writer.endArray(); writer.endObject(); } - + @Override public void deserialize(JsonReader reader) throws IOException { JsonObject root = new JsonParser().parse(reader).getAsJsonObject(); this.key = root.get("key").getAsInt(); - + Streams.stream(root.get("commands").getAsJsonArray()) - .map(JsonElement::getAsJsonArray) - .map(jArray -> ImmutableList.copyOf(stringIterator(jArray))) - .forEach(commands::add); - - if (!this.isAnonymous()) this.registerBind(); + .map(JsonElement::getAsJsonArray) + .map(jArray -> ImmutableList.copyOf(stringIterator(jArray))) + .forEach(commands::add); + + if (!this.isAnonymous()) { + this.registerBind(); + } } - + @Override public String toString() { return name.orElse(""); } } - + private static Iterator stringIterator(JsonArray jsonArray) { return Streams.stream(jsonArray).map(JsonElement::getAsString).iterator(); } - + private static class MacroBuilders { + static void nameOption(OptionParser parser) { parser.acceptsAll(Arrays.asList("name", "n"), "name").withRequiredArg(); } - + static void keyOption(OptionParser parser) { parser.acceptsAll(Arrays.asList("key", "k"), "key").withRequiredArg(); } - + static void fullOption(OptionParser parser) { parser.accepts("full").withOptionalArg(); } - + static void parseName(ExecuteData data) { final @Nullable String name = (String) data.getOption("name"); data.set("name", Optional.ofNullable(name)); diff --git a/src/main/java/com/matt/forgehax/mods/commands/SayCommand.java b/src/main/java/com/matt/forgehax/mods/commands/SayCommand.java index 2154ed86a..6c69bbffa 100644 --- a/src/main/java/com/matt/forgehax/mods/commands/SayCommand.java +++ b/src/main/java/com/matt/forgehax/mods/commands/SayCommand.java @@ -12,39 +12,43 @@ @RegisterMod public class SayCommand extends CommandMod { - public SayCommand() { super("SayCommand"); } - - @RegisterCommand - public Command say(CommandBuilders builders) { - return builders - .newCommandBuilder() - .name("say") - .description("Send chat message") - .options( - parser -> { - parser.acceptsAll(Arrays.asList("fake", "f"), "Send a fake message that won't be treated as command"); - parser.acceptsAll(Arrays.asList("local", "l"), "Send message from local chat"); - } - ) - .processor( - data -> { - boolean fake = data.hasOption("fake"); - // any emoji will work until 1.13 - final int fakePrefix = 0x1F921; - String msg = data.getArgumentCount() > 0 ? data.getArgumentAsString(0) : ""; - - if (getLocalPlayer() != null) { - if (fake) { - msg = new StringBuilder().appendCodePoint(fakePrefix).append(msg).toString(); - } - if (data.hasOption("local")) { - getLocalPlayer().sendChatMessage(msg); - } else { - PacketHelper.ignoreAndSend(new CPacketChatMessage(msg)); - } - } - } - ) - .build(); - } -} \ No newline at end of file + + public SayCommand() { + super("SayCommand"); + } + + @RegisterCommand + public Command say(CommandBuilders builders) { + return builders + .newCommandBuilder() + .name("say") + .description("Send chat message") + .options( + parser -> { + parser.acceptsAll(Arrays.asList("fake", "f"), + "Send a fake message that won't be treated as command"); + parser.acceptsAll(Arrays.asList("local", "l"), "Send message from local chat"); + } + ) + .processor( + data -> { + boolean fake = data.hasOption("fake"); + // any emoji will work until 1.13 + final int fakePrefix = 0x1F921; + String msg = data.getArgumentCount() > 0 ? data.getArgumentAsString(0) : ""; + + if (getLocalPlayer() != null) { + if (fake) { + msg = new StringBuilder().appendCodePoint(fakePrefix).append(msg).toString(); + } + if (data.hasOption("local")) { + getLocalPlayer().sendChatMessage(msg); + } else { + PacketHelper.ignoreAndSend(new CPacketChatMessage(msg)); + } + } + } + ) + .build(); + } +} diff --git a/src/main/java/com/matt/forgehax/mods/managers/PositionRotationManager.java b/src/main/java/com/matt/forgehax/mods/managers/PositionRotationManager.java index 656351f6b..b2fbdebd5 100644 --- a/src/main/java/com/matt/forgehax/mods/managers/PositionRotationManager.java +++ b/src/main/java/com/matt/forgehax/mods/managers/PositionRotationManager.java @@ -21,113 +21,116 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 6/15/2017 by fr1kin */ +/** + * Created on 6/15/2017 by fr1kin + */ @RegisterMod public class PositionRotationManager extends ServiceMod { + private static final SimpleManagerContainer MANAGER = - new SimpleManagerContainer<>(); + new SimpleManagerContainer<>(); private static final SimpleWrapperImpl STATE = new SimpleWrapperImpl(); - + public static SimpleManagerContainer getManager() { return MANAGER; } - + public static ReadableRotationState getState() { return STATE; } - + public PositionRotationManager() { super("PositionRotationManager"); } - + public final Setting smooth = - getCommandStub() - .builders() - .newSettingBuilder() - .name("smooth") - .description("Angle smoothing for bypassing anti-cheats. Set to 0 to disable") - .defaultTo(45.D) - .min(0.D) - .max(180.D) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("smooth") + .description("Angle smoothing for bypassing anti-cheats. Set to 0 to disable") + .defaultTo(45.D) + .min(0.D) + .max(180.D) + .build(); + private final RotationState gState = new RotationState(); private TaskChain> futureTasks = TaskChain.empty(); - + private static Angle getPlayerAngles(EntityPlayer player) { return Angle.degrees(player.rotationPitch, player.rotationYaw); } - + private static void setPlayerAngles(EntityPlayerSP player, Angle angles) { Angle original = getPlayerAngles(player); Angle diff = angles.normalize().sub(original.normalize()); player.rotationPitch = Utils.clamp(original.getPitch() + diff.getPitch(), -90.f, 90.f); player.rotationYaw = original.getYaw() + diff.getYaw(); } - + private static void setPlayerPosition(EntityPlayerSP player, Vec3d position) { player.posX = position.x; player.posY = position.y; player.posZ = position.z; } - + private float clampAngle(float from, float to, float clamp) { return AngleHelper.normalizeInDegrees( - from + Utils.clamp(AngleHelper.normalizeInDegrees(to - from), -clamp, clamp)); + from + Utils.clamp(AngleHelper.normalizeInDegrees(to - from), -clamp, clamp)); } - + private Angle clampAngle(Angle from, Angle to, float clamp) { return Angle.degrees( - clampAngle(from.getPitch(), to.getPitch(), clamp), - clampAngle(from.getYaw(), to.getYaw(), clamp)); + clampAngle(from.getPitch(), to.getPitch(), clamp), + clampAngle(from.getYaw(), to.getYaw(), clamp)); } - + private float getRotationCount(Angle from, Angle to, float clamp) { Angle diff = to.sub(from).normalize(); float rp = (diff.getPitch() / clamp); float ry = (diff.getYaw() / clamp); return Math.max(Math.abs(rp), Math.abs(ry)); } - + @SubscribeEvent public void onWorldLoad(WorldEvent.Load event) { gState.setInitialized(false); } - + @SubscribeEvent public void onMovementUpdatePre(LocalPlayerUpdateMovementEvent.Pre event) { // updated view angles Angle va = getPlayerAngles(event.getLocalPlayer()); - + if (!gState.isInitialized()) { gState.setServerAngles(va); gState.setClientAngles(va); gState.setInitialized(true); } - + RotationState gs = new RotationState(); gs.setServerAngles(gState.getServerAngles()); // use previous angles gs.setClientAngles(va); - + // boolean to check if any task has been processed boolean changed = false; - + // true if only the client angle has been updated boolean clientOnly = false; - + RotationState.Local ls = null; // process tasks until there are none left or one changes the players view angles for (MovementUpdateListener listener : getManager().functions()) { ls = new Local(gs); listener.onLocalPlayerMovementUpdate(ls); - + boolean clientCng = ls.isClientAnglesChanged(); boolean serverCng = ls.isServerAnglesChanged(); - + if (ls.isCanceled()) { // cancel event, do not update any view angles event.setCanceled(true); - + // set the current server angles to the previous states as this event wont fire RotationState rs = new RotationState(gs); rs.setServerAngles(gState.getServerAngles()); @@ -165,7 +168,7 @@ public void onMovementUpdatePre(LocalPlayerUpdateMovementEvent.Pre event) { break; } } - + if (gs.getListener() == null && gState.getListener() == null) { gs.setServerAngles(gs.getClientAngles()); } else if (gs.getListener() == null && gState.getListener() != null) { @@ -174,45 +177,51 @@ public void onMovementUpdatePre(LocalPlayerUpdateMovementEvent.Pre event) { } else if (gState.getListener() != gs.getListener()) { getManager().begin(gs.getListener()); } - + if (smooth.get() > 0.D) { // the current angles the server thinks we are looking at Angle start = gState.getServerAngles(); // the angles we want to look at Angle dest = gs.getServerAngles(); - + gs.setServerAngles(clampAngle(start, dest, smooth.getAsFloat())); - - if (getRotationCount(start, dest, smooth.getAsFloat()) <= 1.f) + + if (getRotationCount(start, dest, smooth.getAsFloat()) <= 1.f) { futureTasks = ls != null ? ls.getFutureTasks() : TaskChain.empty(); - else futureTasks = TaskChain.empty(); + } else { + futureTasks = TaskChain.empty(); + } } else { // update the future tasks that are processed in the post movement update hook futureTasks = ls != null ? ls.getFutureTasks() : TaskChain.empty(); } - + gState.copyOf(gs); - + // set the player angles to the server angles setPlayerAngles(event.getLocalPlayer(), gState.getServerAngles().inDegrees().normalize()); } - + @SubscribeEvent public void onMovementUpdatePost(LocalPlayerUpdateMovementEvent.Post event) { // reset angles if silent aiming is enabled - if (gState.isSilent()) + if (gState.isSilent()) { setPlayerAngles(event.getLocalPlayer(), gState.getClientAngles().inDegrees().normalize()); - + } + // process all the tasks - while (futureTasks.hasNext()) futureTasks.next().accept(gState); + while (futureTasks.hasNext()) { + futureTasks.next().accept(gState); + } // set to empty task chain futureTasks = TaskChain.empty(); - + // update the read-only state STATE.setCurrentState(gState); } - + public interface MovementUpdateListener { + /** * Called when this event has focus. * @@ -220,8 +229,9 @@ public interface MovementUpdateListener { */ void onLocalPlayerMovementUpdate(RotationState.Local state); } - + public interface ReadableRotationState { + /** * Gets the local player instance * @@ -230,14 +240,14 @@ public interface ReadableRotationState { default EntityPlayerSP getLocalPlayer() { return Helper.getLocalPlayer(); } - + /** * The client-sided view angles of the player * * @return angle in degrees */ Angle getClientAngles(); - + /** * The server-sided view angles of the player (what the server thinks the players view angles * are) @@ -245,7 +255,7 @@ default EntityPlayerSP getLocalPlayer() { * @return angle in degrees */ Angle getServerAngles(); - + /** * Will return the client-sided view angles or the immediate view angles if no task is currently * active. @@ -254,10 +264,10 @@ default EntityPlayerSP getLocalPlayer() { */ default Angle getRenderClientViewAngles() { return isActive() - ? getClientAngles() - : Angle.degrees(getLocalPlayer().rotationPitch, getLocalPlayer().rotationYaw); + ? getClientAngles() + : Angle.degrees(getLocalPlayer().rotationPitch, getLocalPlayer().rotationYaw); } - + /** * Will return the server-sided view angles or the immediate view angles if no task is currently * active. @@ -266,17 +276,17 @@ default Angle getRenderClientViewAngles() { */ default Angle getRenderServerViewAngles() { return isActive() - ? getServerAngles() - : Angle.degrees(getLocalPlayer().rotationPitch, getLocalPlayer().rotationYaw); + ? getServerAngles() + : Angle.degrees(getLocalPlayer().rotationPitch, getLocalPlayer().rotationYaw); } - + /** * If the client and server view angles are purposefully desynchronized. * * @return true of the angles are desynced */ boolean isSilent(); - + /** * If a viewing task is currently being processed. * @@ -285,7 +295,7 @@ default Angle getRenderServerViewAngles() { default boolean isActive() { return getListener() != null; } - + /** * The current active listener. * @@ -293,216 +303,226 @@ default boolean isActive() { */ MovementUpdateListener getListener(); } - + public static class RotationState implements ReadableRotationState { + private boolean initialized = false; - + private Angle serverViewAngles = Angle.ZERO; private Angle clientViewAngles = Angle.ZERO; - + private MovementUpdateListener listener = null; - - private RotationState() {} - + + private RotationState() { + } + private RotationState(RotationState other) { copyOf(other); } - + private void copyOf(RotationState other) { this.serverViewAngles = other.serverViewAngles; this.clientViewAngles = other.clientViewAngles; this.listener = other.listener; } - + private boolean isInitialized() { return initialized; } - + private void setInitialized(boolean initialized) { this.initialized = initialized; } - + public Angle getServerAngles() { return serverViewAngles; } - + public void setServerAngles(Angle va) { Objects.requireNonNull(va); this.serverViewAngles = va.normalize(); } - + public void setServerAngles(float pitch, float yaw) { setServerAngles(Angle.degrees(pitch, yaw)); } - + public Angle getClientAngles() { return clientViewAngles; } - + public void setClientAngles(Angle va) { Objects.requireNonNull(va); this.clientViewAngles = va.normalize(); } - + public void setClientAngles(float pitch, float yaw) { setClientAngles(Angle.degrees(pitch, yaw)); } - + public void setViewAngles(Angle va, boolean silent) { setServerAngles(va); - if (!silent) setClientAngles(va); + if (!silent) { + setClientAngles(va); + } } - + public void setViewAngles(float pitch, float yaw, boolean silent) { setServerAngles(pitch, yaw); - if (!silent) setClientAngles(pitch, yaw); + if (!silent) { + setClientAngles(pitch, yaw); + } } - + public void setViewAngles(Angle va) { setViewAngles(va, false); } - + public void setViewAngles(float pitch, float yaw) { setViewAngles(pitch, yaw, false); } - + public void setViewAnglesSilent(Angle va) { setViewAngles(va, true); } - + public void setViewAnglesSilent(float pitch, float yaw) { setViewAngles(pitch, yaw, true); } - + public boolean isSilent() { return !Objects.equals(clientViewAngles, serverViewAngles); } - + public MovementUpdateListener getListener() { return listener; } - + private void setListener(MovementUpdateListener listener) { this.listener = listener; } - + protected TaskChain> getFutureTasks() { return TaskChain.empty(); } - - /** A class that contains variables localized to each listener instance */ + + /** + * A class that contains variables localized to each listener instance + */ public static class Local extends RotationState { + private final List> later = Lists.newArrayList(); - + private boolean serverAnglesChanged = false; private boolean clientAnglesChanged = false; private boolean halted = false; private boolean canceled = false; private boolean clientSided = false; - + private Local(RotationState other) { super(other); } - + @Override public void setServerAngles(Angle va) { super.setServerAngles(va); this.serverAnglesChanged = true; } - + @Override public void setClientAngles(Angle va) { super.setClientAngles(va); this.clientAnglesChanged = true; } - + @Override protected TaskChain> getFutureTasks() { return TaskChain.>builder().addAll(later).build(); } - + public void invokeLater(Consumer task) { later.add(task); } - + public boolean isHalted() { return halted; } - + public void setHalted(boolean halted) { this.halted = halted; } - + public boolean isCanceled() { return canceled; } - + public void setCanceled(boolean canceled) { this.canceled = canceled; } - + public boolean isClientSided() { return clientSided; } - + public void setClientSided(boolean clientSided) { this.clientSided = clientSided; } - + public boolean isServerAnglesChanged() { return serverAnglesChanged; } - + public boolean isClientAnglesChanged() { return clientAnglesChanged; } } } - + private static class SimpleWrapperImpl implements ReadableRotationState { + private ReadableRotationState state = - new ReadableRotationState() { - @Override - public Angle getClientAngles() { - return Angle.ZERO; - } - - @Override - public Angle getServerAngles() { - return Angle.ZERO; - } - - @Override - public boolean isSilent() { - return false; - } - - @Override - public MovementUpdateListener getListener() { - return null; - } - }; - + new ReadableRotationState() { + @Override + public Angle getClientAngles() { + return Angle.ZERO; + } + + @Override + public Angle getServerAngles() { + return Angle.ZERO; + } + + @Override + public boolean isSilent() { + return false; + } + + @Override + public MovementUpdateListener getListener() { + return null; + } + }; + private void setCurrentState(ReadableRotationState state) { Objects.requireNonNull(state); this.state = state; } - + @Override public synchronized Angle getClientAngles() { return state.getClientAngles(); } - + @Override public synchronized Angle getServerAngles() { return state.getServerAngles(); } - + @Override public synchronized boolean isSilent() { return state.isSilent(); } - + @Override public synchronized MovementUpdateListener getListener() { return state.getListener(); diff --git a/src/main/java/com/matt/forgehax/mods/services/BindEventService.java b/src/main/java/com/matt/forgehax/mods/services/BindEventService.java index ff6c82dd8..543191927 100644 --- a/src/main/java/com/matt/forgehax/mods/services/BindEventService.java +++ b/src/main/java/com/matt/forgehax/mods/services/BindEventService.java @@ -8,9 +8,12 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.InputEvent; -/** Created on 6/14/2017 by fr1kin */ +/** + * Created on 6/14/2017 by fr1kin + */ @RegisterMod public class BindEventService extends ServiceMod { + public BindEventService() { super("BindEventService"); } @@ -18,15 +21,19 @@ public BindEventService() { @SubscribeEvent public void onKeyboardEvent(InputEvent.KeyInputEvent event) { getGlobalCommand() - .getChildrenDeep() - .stream() - .filter(command -> command instanceof CommandStub) - .map(command -> (CommandStub) command) - .filter(stub -> stub.getBind() != null) - .forEach( - stub -> { - if (stub.getBind().isPressed()) stub.onKeyPressed(); - if (stub.getBind().isKeyDown()) stub.onKeyDown(); - }); + .getChildrenDeep() + .stream() + .filter(command -> command instanceof CommandStub) + .map(command -> (CommandStub) command) + .filter(stub -> stub.getBind() != null) + .forEach( + stub -> { + if (stub.getBind().isPressed()) { + stub.onKeyPressed(); + } + if (stub.getBind().isKeyDown()) { + stub.onKeyDown(); + } + }); } } diff --git a/src/main/java/com/matt/forgehax/mods/services/ChatCommandService.java b/src/main/java/com/matt/forgehax/mods/services/ChatCommandService.java index 7f0636c8e..de071a770 100644 --- a/src/main/java/com/matt/forgehax/mods/services/ChatCommandService.java +++ b/src/main/java/com/matt/forgehax/mods/services/ChatCommandService.java @@ -12,40 +12,43 @@ import net.minecraft.network.play.client.CPacketChatMessage; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 5/15/2017 by fr1kin */ +/** + * Created on 5/15/2017 by fr1kin + */ @RegisterMod public class ChatCommandService extends ServiceMod { + private static Character ACTIVATION_CHARACTER = '.'; - + public static Character getActivationCharacter() { return ACTIVATION_CHARACTER; } - + public final Setting activationCharacter = - getCommandStub() - .builders() - .newSettingBuilder() - .name("activation_char") - .description("Activation character") - .defaultTo('.') - .changed(cb -> ACTIVATION_CHARACTER = cb.getTo()) - .build(); - + getCommandStub() + .builders() + .newSettingBuilder() + .name("activation_char") + .description("Activation character") + .defaultTo('.') + .changed(cb -> ACTIVATION_CHARACTER = cb.getTo()) + .build(); + public ChatCommandService() { super("ChatCommandService", "Listeners for activation key in chat messages typed"); } - + @Override protected void onLoad() { ACTIVATION_CHARACTER = activationCharacter.get(); } - + @SubscribeEvent public void onSendPacket(PacketEvent.Outgoing.Pre event) { if (event.getPacket() instanceof CPacketChatMessage) { String message = ((CPacketChatMessage) event.getPacket()).getMessage(); if (!PacketHelper.isIgnored(event.getPacket()) - && message.startsWith(activationCharacter.getAsString()) && message.length() > 1) { + && message.startsWith(activationCharacter.getAsString()) && message.length() > 1) { // cut out the . from the message String line = message.substring(1); handleCommand(line); @@ -53,7 +56,7 @@ public void onSendPacket(PacketEvent.Outgoing.Pre event) { } } } - + // to be called from MainMenuGuiService public static void handleCommand(String message) { ConsoleIO.start(); @@ -63,7 +66,9 @@ public static void handleCommand(String message) { String[] arguments = CommandHelper.translate(message); GLOBAL_COMMAND.run(arguments); } catch (Throwable t) { - if (!(t instanceof CommandExecuteException)) t.printStackTrace(); + if (!(t instanceof CommandExecuteException)) { + t.printStackTrace(); + } Helper.printMessage(t.getMessage()); } ConsoleIO.finished(); diff --git a/src/main/java/com/matt/forgehax/mods/services/ChatIdentifierService.java b/src/main/java/com/matt/forgehax/mods/services/ChatIdentifierService.java index 6788eaca5..0ea3758a7 100644 --- a/src/main/java/com/matt/forgehax/mods/services/ChatIdentifierService.java +++ b/src/main/java/com/matt/forgehax/mods/services/ChatIdentifierService.java @@ -20,9 +20,12 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 7/18/2017 by fr1kin */ +/** + * Created on 7/18/2017 by fr1kin + */ @RegisterMod public class ChatIdentifierService extends ServiceMod { + // should split into two groups: group 1: senders name. group 2: message private static final Pattern[] MESSAGE_PATTERNS = { Pattern.compile("<(.*?)> (.*)"), // vanilla @@ -42,7 +45,7 @@ public ChatIdentifierService() { } private static boolean extract( - String message, Pattern[] patterns, BiConsumer callback) { + String message, Pattern[] patterns, BiConsumer callback) { for (Pattern pattern : patterns) { Matcher matcher = pattern.matcher(message); if (matcher.find()) { @@ -50,7 +53,9 @@ private static boolean extract( final String messageOnly = matcher.group(2); if (!Strings.isNullOrEmpty(messageSender)) { for (NetworkPlayerInfo data : getLocalPlayer().connection.getPlayerInfoMap()) { - if (String.CASE_INSENSITIVE_ORDER.compare(messageSender, data.getGameProfile().getName()) == 0) { + if ( + String.CASE_INSENSITIVE_ORDER.compare(messageSender, data.getGameProfile().getName()) + == 0) { callback.accept(data.getGameProfile(), messageOnly); return true; } @@ -64,111 +69,120 @@ private static boolean extract( @SuppressWarnings("Duplicates") @SubscribeEvent public void onChatMessage(PacketEvent.Incoming.Pre event) { - if (getLocalPlayer() == null || getLocalPlayer().connection == null) return; - else if (event.getPacket() instanceof SPacketChat) { + if (getLocalPlayer() == null || getLocalPlayer().connection == null) { + return; + } else if (event.getPacket() instanceof SPacketChat) { SPacketChat packet = (SPacketChat) event.getPacket(); String message = packet.getChatComponent().getUnformattedText(); if (!Strings.isNullOrEmpty(message)) { MC.addScheduledTask(() -> { // normal public messages if (extract( - message, - MESSAGE_PATTERNS, - (senderProfile, msg) -> { - PlayerInfoHelper.registerWithCallback( - senderProfile.getName(), - new FutureCallback() { - @Override - public void onSuccess(@Nullable PlayerInfo result) { - if (result != null) - MinecraftForge.EVENT_BUS - .post(ChatMessageEvent.newPublicChat(result, msg)); - } - - @Override - public void onFailure(Throwable t) { - PlayerInfoHelper.generateOfflineWithCallback(senderProfile.getName(), this); - } - }); - })) + message, + MESSAGE_PATTERNS, + (senderProfile, msg) -> { + PlayerInfoHelper.registerWithCallback( + senderProfile.getName(), + new FutureCallback() { + @Override + public void onSuccess(@Nullable PlayerInfo result) { + if (result != null) { + MinecraftForge.EVENT_BUS + .post(ChatMessageEvent.newPublicChat(result, msg)); + } + } + + @Override + public void onFailure(Throwable t) { + PlayerInfoHelper.generateOfflineWithCallback(senderProfile.getName(), this); + } + }); + })) { return; + } // private messages to the local player if (extract( - message, - INCOMING_PRIVATE_MESSAGES, - (senderProfile, msg) -> { - PlayerInfoHelper.registerWithCallback( - senderProfile.getName(), - new FutureCallback() { - @Override - public void onSuccess(final @Nullable PlayerInfo sender) { - // now get the local player - if (sender != null) - PlayerInfoHelper.registerWithCallback( - getLocalPlayer().getName(), - new FutureCallback() { - @Override - public void onSuccess(@Nullable PlayerInfo result) { - if (result != null) - MinecraftForge.EVENT_BUS.post( - ChatMessageEvent.newPrivateChat(sender, result, msg)); - } - - @Override - public void onFailure(Throwable t) { - PlayerInfoHelper.generateOfflineWithCallback( - getLocalPlayer().getName(), this); - } - }); - } - - @Override - public void onFailure(Throwable t) { - PlayerInfoHelper.generateOfflineWithCallback(senderProfile.getName(), this); - } - }); - })) + message, + INCOMING_PRIVATE_MESSAGES, + (senderProfile, msg) -> { + PlayerInfoHelper.registerWithCallback( + senderProfile.getName(), + new FutureCallback() { + @Override + public void onSuccess(final @Nullable PlayerInfo sender) { + // now get the local player + if (sender != null) { + PlayerInfoHelper.registerWithCallback( + getLocalPlayer().getName(), + new FutureCallback() { + @Override + public void onSuccess(@Nullable PlayerInfo result) { + if (result != null) { + MinecraftForge.EVENT_BUS.post( + ChatMessageEvent.newPrivateChat(sender, result, msg)); + } + } + + @Override + public void onFailure(Throwable t) { + PlayerInfoHelper.generateOfflineWithCallback( + getLocalPlayer().getName(), this); + } + }); + } + } + + @Override + public void onFailure(Throwable t) { + PlayerInfoHelper.generateOfflineWithCallback(senderProfile.getName(), this); + } + }); + })) { return; + } // outgoing pms from local player if (extract( - message, - OUTGOING_PRIVATE_MESSAGES, - (receiverProfile, msg) -> { - PlayerInfoHelper.registerWithCallback( - receiverProfile.getName(), - new FutureCallback() { - @Override - public void onSuccess(final @Nullable PlayerInfo receiver) { - // now get the local player - if (receiver != null) - PlayerInfoHelper.registerWithCallback( - getLocalPlayer().getName(), - new FutureCallback() { - @Override - public void onSuccess(@Nullable PlayerInfo sender) { - if (sender != null) - MinecraftForge.EVENT_BUS.post( - ChatMessageEvent.newPrivateChat(sender, receiver, msg)); - } - - @Override - public void onFailure(Throwable t) { - PlayerInfoHelper.generateOfflineWithCallback( - getLocalPlayer().getName(), this); - } - }); - } - - @Override - public void onFailure(Throwable t) { - PlayerInfoHelper - .generateOfflineWithCallback(receiverProfile.getName(), this); - } - }); - })) + message, + OUTGOING_PRIVATE_MESSAGES, + (receiverProfile, msg) -> { + PlayerInfoHelper.registerWithCallback( + receiverProfile.getName(), + new FutureCallback() { + @Override + public void onSuccess(final @Nullable PlayerInfo receiver) { + // now get the local player + if (receiver != null) { + PlayerInfoHelper.registerWithCallback( + getLocalPlayer().getName(), + new FutureCallback() { + @Override + public void onSuccess(@Nullable PlayerInfo sender) { + if (sender != null) { + MinecraftForge.EVENT_BUS.post( + ChatMessageEvent.newPrivateChat(sender, receiver, msg)); + } + } + + @Override + public void onFailure(Throwable t) { + PlayerInfoHelper.generateOfflineWithCallback( + getLocalPlayer().getName(), this); + } + }); + } + } + + @Override + public void onFailure(Throwable t) { + PlayerInfoHelper + .generateOfflineWithCallback(receiverProfile.getName(), this); + } + }); + })) { return; + } // if reached here then the message is unrecognized }); diff --git a/src/main/java/com/matt/forgehax/mods/services/FirstTimeRunningService.java b/src/main/java/com/matt/forgehax/mods/services/FirstTimeRunningService.java index ceea47013..4f44392ad 100644 --- a/src/main/java/com/matt/forgehax/mods/services/FirstTimeRunningService.java +++ b/src/main/java/com/matt/forgehax/mods/services/FirstTimeRunningService.java @@ -5,7 +5,7 @@ import com.matt.forgehax.ForgeHax; import com.matt.forgehax.events.LocalPlayerUpdateEvent; -import com.matt.forgehax.log.FileManager; +import com.matt.forgehax.util.FileManager; import com.matt.forgehax.util.mod.ServiceMod; import com.matt.forgehax.util.mod.loader.RegisterMod; import java.io.IOException; @@ -15,17 +15,21 @@ import joptsimple.internal.Strings; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 6/14/2017 by fr1kin */ +/** + * Created on 6/14/2017 by fr1kin + */ @RegisterMod public class FirstTimeRunningService extends ServiceMod { + private static final Path STARTUP_ONCE = FileManager.getInstance().getBaseResolve("config/.once"); private static final String getOnceFileVersion() { - if (Files.exists(STARTUP_ONCE)) + if (Files.exists(STARTUP_ONCE)) { try { return new String(Files.readAllBytes(STARTUP_ONCE)); } catch (Throwable t) { } + } return Strings.EMPTY; } diff --git a/src/main/java/com/matt/forgehax/mods/services/GuiService.java b/src/main/java/com/matt/forgehax/mods/services/GuiService.java index ddc60929f..9bbfbf783 100644 --- a/src/main/java/com/matt/forgehax/mods/services/GuiService.java +++ b/src/main/java/com/matt/forgehax/mods/services/GuiService.java @@ -8,9 +8,12 @@ import com.matt.forgehax.util.mod.loader.RegisterMod; import org.lwjgl.input.Keyboard; -/** Created by Babbaj on 9/10/2017. */ +/** + * Created by Babbaj on 9/10/2017. + */ @RegisterMod public class GuiService extends ServiceMod { + public GuiService() { super("GUI"); } @@ -25,9 +28,9 @@ public void onBindPressed(CallbackData cb) { @Override protected StubBuilder buildStubCommand(StubBuilder builder) { return builder - .kpressed(this::onBindPressed) - .kdown(this::onBindKeyDown) - .bind(Keyboard.KEY_RSHIFT) // default to right shift - ; + .kpressed(this::onBindPressed) + .kdown(this::onBindKeyDown) + .bind(Keyboard.KEY_RSHIFT) // default to right shift + ; } } diff --git a/src/main/java/com/matt/forgehax/mods/services/HotbarSelectionService.java b/src/main/java/com/matt/forgehax/mods/services/HotbarSelectionService.java index 634be10a5..596b0008a 100644 --- a/src/main/java/com/matt/forgehax/mods/services/HotbarSelectionService.java +++ b/src/main/java/com/matt/forgehax/mods/services/HotbarSelectionService.java @@ -14,46 +14,52 @@ @RegisterMod public class HotbarSelectionService extends ServiceMod { + private static HotbarSelectionService instance = null; - + public static HotbarSelectionService getInstance() { return instance; } - + private int originalIndex = -1; private long ticksElapsed = -1; - + private int lastSetIndex = -1; private Predicate resetCondition = Predicates.alwaysTrue(); - + public HotbarSelectionService() { super("HotbarSelectionService"); instance = this; } - + public ResetFunction setSelected(final int index, boolean reset, Predicate condition) { - if (index < 0 || index > LocalPlayerInventory.getHotbarSize() - 1) + if (index < 0 || index > LocalPlayerInventory.getHotbarSize() - 1) { throw new IllegalArgumentException( - "index must be between 0 and " + (LocalPlayerInventory.getHotbarSize() - 1)); - + "index must be between 0 and " + (LocalPlayerInventory.getHotbarSize() - 1)); + } + final int current = selected(); - + if (!reset) { select(index); - if (originalIndex != -1) originalIndex = index; - + if (originalIndex != -1) { + originalIndex = index; + } + return () -> select(index); } else { if (current != index) { - if (originalIndex == -1) originalIndex = current; - + if (originalIndex == -1) { + originalIndex = current; + } + lastSetIndex = index; resetCondition = MoreObjects.firstNonNull(condition, Predicates.alwaysTrue()); - + select(index); } ticksElapsed = 0; - + return () -> { if (index == selected() && lastSetIndex == index) { select(current); @@ -62,50 +68,58 @@ public ResetFunction setSelected(final int index, boolean reset, Predicate }; } } - + public void resetSelected() { - if (originalIndex != -1 && selected() == lastSetIndex) select(originalIndex); + if (originalIndex != -1 && selected() == lastSetIndex) { + select(originalIndex); + } reset(); } - + private void reset() { originalIndex = -1; ticksElapsed = -1; lastSetIndex = -1; resetCondition = Predicates.alwaysTrue(); } - + @SubscribeEvent public void onClientTick(ClientTickEvent event) { if (getWorld() == null || getLocalPlayer() == null) { reset(); return; } - + switch (event.phase) { - case START: - { - if (originalIndex != -1 && resetCondition.test(ticksElapsed)) resetSelected(); - if (ticksElapsed != -1) ++ticksElapsed; - break; + case START: { + if (originalIndex != -1 && resetCondition.test(ticksElapsed)) { + resetSelected(); + } + if (ticksElapsed != -1) { + ++ticksElapsed; } + break; + } } } - + // // // - + private static void select(int index) { - if (getLocalPlayer() == null) return; + if (getLocalPlayer() == null) { + return; + } LocalPlayerInventory.getInventory().currentItem = index; } - + private static int selected() { return getLocalPlayer() == null ? -1 : LocalPlayerInventory.getSelected().getIndex(); } - + public interface ResetFunction { + void revert(); } } diff --git a/src/main/java/com/matt/forgehax/mods/services/LocalPlayerUpdateEventService.java b/src/main/java/com/matt/forgehax/mods/services/LocalPlayerUpdateEventService.java index 27e3cf5e6..b11a8e2d1 100644 --- a/src/main/java/com/matt/forgehax/mods/services/LocalPlayerUpdateEventService.java +++ b/src/main/java/com/matt/forgehax/mods/services/LocalPlayerUpdateEventService.java @@ -11,9 +11,12 @@ import net.minecraftforge.fml.common.eventhandler.Event; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 6/14/2017 by fr1kin */ +/** + * Created on 6/14/2017 by fr1kin + */ @RegisterMod public class LocalPlayerUpdateEventService extends ServiceMod { + public LocalPlayerUpdateEventService() { super("LocalPlayerUpdateEventService"); } @@ -21,8 +24,8 @@ public LocalPlayerUpdateEventService() { @SubscribeEvent public void onUpdate(LivingEvent.LivingUpdateEvent event) { if (getWorld() != null - && event.getEntity().getEntityWorld().isRemote - && event.getEntityLiving().equals(getLocalPlayer())) { + && event.getEntity().getEntityWorld().isRemote + && event.getEntityLiving().equals(getLocalPlayer())) { Event ev = new LocalPlayerUpdateEvent(event.getEntityLiving()); MinecraftForge.EVENT_BUS.post(ev); event.setCanceled(ev.isCanceled()); diff --git a/src/main/java/com/matt/forgehax/mods/services/MainMenuGuiService.java b/src/main/java/com/matt/forgehax/mods/services/MainMenuGuiService.java index 9321d1cde..a69c9ed1f 100644 --- a/src/main/java/com/matt/forgehax/mods/services/MainMenuGuiService.java +++ b/src/main/java/com/matt/forgehax/mods/services/MainMenuGuiService.java @@ -1,22 +1,36 @@ package com.matt.forgehax.mods.services; -import static net.minecraft.util.text.TextFormatting.*; -import static org.lwjgl.input.Keyboard.*; +import static net.minecraft.util.text.TextFormatting.RED; +import static org.lwjgl.input.Keyboard.KEY_DOWN; +import static org.lwjgl.input.Keyboard.KEY_ESCAPE; +import static org.lwjgl.input.Keyboard.KEY_NEXT; +import static org.lwjgl.input.Keyboard.KEY_NUMPADENTER; +import static org.lwjgl.input.Keyboard.KEY_PRIOR; +import static org.lwjgl.input.Keyboard.KEY_RETURN; +import static org.lwjgl.input.Keyboard.KEY_UP; import com.google.common.util.concurrent.AtomicDouble; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.mod.ServiceMod; import com.matt.forgehax.util.mod.loader.RegisterMod; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; import javax.annotation.Nullable; -import net.minecraft.client.gui.*; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiMainMenu; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; import net.minecraft.util.math.MathHelper; import net.minecraftforge.client.event.GuiScreenEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.input.Keyboard; -/** Created by Babbaj on 4/10/2018. */ +/** + * Created by Babbaj on 4/10/2018. + */ @RegisterMod public class MainMenuGuiService extends ServiceMod { @@ -32,23 +46,23 @@ public void onGui(GuiScreenEvent.InitGuiEvent.Post event) { GuiMainMenu gui = (GuiMainMenu) event.getGui(); event - .getButtonList() - .stream() - .skip(4) // skip first 4 button - .forEach( - button -> { - button.y += 24; - }); // lower the rest of the buttons to make room for ours + .getButtonList() + .stream() + .skip(4) // skip first 4 button + .forEach( + button -> { + button.y += 24; + }); // lower the rest of the buttons to make room for ours event - .getButtonList() - .add( - customButton = - new GuiButton( - 666, - gui.width / 2 - 100, - gui.height / 4 + 48 + (24 * 3), // put button in 4th row - "Command Input")); + .getButtonList() + .add( + customButton = + new GuiButton( + 666, + gui.width / 2 - 100, + gui.height / 4 + 48 + (24 * 3), // put button in 4th row + "Command Input")); } } @@ -76,23 +90,23 @@ public class CommandInputGui extends GuiScreen { public void initGui() { Keyboard.enableRepeatEvents(true); this.inputField = - new GuiTextField(0, this.fontRenderer, 4, this.height - 12, this.width - 4, 12); + new GuiTextField(0, this.fontRenderer, 4, this.height - 12, this.width - 4, 12); inputField.setMaxStringLength(Integer.MAX_VALUE); this.inputField.setEnableBackgroundDrawing(false); this.inputField.setFocused(true); this.inputField.setCanLoseFocus(false); this.buttonList.add( - modeButton = - new GuiButton( - 0, this.width - 100 - 2, this.height - 20 - 2, 100, 20, mode.getName())); + modeButton = + new GuiButton( + 0, this.width - 100 - 2, this.height - 20 - 2, 100, 20, mode.getName())); } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { this.drawDefaultBackground(); drawRect( - 2, this.height - 16, this.width - 104, this.height - 4, Integer.MIN_VALUE); // input field + 2, this.height - 16, this.width - 104, this.height - 4, Integer.MIN_VALUE); // input field drawRect(2, 2, this.width - 2, this.height - 38, 70 << 24); // messageHistory box this.inputField.drawTextBox(); this.drawHistory(); @@ -122,14 +136,14 @@ protected void actionPerformed(GuiButton button) { private void drawHistory() { AtomicDouble offset = new AtomicDouble(); messageHistory - .stream() - .limit(100) - .forEach( - str -> { - MC.fontRenderer.drawString( - str, 5, (this.height - 50 - offset.intValue()), Utils.Colors.WHITE); - offset.addAndGet(10); - }); + .stream() + .limit(100) + .forEach( + str -> { + MC.fontRenderer.drawString( + str, 5, (this.height - 50 - offset.intValue()), Colors.WHITE.toBuffer()); + offset.addAndGet(10); + }); } @Override @@ -141,12 +155,16 @@ protected void keyTyped(char typedChar, int keyCode) throws IOException { { // older String sent = getSentHistory(-1); - if (sent != null) inputField.setText(sent); + if (sent != null) { + inputField.setText(sent); + } } else if (keyCode == KEY_DOWN) // down arrow { // newer String sent = getSentHistory(1); - if (sent != null) inputField.setText(sent); + if (sent != null) { + inputField.setText(sent); + } } else if (keyCode == KEY_PRIOR) { // this.mc.ingameGUI.getChatGUI().scroll(this.mc.ingameGUI.getChatGUI().getLineCount() - // 1); @@ -164,7 +182,7 @@ protected void keyTyped(char typedChar, int keyCode) throws IOException { // this.print("> " + str); this.inputField.setText(""); if (this.inputHistory.isEmpty() - || !this.inputHistory.get(this.inputHistory.size() - 1).equals(str)) { + || !this.inputHistory.get(this.inputHistory.size() - 1).equals(str)) { this.inputHistory.add(str); } this.sentHistoryCursor = inputHistory.size(); diff --git a/src/main/java/com/matt/forgehax/mods/services/PacketIgnoreListService.java b/src/main/java/com/matt/forgehax/mods/services/PacketIgnoreListService.java index 6e021f716..0abd1bee3 100644 --- a/src/main/java/com/matt/forgehax/mods/services/PacketIgnoreListService.java +++ b/src/main/java/com/matt/forgehax/mods/services/PacketIgnoreListService.java @@ -7,20 +7,27 @@ import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 6/14/2017 by fr1kin */ +/** + * Created on 6/14/2017 by fr1kin + */ @RegisterMod public class PacketIgnoreListService extends ServiceMod { + public PacketIgnoreListService() { super("PacketIgnoreListService"); } @SubscribeEvent(priority = EventPriority.LOWEST) public void onSentPacket(PacketEvent.Outgoing.Post event) { - if (PacketHelper.isIgnored(event.getPacket())) PacketHelper.remove(event.getPacket()); + if (PacketHelper.isIgnored(event.getPacket())) { + PacketHelper.remove(event.getPacket()); + } } @SubscribeEvent(priority = EventPriority.LOWEST) public void onIncomingPacket(PacketEvent.Incoming.Post event) { - if (PacketHelper.isIgnored(event.getPacket())) PacketHelper.remove(event.getPacket()); + if (PacketHelper.isIgnored(event.getPacket())) { + PacketHelper.remove(event.getPacket()); + } } } diff --git a/src/main/java/com/matt/forgehax/mods/services/PigmenAngerCooldownService.java b/src/main/java/com/matt/forgehax/mods/services/PigmenAngerCooldownService.java index be4aa9950..18827620c 100644 --- a/src/main/java/com/matt/forgehax/mods/services/PigmenAngerCooldownService.java +++ b/src/main/java/com/matt/forgehax/mods/services/PigmenAngerCooldownService.java @@ -7,9 +7,12 @@ import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 6/14/2017 by fr1kin */ +/** + * Created on 6/14/2017 by fr1kin + */ @RegisterMod public class PigmenAngerCooldownService extends ServiceMod { + public PigmenAngerCooldownService() { super("PigmenAngerCooldownService"); } @@ -23,7 +26,7 @@ public void onUpdate(LivingEvent.LivingUpdateEvent event) { FastReflection.Fields.EntityPigZombie_angerLevel.set(pigZombie, 400); } else if (pigZombie.isAngry()) { FastReflection.Fields.EntityPigZombie_angerLevel.set( - pigZombie, FastReflection.Fields.EntityPigZombie_angerLevel.get(pigZombie) - 1); + pigZombie, FastReflection.Fields.EntityPigZombie_angerLevel.get(pigZombie) - 1); } } } diff --git a/src/main/java/com/matt/forgehax/mods/services/RenderEventService.java b/src/main/java/com/matt/forgehax/mods/services/RenderEventService.java index a58114e35..42e117dda 100644 --- a/src/main/java/com/matt/forgehax/mods/services/RenderEventService.java +++ b/src/main/java/com/matt/forgehax/mods/services/RenderEventService.java @@ -2,12 +2,12 @@ import static com.matt.forgehax.Helper.getLocalPlayer; -import com.github.lunatrius.core.client.renderer.unique.GeometryTessellator; import com.matt.forgehax.events.Render2DEvent; import com.matt.forgehax.events.RenderEvent; import com.matt.forgehax.util.entity.EntityUtils; import com.matt.forgehax.util.mod.ServiceMod; import com.matt.forgehax.util.mod.loader.RegisterMod; +import com.matt.forgehax.util.tesselation.GeometryTessellator; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.Vec3d; import net.minecraftforge.client.event.RenderGameOverlayEvent; @@ -17,15 +17,18 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.opengl.GL11; -/** Created on 6/14/2017 by fr1kin */ +/** + * Created on 6/14/2017 by fr1kin + */ @RegisterMod public class RenderEventService extends ServiceMod { + private static final GeometryTessellator TESSELLATOR = new GeometryTessellator(); - + public RenderEventService() { super("RenderEventService"); } - + @SubscribeEvent public void onRenderWorld(RenderWorldLastEvent event) { GlStateManager.pushMatrix(); @@ -35,17 +38,17 @@ public void onRenderWorld(RenderWorldLastEvent event) { GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); GlStateManager.shadeModel(GL11.GL_SMOOTH); GlStateManager.disableDepth(); - + GlStateManager.glLineWidth(1.f); - + Vec3d renderPos = EntityUtils.getInterpolatedPos(getLocalPlayer(), event.getPartialTicks()); - + RenderEvent e = new RenderEvent(TESSELLATOR, renderPos, event.getPartialTicks()); e.resetTranslation(); MinecraftForge.EVENT_BUS.post(e); - + GlStateManager.glLineWidth(1.f); - + GlStateManager.shadeModel(GL11.GL_FLAT); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); @@ -54,7 +57,7 @@ public void onRenderWorld(RenderWorldLastEvent event) { GlStateManager.enableCull(); GlStateManager.popMatrix(); } - + @SubscribeEvent(priority = EventPriority.LOW) public void onRenderGameOverlayEvent(final RenderGameOverlayEvent.Text event) { if (event.getType().equals(RenderGameOverlayEvent.ElementType.TEXT)) { diff --git a/src/main/java/com/matt/forgehax/mods/services/ScoreboardListenerService.java b/src/main/java/com/matt/forgehax/mods/services/ScoreboardListenerService.java index d10299a4e..4e0be997e 100644 --- a/src/main/java/com/matt/forgehax/mods/services/ScoreboardListenerService.java +++ b/src/main/java/com/matt/forgehax/mods/services/ScoreboardListenerService.java @@ -25,25 +25,28 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.network.FMLNetworkEvent; -/** Created on 7/18/2017 by fr1kin */ +/** + * Created on 7/18/2017 by fr1kin + */ @RegisterMod public class ScoreboardListenerService extends ServiceMod { + private final Setting wait = - getCommandStub() - .builders() - .newSettingBuilder() - .name("wait") - .description("Time to wait after joining world") - .defaultTo(5000) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("wait") + .description("Time to wait after joining world") + .defaultTo(5000) + .build(); private final Setting retries = - getCommandStub() - .builders() - .newSettingBuilder() - .name("retries") - .description("Number of times to attempt retries on failure") - .defaultTo(1) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("retries") + .description("Number of times to attempt retries on failure") + .defaultTo(1) + .build(); private final SimpleTimer timer = new SimpleTimer(); @@ -54,19 +57,19 @@ public ScoreboardListenerService() { } private void fireEvents( - SPacketPlayerListItem.Action action, PlayerInfo info, GameProfile profile) { - if (ignore || info == null) return; + SPacketPlayerListItem.Action action, PlayerInfo info, GameProfile profile) { + if (ignore || info == null) { + return; + } switch (action) { - case ADD_PLAYER: - { - MinecraftForge.EVENT_BUS.post(new PlayerConnectEvent.Join(info, profile)); - break; - } - case REMOVE_PLAYER: - { - MinecraftForge.EVENT_BUS.post(new PlayerConnectEvent.Leave(info, profile)); - break; - } + case ADD_PLAYER: { + MinecraftForge.EVENT_BUS.post(new PlayerConnectEvent.Join(info, profile)); + break; + } + case REMOVE_PLAYER: { + MinecraftForge.EVENT_BUS.post(new PlayerConnectEvent.Leave(info, profile)); + break; + } } } @@ -82,7 +85,9 @@ public void onClientDisconnect(FMLNetworkEvent.ClientDisconnectionFromServerEven @SubscribeEvent public void onPacketIn(PacketEvent.Incoming.Pre event) { - if (ignore && timer.isStarted() && timer.hasTimeElapsed(wait.get())) ignore = false; + if (ignore && timer.isStarted() && timer.hasTimeElapsed(wait.get())) { + ignore = false; + } if (!ignore && event.getPacket() instanceof SPacketCustomPayload) { ignore = true; @@ -98,51 +103,53 @@ public void onScoreboardEvent(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketPlayerListItem) { final SPacketPlayerListItem packet = (SPacketPlayerListItem) event.getPacket(); if (!Action.ADD_PLAYER.equals(packet.getAction()) - && !Action.REMOVE_PLAYER.equals(packet.getAction())) return; + && !Action.REMOVE_PLAYER.equals(packet.getAction())) { + return; + } packet - .getEntries() - .stream() - .filter(Objects::nonNull) - .filter( - data -> - !Strings.isNullOrEmpty(data.getProfile().getName()) - || data.getProfile().getId() != null) - .forEach( - data -> { - final String name = data.getProfile().getName(); - final UUID id = data.getProfile().getId(); - final AtomicInteger retries = new AtomicInteger(this.retries.get()); - PlayerInfoHelper.registerWithCallback( - id, - name, - new FutureCallback() { - @Override - public void onSuccess(@Nullable PlayerInfo result) { - fireEvents(packet.getAction(), result, data.getProfile()); - } - - @Override - public void onFailure(Throwable t) { - if (retries.getAndDecrement() > 0) { - getLog() - .warn( - "Failed to lookup " - + name - + "/" - + id.toString() - + ", retrying (" - + retries.get() - + ")..."); - PlayerInfoHelper.registerWithCallback( - data.getProfile().getId(), name, this); - } else { - t.printStackTrace(); - PlayerInfoHelper.generateOfflineWithCallback(name, this); - } - } - }); + .getEntries() + .stream() + .filter(Objects::nonNull) + .filter( + data -> + !Strings.isNullOrEmpty(data.getProfile().getName()) + || data.getProfile().getId() != null) + .forEach( + data -> { + final String name = data.getProfile().getName(); + final UUID id = data.getProfile().getId(); + final AtomicInteger retries = new AtomicInteger(this.retries.get()); + PlayerInfoHelper.registerWithCallback( + id, + name, + new FutureCallback() { + @Override + public void onSuccess(@Nullable PlayerInfo result) { + fireEvents(packet.getAction(), result, data.getProfile()); + } + + @Override + public void onFailure(Throwable t) { + if (retries.getAndDecrement() > 0) { + getLog() + .warn( + "Failed to lookup " + + name + + "/" + + id.toString() + + ", retrying (" + + retries.get() + + ")..."); + PlayerInfoHelper.registerWithCallback( + data.getProfile().getId(), name, this); + } else { + t.printStackTrace(); + PlayerInfoHelper.generateOfflineWithCallback(name, this); + } + } }); + }); } } } diff --git a/src/main/java/com/matt/forgehax/mods/services/SneakService.java b/src/main/java/com/matt/forgehax/mods/services/SneakService.java index 04e4e97f2..5717ff93b 100644 --- a/src/main/java/com/matt/forgehax/mods/services/SneakService.java +++ b/src/main/java/com/matt/forgehax/mods/services/SneakService.java @@ -13,6 +13,7 @@ @RegisterMod public class SneakService extends ServiceMod { + private static SneakService instance; public static SneakService getInstance() { @@ -50,12 +51,15 @@ public void onPacketSend(PacketEvent.Outgoing.Pre event) { CPacketEntityAction packet = (CPacketEntityAction) event.getPacket(); int id = CPacketEntityAction_entityID.get(packet); if (getLocalPlayer().getEntityId() == id - && (packet.getAction() == Action.START_SNEAKING - || packet.getAction() == Action.STOP_SNEAKING) - && !PacketHelper.isIgnored(packet)) { + && (packet.getAction() == Action.START_SNEAKING + || packet.getAction() == Action.STOP_SNEAKING) + && !PacketHelper.isIgnored(packet)) { sneakingClient = packet.getAction() == Action.START_SNEAKING; - if (isSuppressing()) event.setCanceled(true); - else sneakingServer = sneakingClient; + if (isSuppressing()) { + event.setCanceled(true); + } else { + sneakingServer = sneakingClient; + } } } } diff --git a/src/main/java/com/matt/forgehax/mods/services/SpamService.java b/src/main/java/com/matt/forgehax/mods/services/SpamService.java index 57ad7564b..8c67ada3d 100644 --- a/src/main/java/com/matt/forgehax/mods/services/SpamService.java +++ b/src/main/java/com/matt/forgehax/mods/services/SpamService.java @@ -15,19 +15,31 @@ import joptsimple.internal.Strings; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 7/21/2017 by fr1kin */ +/** + * Created on 7/21/2017 by fr1kin + */ @RegisterMod public class SpamService extends ServiceMod { + private static final List SENDING = Lists.newCopyOnWriteArrayList(); public static boolean send(SpamMessage spam) { - if (!SENDING.contains(spam)) return SENDING.add(spam); - else return false; + if (!SENDING.contains(spam)) { + return SENDING.add(spam); + } else { + return false; + } } public static boolean isActivatorPresent(String activator) { - if (activator == null) return false; - for (SpamMessage msg : SENDING) if (activator.equalsIgnoreCase(msg.getActivator())) return true; + if (activator == null) { + return false; + } + for (SpamMessage msg : SENDING) { + if (activator.equalsIgnoreCase(msg.getActivator())) { + return true; + } + } return false; } @@ -36,19 +48,21 @@ public static boolean isEmpty() { } public final Setting delay = - getCommandStub() - .builders() - .newSettingBuilder() - .name("delay") - .description("Delay between each message in ms") - .defaultTo(5000L) - .changed( - cb -> { - nextSendMs = 0L; - }) - .build(); - - /** Next time to send a message */ + getCommandStub() + .builders() + .newSettingBuilder() + .name("delay") + .description("Delay between each message in ms") + .defaultTo(5000L) + .changed( + cb -> { + nextSendMs = 0L; + }) + .build(); + + /** + * Next time to send a message + */ private long nextSendMs = 0L; private Map customDelays = Maps.newConcurrentMap(); @@ -60,44 +74,46 @@ public SpamService() { @Override protected void onLoad() { getCommandStub() - .builders() - .newCommandBuilder() - .name("reset") - .description("Resets spam delay and send list") - .processor( - data -> { - nextSendMs = Long.MAX_VALUE; - SENDING.clear(); - customDelays.clear(); - nextSendMs = 0; - data.write("Reset chat spam"); - }) - .build(); + .builders() + .newCommandBuilder() + .name("reset") + .description("Resets spam delay and send list") + .processor( + data -> { + nextSendMs = Long.MAX_VALUE; + SENDING.clear(); + customDelays.clear(); + nextSendMs = 0; + data.write("Reset chat spam"); + }) + .build(); } @SubscribeEvent public void onTick(LocalPlayerUpdateEvent event) { if (!SENDING.isEmpty() && System.currentTimeMillis() > nextSendMs) { SENDING - .stream() - .filter( - msg -> { - if (!Strings.isNullOrEmpty(msg.getType())) { - long time = customDelays.getOrDefault(msg.getType(), new AtomicLong(0)).get(); - return System.currentTimeMillis() > time; - } else return true; - }) - .sorted() - .findFirst() - .ifPresent( - msg -> { - getLocalPlayer().sendChatMessage(msg.getMessage()); - customDelays - .computeIfAbsent(msg.getType(), t -> new AtomicLong(0L)) - .set(System.currentTimeMillis() + msg.getDelay()); - nextSendMs = System.currentTimeMillis() + delay.get(); - SENDING.remove(msg); - }); + .stream() + .filter( + msg -> { + if (!Strings.isNullOrEmpty(msg.getType())) { + long time = customDelays.getOrDefault(msg.getType(), new AtomicLong(0)).get(); + return System.currentTimeMillis() > time; + } else { + return true; + } + }) + .sorted() + .findFirst() + .ifPresent( + msg -> { + getLocalPlayer().sendChatMessage(msg.getMessage()); + customDelays + .computeIfAbsent(msg.getType(), t -> new AtomicLong(0L)) + .set(System.currentTimeMillis() + msg.getDelay()); + nextSendMs = System.currentTimeMillis() + delay.get(); + SENDING.remove(msg); + }); } } } diff --git a/src/main/java/com/matt/forgehax/mods/services/TickRateService.java b/src/main/java/com/matt/forgehax/mods/services/TickRateService.java index 482a4562d..a5d466283 100644 --- a/src/main/java/com/matt/forgehax/mods/services/TickRateService.java +++ b/src/main/java/com/matt/forgehax/mods/services/TickRateService.java @@ -13,30 +13,37 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 11/14/2016 by fr1kin */ +/** + * Created on 11/14/2016 by fr1kin + */ @RegisterMod public class TickRateService extends ServiceMod { - /** Ticks per second maximum and minimum */ + + /** + * Ticks per second maximum and minimum + */ public static final double MAX_TICKRATE = 20.D; - + public static final double MIN_TICKRATE = 0.D; - - /** Tick rate sample size */ + + /** + * Tick rate sample size + */ public static final int MAXIMUM_SAMPLE_SIZE = 100; - + private static final TickRateService INSTANCE = new TickRateService(); private static final TickRateData TICK_DATA = new TickRateData(MAXIMUM_SAMPLE_SIZE); - + public static TickRateService getInstance() { return INSTANCE; } - + public static TickRateData getTickData() { return TICK_DATA; } - + private long timeLastTimeUpdate = -1; - + public long getLastTimeDiff() { if (timeLastTimeUpdate != -1) { return System.currentTimeMillis() - timeLastTimeUpdate; @@ -44,17 +51,17 @@ public long getLastTimeDiff() { return 0; } } - + public TickRateService() { super("TickManager", "Records the average tick rate"); } - + @SubscribeEvent public void onWorldLoad(WorldEvent.Load event) { timeLastTimeUpdate = -1; TICK_DATA.onWorldLoaded(); } - + @SubscribeEvent public void onPacketPreceived(PacketEvent.Incoming.Pre event) { if (event.getPacket() instanceof SPacketTimeUpdate) { @@ -66,22 +73,27 @@ public void onPacketPreceived(PacketEvent.Incoming.Pre event) { INSTANCE.timeLastTimeUpdate = timeLastTimeUpdate; } } - + public static class TickRateData { + private final CalculationData EMPTY_DATA = new CalculationData(); - + private final Queue rates; private final List data = Lists.newArrayList(); - + private TickRateData(int maxSampleSize) { this.rates = EvictingQueue.create(maxSampleSize); - for (int i = 0; i < maxSampleSize; i++) data.add(new CalculationData()); + for (int i = 0; i < maxSampleSize; i++) { + data.add(new CalculationData()); + } } - + private void resetData() { - for (CalculationData d : data) d.reset(); + for (CalculationData d : data) { + d.reset(); + } } - + private void recalculate() { resetData(); int size = 0; @@ -97,40 +109,41 @@ private void recalculate() { } } } - + public CalculationData getPoint(int point) { // clamp between existing data points and 0 CalculationData d = data.get(Math.max(Math.min(getSampleSize() - 1, point - 1), 0)); return d != null ? d : EMPTY_DATA; } - + public CalculationData getPoint() { return getPoint(getSampleSize() - 1); } - + public int getSampleSize() { return rates.size(); } - + private void onTimePacketIncoming(long difference) { double timeElapsed = ((double) (difference) / 1000.D); rates.offer(MathHelper.clamp(MAX_TICKRATE / timeElapsed, MIN_TICKRATE, MAX_TICKRATE)); // recalculate tick rate data recalculate(); } - + private void onWorldLoaded() { rates.clear(); resetData(); } - + public class CalculationData { + private double average = 0.D; - + public double getAverage() { return average; } - + public void reset() { average = 0.D; } diff --git a/src/main/java/com/matt/forgehax/mods/services/WorldEventService.java b/src/main/java/com/matt/forgehax/mods/services/WorldEventService.java index 4216155c6..818d2733f 100644 --- a/src/main/java/com/matt/forgehax/mods/services/WorldEventService.java +++ b/src/main/java/com/matt/forgehax/mods/services/WorldEventService.java @@ -8,9 +8,12 @@ import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -/** Created on 6/14/2017 by fr1kin */ +/** + * Created on 6/14/2017 by fr1kin + */ @RegisterMod public class WorldEventService extends ServiceMod { + private static final WorldListener WORLD_LISTENER = new WorldListener(); public WorldEventService() { diff --git a/src/main/java/com/matt/forgehax/util/ArrayHelper.java b/src/main/java/com/matt/forgehax/util/ArrayHelper.java index 35effdd95..8b3ba94d2 100644 --- a/src/main/java/com/matt/forgehax/util/ArrayHelper.java +++ b/src/main/java/com/matt/forgehax/util/ArrayHelper.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util; -/** Created on 7/19/2017 by fr1kin */ +/** + * Created on 7/19/2017 by fr1kin + */ public class ArrayHelper { + public static T getOrDefault(T[] array, int index, T defaultValue) { return isInRange(array, index) ? array[index] : defaultValue; } diff --git a/src/main/java/com/matt/forgehax/util/BlockHelper.java b/src/main/java/com/matt/forgehax/util/BlockHelper.java index 9912e0f9e..26074f572 100644 --- a/src/main/java/com/matt/forgehax/util/BlockHelper.java +++ b/src/main/java/com/matt/forgehax/util/BlockHelper.java @@ -30,24 +30,25 @@ import net.minecraft.util.math.Vec3d; public class BlockHelper { + public static UniqueBlock newUniqueBlock(Block block, int metadata, BlockPos pos) { return new UniqueBlock(block, metadata, pos); } - + public static UniqueBlock newUniqueBlock(Block block, int metadata) { return newUniqueBlock(block, metadata, BlockPos.ORIGIN); } - + public static UniqueBlock newUniqueBlock(BlockPos pos) { IBlockState state = getWorld().getBlockState(pos); Block block = state.getBlock(); return newUniqueBlock(block, block.getMetaFromState(state), pos); } - + public static BlockTraceInfo newBlockTrace(BlockPos pos, EnumFacing side) { return new BlockTraceInfo(pos, side); } - + public static List getBlocksInRadius(Vec3d pos, double radius) { List list = Lists.newArrayList(); for (double x = pos.x - radius; x <= pos.x + radius; ++x) { @@ -59,195 +60,200 @@ public static List getBlocksInRadius(Vec3d pos, double radius) { } return list; } - + public static float getBlockHardness(BlockPos pos) { IBlockState state = getWorld().getBlockState(pos); return state.getBlockHardness(getWorld(), pos); } - + public static boolean isBlockReplaceable(BlockPos pos) { return getWorld().getBlockState(pos).getMaterial().isReplaceable(); } - + public static boolean isTraceClear(Vec3d start, Vec3d end, EnumFacing targetSide) { RayTraceResult tr = getWorld().rayTraceBlocks(start, end, false, true, false); return tr == null - || (new BlockPos(end).equals(new BlockPos(tr.hitVec)) - && targetSide.getOpposite().equals(tr.sideHit)); + || (new BlockPos(end).equals(new BlockPos(tr.hitVec)) + && targetSide.getOpposite().equals(tr.sideHit)); } - + public static Vec3d getOBBCenter(BlockPos pos) { IBlockState state = getWorld().getBlockState(pos); AxisAlignedBB bb = state.getBoundingBox(getWorld(), pos); return new Vec3d( - bb.minX + ((bb.maxX - bb.minX) / 2.D), - bb.minY + ((bb.maxY - bb.minY) / 2.D), - bb.minZ + ((bb.maxZ - bb.minZ) / 2.D)); + bb.minX + ((bb.maxX - bb.minX) / 2.D), + bb.minY + ((bb.maxY - bb.minY) / 2.D), + bb.minZ + ((bb.maxZ - bb.minZ) / 2.D)); } - + public static boolean isBlockPlaceable(BlockPos pos) { IBlockState state = getWorld().getBlockState(pos); return state.getBlock().canCollideCheck(state, false); } - + private static BlockTraceInfo getPlaceableBlockSideTrace( - Vec3d eyes, Vec3d normal, Stream stream, BlockPos pos) { + Vec3d eyes, Vec3d normal, Stream stream, BlockPos pos) { return stream - .map(side -> newBlockTrace(pos.offset(side), side)) - .filter(info -> isBlockPlaceable(info.getPos())) - .filter(info -> isInReach(eyes, info.getHitVec())) - .filter(info -> BlockHelper.isTraceClear(eyes, info.getHitVec(), info.getSide())) - .min( - Comparator.comparingInt(info -> info.isSneakRequired() ? 1 : 0) - .thenComparing( - info -> VectorUtils.getCrosshairDistance(eyes, normal, info.getCenteredPos()))) - .orElse(null); + .map(side -> newBlockTrace(pos.offset(side), side)) + .filter(info -> isBlockPlaceable(info.getPos())) + .filter(info -> isInReach(eyes, info.getHitVec())) + .filter(info -> BlockHelper.isTraceClear(eyes, info.getHitVec(), info.getSide())) + .min( + Comparator.comparingInt(info -> info.isSneakRequired() ? 1 : 0) + .thenComparing( + info -> VectorUtils.getCrosshairDistance(eyes, normal, info.getCenteredPos()))) + .orElse(null); } - + public static BlockTraceInfo getPlaceableBlockSideTrace( - Vec3d eyes, Vec3d normal, EnumSet sides, BlockPos pos) { + Vec3d eyes, Vec3d normal, EnumSet sides, BlockPos pos) { return getPlaceableBlockSideTrace(eyes, normal, sides.stream(), pos); } - + public static BlockTraceInfo getPlaceableBlockSideTrace(Vec3d eyes, Vec3d normal, BlockPos pos) { return getPlaceableBlockSideTrace(eyes, normal, Stream.of(EnumFacing.values()), pos); } - + public static BlockTraceInfo getBlockSideTrace(Vec3d eyes, BlockPos pos, EnumFacing side) { return Optional.of(newBlockTrace(pos, side)) - .filter(tr -> BlockHelper.isTraceClear(eyes, tr.getHitVec(), tr.getSide())) - .filter(tr -> LocalPlayerUtils.isInReach(eyes, tr.getHitVec())) - .orElse(null); + .filter(tr -> BlockHelper.isTraceClear(eyes, tr.getHitVec(), tr.getSide())) + .filter(tr -> LocalPlayerUtils.isInReach(eyes, tr.getHitVec())) + .orElse(null); } - + public static BlockTraceInfo getVisibleBlockSideTrace(Vec3d eyes, Vec3d normal, BlockPos pos) { return Arrays.stream(EnumFacing.values()) - .map(side -> BlockHelper.getBlockSideTrace(eyes, pos, side.getOpposite())) - .filter(Objects::nonNull) - .min( - Comparator.comparingDouble( - i -> VectorUtils.getCrosshairDistance(eyes, normal, i.getCenteredPos()))) - .orElse(null); + .map(side -> BlockHelper.getBlockSideTrace(eyes, pos, side.getOpposite())) + .filter(Objects::nonNull) + .min( + Comparator.comparingDouble( + i -> VectorUtils.getCrosshairDistance(eyes, normal, i.getCenteredPos()))) + .orElse(null); } - + public static class BlockTraceInfo { + private final BlockPos pos; private final EnumFacing side; private final Vec3d center; private final Vec3d hitVec; - + private BlockTraceInfo(BlockPos pos, EnumFacing side) { this.pos = pos; this.side = side; Vec3d obb = BlockHelper.getOBBCenter(pos); this.center = new Vec3d(pos).add(obb); this.hitVec = - this.center.add( - VectorUtils.multiplyBy(new Vec3d(getOppositeSide().getDirectionVec()), obb)); + this.center.add( + VectorUtils.multiplyBy(new Vec3d(getOppositeSide().getDirectionVec()), obb)); } - + public BlockPos getPos() { return pos; } - + public EnumFacing getSide() { return side; } - + public EnumFacing getOppositeSide() { return side.getOpposite(); } - + public Vec3d getHitVec() { return this.hitVec; } - + public Vec3d getCenteredPos() { return center; } - + public IBlockState getBlockState() { return getWorld().getBlockState(getPos()); } - + public boolean isPlaceable(InvItem item) { - if (!(item.getItem() instanceof ItemBlock)) return true; - + if (!(item.getItem() instanceof ItemBlock)) { + return true; + } + ItemBlock itemBlock = (ItemBlock) item.getItem(); return itemBlock.canPlaceBlockOnSide( - getWorld(), getPos(), getOppositeSide(), getLocalPlayer(), item.getItemStack()); + getWorld(), getPos(), getOppositeSide(), getLocalPlayer(), item.getItemStack()); } - + public boolean isSneakRequired() { return BlockActivationChecker.isOverwritten(getBlockState().getBlock()); } } - + public static class UniqueBlock { + private final Block block; private final int metadata; private final BlockPos pos; - + private UniqueBlock(Block block, int metadata, BlockPos pos) { this.block = block; this.metadata = metadata; this.pos = pos; } - + public Block getBlock() { return block; } - + public int getMetadata() { return metadata; } - + public BlockPos getPos() { return pos; } - + public Vec3d getCenteredPos() { return new Vec3d(getPos()).add(getOBBCenter(getPos())); } - + public ItemStack asItemStack() { return new ItemStack(getBlock(), 1, getMetadata()); } - + public boolean isInvalid() { return Blocks.AIR.equals(getBlock()); } - + public boolean isEqual(BlockPos pos) { IBlockState state = getWorld().getBlockState(pos); Block bl = state.getBlock(); return Objects.equals(getBlock(), bl) && getMetadata() == bl.getMetaFromState(state); } - + @Override public boolean equals(Object obj) { return this == obj - || (obj instanceof UniqueBlock - && getBlock().equals(((UniqueBlock) obj).getBlock()) - && getMetadata() == ((UniqueBlock) obj).getMetadata()); + || (obj instanceof UniqueBlock + && getBlock().equals(((UniqueBlock) obj).getBlock()) + && getMetadata() == ((UniqueBlock) obj).getMetadata()); } - + @Override public String toString() { return getBlock().getRegistryName().toString() + "{" + getMetadata() + "}"; } } - + public static class BlockActivationChecker { + private static final Object2BooleanArrayMap> CACHE = new Object2BooleanArrayMap<>(); - + public static boolean isOverwritten(final Block instance) { Objects.requireNonNull(instance); return CACHE.computeIfAbsent( - instance.getClass(), - clazz -> - Block.class - != ReflectionHelper.getMethodDeclaringClass(Block_onBlockActivated, instance)); + instance.getClass(), + clazz -> + Block.class + != ReflectionHelper.getMethodDeclaringClass(Block_onBlockActivated, instance)); } } } diff --git a/src/main/java/com/matt/forgehax/util/CaseInsensitive.java b/src/main/java/com/matt/forgehax/util/CaseInsensitive.java deleted file mode 100644 index 6b448769e..000000000 --- a/src/main/java/com/matt/forgehax/util/CaseInsensitive.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.matt.forgehax.util; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** Created on 4/19/2018 by fr1kin */ -@Retention(RetentionPolicy.SOURCE) -public @interface CaseInsensitive {} diff --git a/src/main/java/com/matt/forgehax/util/CaseSensitive.java b/src/main/java/com/matt/forgehax/util/CaseSensitive.java deleted file mode 100644 index 77f6433cc..000000000 --- a/src/main/java/com/matt/forgehax/util/CaseSensitive.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.matt.forgehax.util; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** Created on 4/19/2018 by fr1kin */ -// @Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, -// ElementType.CONSTRUCTOR}) -@Retention(RetentionPolicy.SOURCE) -public @interface CaseSensitive {} diff --git a/src/main/java/com/matt/forgehax/util/FileHelper.java b/src/main/java/com/matt/forgehax/util/FileHelper.java index 1da9a81a6..d1e197075 100644 --- a/src/main/java/com/matt/forgehax/util/FileHelper.java +++ b/src/main/java/com/matt/forgehax/util/FileHelper.java @@ -11,10 +11,13 @@ import javax.annotation.Nullable; import joptsimple.internal.Strings; -/** Created on 2/16/2018 by fr1kin */ +/** + * Created on 2/16/2018 by fr1kin + */ public class FileHelper { + private static final Pattern PATTERN_PACKAGE_FROM_PATH = - Pattern.compile("[.]jar[!][\\/|\\\\](.*)"); + Pattern.compile("[.]jar[!][\\/|\\\\](.*)"); private static final Pattern PATTERN_JAR_DIR_FROM_PATH = Pattern.compile("(.*.jar)"); private static final Pattern PATTERN_FILE_SEPARATORS = Pattern.compile("[\\\\|\\/]"); @@ -56,12 +59,17 @@ public static String getPathWithoutExtension(Path path) { } public static String asPackagePath(@Nullable String filePath) { - if (filePath == null) return ""; + if (filePath == null) { + return ""; + } String str = getPathWithoutExtension(filePath); // remove the extension (if there is one) str = PATTERN_FILE_SEPARATORS.matcher(str).replaceAll("."); // replace '/' and '\' with '.' - if (str.startsWith(".")) str = str.substring(1); // jar files will start with a '/' - if (str.endsWith(".")) + if (str.startsWith(".")) { + str = str.substring(1); // jar files will start with a '/' + } + if (str.endsWith(".")) { str = str.substring(0, str.length() - 1); // if the path ended with '/' that will be removed + } return str; } diff --git a/src/main/java/com/matt/forgehax/log/FileManager.java b/src/main/java/com/matt/forgehax/util/FileManager.java similarity index 79% rename from src/main/java/com/matt/forgehax/log/FileManager.java rename to src/main/java/com/matt/forgehax/util/FileManager.java index 06f6d5941..ae97aad75 100644 --- a/src/main/java/com/matt/forgehax/log/FileManager.java +++ b/src/main/java/com/matt/forgehax/util/FileManager.java @@ -1,4 +1,4 @@ -package com.matt.forgehax.log; +package com.matt.forgehax.util; import java.io.File; import java.io.IOException; @@ -9,91 +9,100 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -/** Created on 5/30/2017 by fr1kin */ +/** + * Created on 5/30/2017 by fr1kin + */ public class FileManager { + private static final FileManager INSTANCE = new FileManager(); - + public static FileManager getInstance() { return INSTANCE; } - + private static String[] expandPath(String fullPath) { return fullPath.split(":?\\\\\\\\|\\/"); } - + private static Stream expandPaths(String... paths) { return Arrays.stream(paths).map(FileManager::expandPath).flatMap(Arrays::stream); } - + private static Path lookupPath(Path root, String... paths) { return Paths.get(root.toString(), paths); } - + private static Path getRoot() { return Paths.get(""); } - + private static void createDirectory(Path dir) { try { if (!Files.isDirectory(dir)) { - if (Files.exists(dir)) Files.delete(dir); // delete if it exists but isn't a directory - + if (Files.exists(dir)) { + Files.delete(dir); // delete if it exists but isn't a directory + } + Files.createDirectories(dir); } } catch (IOException e) { e.printStackTrace(); } } - + private static Path getMkDirectory(Path parent, String... paths) { - if (paths.length < 1) return parent; - + if (paths.length < 1) { + return parent; + } + Path dir = lookupPath(parent, paths); createDirectory(dir); return dir; } - + private final Path base; - + private FileManager() { base = getMkDirectory(getRoot(), "forgehax"); // create directories for these common getMkDirectory(base, "config"); getMkDirectory(base, "cache"); } - + public Path getBasePath() { return base; } - + public Path getBaseResolve(String... paths) { String[] names = expandPaths(paths).toArray(String[]::new); - if (names.length < 1) throw new IllegalArgumentException("missing path"); - + if (names.length < 1) { + throw new IllegalArgumentException("missing path"); + } + return lookupPath(getBasePath(), names); } - + public Path getMkBaseResolve(String... paths) { Path path = getBaseResolve(paths); createDirectory(path.getParent()); return path; } - + public Path getConfig() { return getBasePath().resolve("config"); } - + public Path getCache() { return getBasePath().resolve("cache"); } - + public Path getMkBaseDirectory(String... names) { return getMkDirectory( - getBasePath(), expandPaths(names).collect(Collectors.joining(File.separator))); + getBasePath(), expandPaths(names).collect(Collectors.joining(File.separator))); } - + public Path getMkConfigDirectory(String... names) { return getMkDirectory( - getConfig(), expandPaths(names).collect(Collectors.joining(File.separator))); + getConfig(), expandPaths(names).collect(Collectors.joining(File.separator))); } } diff --git a/src/main/java/com/matt/forgehax/util/ImageUtils.java b/src/main/java/com/matt/forgehax/util/ImageUtils.java index b2332e2ad..d3e57adbc 100644 --- a/src/main/java/com/matt/forgehax/util/ImageUtils.java +++ b/src/main/java/com/matt/forgehax/util/ImageUtils.java @@ -1,16 +1,20 @@ package com.matt.forgehax.util; import com.matt.forgehax.Globals; -import java.awt.*; +import java.awt.AlphaComposite; +import java.awt.Graphics2D; +import java.awt.Image; import java.awt.image.BufferedImage; import java.net.URL; import javax.imageio.ImageIO; -/** Created by Babbaj on 11/7/2017. */ +/** + * Created by Babbaj on 11/7/2017. + */ public class ImageUtils implements Globals { public static BufferedImage createResizedCopy( - Image originalImage, int scaledWidth, int scaledHeight, boolean preserveAlpha) { + Image originalImage, int scaledWidth, int scaledHeight, boolean preserveAlpha) { int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType); Graphics2D g = scaledBI.createGraphics(); diff --git a/src/main/java/com/matt/forgehax/util/Immutables.java b/src/main/java/com/matt/forgehax/util/Immutables.java index d6ec6b7cb..3eb75c8b5 100644 --- a/src/main/java/com/matt/forgehax/util/Immutables.java +++ b/src/main/java/com/matt/forgehax/util/Immutables.java @@ -2,7 +2,11 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Function; @@ -12,23 +16,36 @@ // credits to http://www.nurkiewicz.com/2014/07/introduction-to-writing-custom.html -/** Created on 2/6/2018 by fr1kin */ +/** + * Created on 2/6/2018 by fr1kin + */ public class Immutables { + public static Collection copy(@Nullable Collection collection) { return copyToList(collection); } public static List copyToList(@Nullable Collection collection) { - if (collection == null || collection.isEmpty()) return Collections.emptyList(); - if (collection instanceof ImmutableList) return (List) collection; - else if (collection.size() == 1) return Collections.singletonList(collection.iterator().next()); - else return ImmutableList.copyOf(collection); + if (collection == null || collection.isEmpty()) { + return Collections.emptyList(); + } + if (collection instanceof ImmutableList) { + return (List) collection; + } else if (collection.size() == 1) { + return Collections.singletonList(collection.iterator().next()); + } else { + return ImmutableList.copyOf(collection); + } } public static Set copyToSet(@Nullable Collection collection) { - if (collection == null || collection.isEmpty()) return Collections.emptySet(); - else if (collection.size() == 1) return Collections.singleton(collection.iterator().next()); - else return ImmutableSet.copyOf(collection); + if (collection == null || collection.isEmpty()) { + return Collections.emptySet(); + } else if (collection.size() == 1) { + return Collections.singleton(collection.iterator().next()); + } else { + return ImmutableSet.copyOf(collection); + } } public static Collector, ImmutableSet> toImmutableSet() { @@ -40,7 +57,8 @@ public static Collector, ImmutableList> toImm } private static class ImmutableSetCollector - implements Collector, ImmutableSet> { + implements Collector, ImmutableSet> { + @Override public Supplier> supplier() { return ImmutableSet::builder; @@ -71,7 +89,8 @@ public Set characteristics() { } private static class ImmutableListCollector - implements Collector, ImmutableList> { + implements Collector, ImmutableList> { + @Override public Supplier> supplier() { return ImmutableList::builder; diff --git a/src/main/java/com/matt/forgehax/util/MapColors.java b/src/main/java/com/matt/forgehax/util/MapColors.java index 0f8734cc9..4491b1d4c 100644 --- a/src/main/java/com/matt/forgehax/util/MapColors.java +++ b/src/main/java/com/matt/forgehax/util/MapColors.java @@ -1,13 +1,20 @@ package com.matt.forgehax.util; +import com.matt.forgehax.util.color.Color; import net.minecraft.block.material.MapColor; -/** Created by Babbaj on 8/19/2017. */ +/** + * Created by Babbaj on 8/19/2017. + */ public class MapColors { - - /** list of all possible colors used on maps, 4 for each base color */ + + /** + * list of all possible colors used on maps, 4 for each base color + */ private static final int[] COLOR_LIST; - /** list of base colors from {@link net.minecraft.block.material.MapColor} */ + /** + * list of base colors from {@link net.minecraft.block.material.MapColor} + */ private static final int[] BASE_COLORS; static { @@ -22,23 +29,34 @@ public class MapColors { BASE_COLORS = new int[baseColorsLength]; COLOR_LIST = new int[baseColorsLength * 4]; - for (int i = 0; - i < BASE_COLORS.length; - i++) { // get integer color values from MapColor object list + for (int i = 0; i < BASE_COLORS.length; i++) { + // get integer color values from MapColor object list BASE_COLORS[i] = MapColor.COLORS[i].colorValue; } for (int i = 0; - i < BASE_COLORS.length; - i++) { // generates full list of colors from the list of base colors - int[] rgb = Utils.toRGBAArray(BASE_COLORS[i]); - COLOR_LIST[i * 4 + 0] = - Utils.toRGBA((rgb[0] * 180) / 255, (rgb[1] * 180) / 255, (rgb[2] * 180) / 255, 0); - COLOR_LIST[i * 4 + 1] = - Utils.toRGBA((rgb[0] * 220) / 255, (rgb[1] * 220) / 255, (rgb[2] * 220) / 255, 0); + i < BASE_COLORS.length; + i++) { // generates full list of colors from the list of base colors + int[] rgb = Color.of(BASE_COLORS[i]).toIntegerArray(); + COLOR_LIST[i * 4] = Color.of( + (rgb[0] * 180) / 255, + (rgb[1] * 180) / 255, + (rgb[2] * 180) / 255, + 0 + ).toBuffer(); + COLOR_LIST[i * 4 + 1] = Color.of( + (rgb[0] * 220) / 255, + (rgb[1] * 220) / 255, + (rgb[2] * 220) / 255, + 0 + ).toBuffer(); COLOR_LIST[i * 4 + 2] = BASE_COLORS[i]; - COLOR_LIST[i * 4 + 3] = - Utils.toRGBA((rgb[0] * 135) / 255, (rgb[1] * 135) / 255, (rgb[2] * 135) / 255, 0); + COLOR_LIST[i * 4 + 3] = Color.of( + (rgb[0] * 135) / 255, + (rgb[1] * 135) / 255, + (rgb[2] * 135) / 255, + 0 + ).toBuffer(); } } diff --git a/src/main/java/com/matt/forgehax/util/PacketHelper.java b/src/main/java/com/matt/forgehax/util/PacketHelper.java index 4298400c6..752edbbd1 100644 --- a/src/main/java/com/matt/forgehax/util/PacketHelper.java +++ b/src/main/java/com/matt/forgehax/util/PacketHelper.java @@ -9,18 +9,20 @@ import java.util.concurrent.TimeUnit; import net.minecraft.network.Packet; -/** Created on 8/4/2017 by fr1kin */ +/** + * Created on 8/4/2017 by fr1kin + */ public class PacketHelper { + private static final LoadingCache CACHE = - CacheBuilder.newBuilder() - .expireAfterWrite(15L, TimeUnit.SECONDS) - .build( - new CacheLoader() { - @Override - public Boolean load(Packet key) throws Exception { - return false; - } - }); + CacheBuilder.newBuilder() + .expireAfterWrite(15L, TimeUnit.SECONDS) + .build(new CacheLoader() { + @Override + public Boolean load(Packet key) throws Exception { + return false; + } + }); public static void ignore(Packet packet) { CACHE.put(packet, true); diff --git a/src/main/java/com/matt/forgehax/util/SafeConverter.java b/src/main/java/com/matt/forgehax/util/SafeConverter.java index c2b4e0219..bebc1e47d 100644 --- a/src/main/java/com/matt/forgehax/util/SafeConverter.java +++ b/src/main/java/com/matt/forgehax/util/SafeConverter.java @@ -3,11 +3,14 @@ import com.matt.forgehax.util.command.CommandHelper; import java.util.Objects; -/** Created on 5/18/2017 by fr1kin */ +/** + * Created on 5/18/2017 by fr1kin + */ public class SafeConverter { + private static final String ACCEPTABLE_TRUE_BOOLEAN_STRINGS = - CommandHelper.join( - new String[] {Boolean.TRUE.toString(), "t", "on", "enable", "enabled"}, "|"); + CommandHelper.join( + new String[]{Boolean.TRUE.toString(), "t", "on", "enable", "enabled"}, "|"); // // BOOLEAN @@ -15,8 +18,9 @@ public class SafeConverter { public static boolean toBoolean(Object o, boolean defaultValue) { try { Objects.requireNonNull(o); - if (o instanceof Boolean) return ((Boolean) o); - else { + if (o instanceof Boolean) { + return ((Boolean) o); + } else { String str = String.valueOf(o); try { return Integer.valueOf(str) != 0; @@ -40,8 +44,9 @@ public static boolean toBoolean(Object o) { public static byte toByte(Object o, byte defaultValue) { try { Objects.requireNonNull(o); - if (o instanceof Number) return ((Number) o).byteValue(); - else { + if (o instanceof Number) { + return ((Number) o).byteValue(); + } else { String str = String.valueOf(o); return Byte.parseByte(str); } @@ -61,8 +66,9 @@ public static byte toByte(Object o) { public static char toCharacter(Object o, char defaultValue) { try { Objects.requireNonNull(o); - if (o instanceof Character) return (Character) o; - else { + if (o instanceof Character) { + return (Character) o; + } else { String str = String.valueOf(o); return str.charAt(0); } @@ -82,8 +88,9 @@ public static char toCharacter(Object o) { public static double toDouble(Object o, double defaultValue) { try { Objects.requireNonNull(o); - if (o instanceof Number) return ((Number) o).doubleValue(); - else { + if (o instanceof Number) { + return ((Number) o).doubleValue(); + } else { String str = String.valueOf(o); return Double.parseDouble(str); } @@ -103,8 +110,9 @@ public static double toDouble(Object o) { public static float toFloat(Object o, float defaultValue) { try { Objects.requireNonNull(o); - if (o instanceof Number) return ((Number) o).floatValue(); - else { + if (o instanceof Number) { + return ((Number) o).floatValue(); + } else { String str = String.valueOf(o); return Float.parseFloat(str); } @@ -124,8 +132,11 @@ public static float toFloat(Object o) { public static int toInteger(Object o, int defaultValue) { try { Objects.requireNonNull(o); - if (o instanceof Number) return ((Number) o).intValue(); - else return Integer.valueOf(String.valueOf(o)); + if (o instanceof Number) { + return ((Number) o).intValue(); + } else { + return Integer.valueOf(String.valueOf(o)); + } } catch (Throwable t) { return defaultValue; } @@ -142,8 +153,9 @@ public static int toInteger(Object o) { public static long toLong(Object o, long defaultValue) { try { Objects.requireNonNull(o); - if (o instanceof Number) return ((Number) o).longValue(); - else { + if (o instanceof Number) { + return ((Number) o).longValue(); + } else { String str = String.valueOf(o); return Long.parseLong(str); } @@ -163,8 +175,9 @@ public static long toLong(Object o) { public static short toShort(Object o, short defaultValue) { try { Objects.requireNonNull(o); - if (o instanceof Number) return ((Number) o).shortValue(); - else { + if (o instanceof Number) { + return ((Number) o).shortValue(); + } else { String str = String.valueOf(o); return Short.parseShort(str); } diff --git a/src/main/java/com/matt/forgehax/util/SimpleTimer.java b/src/main/java/com/matt/forgehax/util/SimpleTimer.java index 418508d8d..202679c09 100644 --- a/src/main/java/com/matt/forgehax/util/SimpleTimer.java +++ b/src/main/java/com/matt/forgehax/util/SimpleTimer.java @@ -6,8 +6,11 @@ import java.util.TimeZone; import java.util.concurrent.TimeUnit; -/** Created on 8/22/2017 by fr1kin */ +/** + * Created on 8/22/2017 by fr1kin + */ public class SimpleTimer { + private static final DateFormat TIME_FORMATTER = new SimpleDateFormat("HH:mm:ss.SSS"); private static final DateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); @@ -27,7 +30,9 @@ public static String toFormattedDate(long time) { private long timeStopped = -1; public SimpleTimer(boolean startOnInit) { - if (startOnInit) start(); + if (startOnInit) { + start(); + } } public SimpleTimer() { @@ -89,8 +94,11 @@ public String getFormattedTimeElapsed() { protected static String formatInterval(long delta) { final long hr = TimeUnit.MILLISECONDS.toHours(delta); final long min = TimeUnit.MILLISECONDS.toMinutes(delta - TimeUnit.HOURS.toMillis(hr)); - final long sec = TimeUnit.MILLISECONDS.toSeconds(delta - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min)); - final long ms = TimeUnit.MILLISECONDS.toMillis(delta - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec)); + final long sec = TimeUnit.MILLISECONDS + .toSeconds(delta - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min)); + final long ms = TimeUnit.MILLISECONDS.toMillis( + delta - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS + .toMillis(sec)); return String.format("%02d:%02d:%02d.%03d", hr, min, sec, ms); } } diff --git a/src/main/java/com/matt/forgehax/util/Streamables.java b/src/main/java/com/matt/forgehax/util/Streamables.java index db1a0479f..5664eb536 100644 --- a/src/main/java/com/matt/forgehax/util/Streamables.java +++ b/src/main/java/com/matt/forgehax/util/Streamables.java @@ -7,12 +7,15 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -/** Created on 2/15/2018 by fr1kin */ +/** + * Created on 2/15/2018 by fr1kin + */ public class Streamables { + public static Stream enumerationStream(Enumeration enumeration) { return StreamSupport.stream( - Spliterators.spliteratorUnknownSize( - Iterators.forEnumeration(enumeration), Spliterator.ORDERED), - false); + Spliterators.spliteratorUnknownSize( + Iterators.forEnumeration(enumeration), Spliterator.ORDERED), + false); } } diff --git a/src/main/java/com/matt/forgehax/util/Switch.java b/src/main/java/com/matt/forgehax/util/Switch.java index 187e545eb..4fc88db1d 100644 --- a/src/main/java/com/matt/forgehax/util/Switch.java +++ b/src/main/java/com/matt/forgehax/util/Switch.java @@ -5,6 +5,7 @@ import java.util.Set; public abstract class Switch { + private final Set handles = Sets.newHashSet(); private final String name; @@ -17,10 +18,11 @@ public Switch(String name) { public Handle createHandle(String id) { Handle handle = new Handle(this, id); synchronized (handles) { - if(handles.add(handle)) + if (handles.add(handle)) { return handle; - else + } else { throw new Error("failed to add handle with id '" + id + "'"); + } } } @@ -47,6 +49,7 @@ public boolean isDisabled() { } protected abstract void onEnabled(); + protected abstract void onDisabled(); @Override @@ -56,6 +59,7 @@ public String toString() { // a more efficient way to toggle the state without having the iterate the array list everytime public static class Handle { + private final Switch parent; private final String id; @@ -69,23 +73,25 @@ private Handle(Switch parent, String id) { } public void enable() { - if(!enabled) { + if (!enabled) { enabled = true; parent.enable(); } - - if(parent.isEnabled()) + + if (parent.isEnabled()) { parent.onEnabled(); + } } public void disable() { - if(enabled) { + if (enabled) { enabled = false; parent.disable(); } - - if(parent.isDisabled()) + + if (parent.isDisabled()) { parent.onDisabled(); + } } @Override @@ -95,7 +101,8 @@ public int hashCode() { @Override public boolean equals(Object obj) { - return this == obj || (obj instanceof Handle && parent.equals(((Handle) obj).parent) && id == ((Handle) obj).id); + return this == obj || (obj instanceof Handle && parent.equals(((Handle) obj).parent) + && id == ((Handle) obj).id); } @Override diff --git a/src/main/java/com/matt/forgehax/util/TickrateCounter.java b/src/main/java/com/matt/forgehax/util/TickrateCounter.java index 2e895dde6..0103d7477 100644 --- a/src/main/java/com/matt/forgehax/util/TickrateCounter.java +++ b/src/main/java/com/matt/forgehax/util/TickrateCounter.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class TickrateCounter { + private static double tr = 0.D; public static double getTickrate() { diff --git a/src/main/java/com/matt/forgehax/util/Utils.java b/src/main/java/com/matt/forgehax/util/Utils.java index 7dc3a76d6..f754d67df 100644 --- a/src/main/java/com/matt/forgehax/util/Utils.java +++ b/src/main/java/com/matt/forgehax/util/Utils.java @@ -6,61 +6,28 @@ import com.matt.forgehax.util.entity.EntityUtils; import com.matt.forgehax.util.math.Angle; import com.matt.forgehax.util.math.AngleHelper; -import java.util.*; +import java.util.Collection; +import java.util.List; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.minecraft.entity.Entity; import net.minecraft.inventory.ItemStackHelper; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.Packet; import net.minecraft.util.NonNullList; import net.minecraft.util.math.Vec3d; public class Utils implements Globals { - - /** Use PacketHelper class now */ - @Deprecated - public static final List OUTGOING_PACKET_IGNORE_LIST = Collections.emptyList(); - - @Deprecated - public static int toRGBA(int r, int g, int b, int a) { - return (r << 16) + (g << 8) + (b << 0) + (a << 24); - } - - @Deprecated - public static int toRGBA(float r, float g, float b, float a) { - return toRGBA((int) (r * 255.f), (int) (g * 255.f), (int) (b * 255.f), (int) (a * 255.f)); - } - - @Deprecated - public static int toRGBA(float[] colors) { - if (colors.length != 4) throw new IllegalArgumentException("colors[] must have a length of 4!"); - return toRGBA(colors[0], colors[1], colors[2], colors[3]); - } - - @Deprecated - public static int toRGBA(double[] colors) { - if (colors.length != 4) throw new IllegalArgumentException("colors[] must have a length of 4!"); - return toRGBA((float) colors[0], (float) colors[1], (float) colors[2], (float) colors[3]); - } - - @Deprecated - public static int[] toRGBAArray(int colorBuffer) { - return new int[] { - (colorBuffer >> 16 & 255), - (colorBuffer >> 8 & 255), - (colorBuffer & 255), - (colorBuffer >> 24 & 255) - }; - } - + public static > String[] toArray(E[] o) { String[] output = new String[o.length]; - for (int i = 0; i < output.length; i++) output[i] = o[i].name(); + for (int i = 0; i < output.length; i++) { + output[i] = o[i].name(); + } return output; } - + public static UUID stringToUUID(String uuid) { if (uuid.contains("-")) { // if it contains the hyphen we don't have to manually put them in @@ -72,50 +39,50 @@ public static UUID stringToUUID(String uuid) { return UUID.fromString(matcher.replaceAll("$1-$2-$3-$4-$5")); } } - + public static double normalizeAngle(double angle) { - while (angle <= -180) angle += 360; - while (angle > 180) angle -= 360; + while (angle <= -180) { + angle += 360; + } + while (angle > 180) { + angle -= 360; + } return angle; } - + public static double clamp(double value, double min, double max) { return Math.max(min, Math.min(max, value)); } - + public static float clamp(float value, float min, float max) { return Math.max(min, Math.min(max, value)); } - + public static Angle getLookAtAngles(Vec3d start, Vec3d end) { return AngleHelper.getAngleFacingInDegrees(end.subtract(start)).normalize(); } - + public static Angle getLookAtAngles(Vec3d end) { return getLookAtAngles(EntityUtils.getEyePos(getLocalPlayer()), end); } - + public static Angle getLookAtAngles(Entity entity) { return getLookAtAngles(EntityUtils.getOBBCenter(entity)); } - + public static double scale( - double x, double from_min, double from_max, double to_min, double to_max) { + double x, double from_min, double from_max, double to_min, double to_max) { return to_min + (to_max - to_min) * ((x - from_min) / (from_max - from_min)); } - - public static boolean isInRange(T[] array, int index) { - return array != null && index >= 0 && index < array.length; - } - + public static boolean isInRange(Collection list, int index) { return list != null && index >= 0 && index < list.size(); } - + public static T defaultTo(T value, T defaultTo) { return value == null ? defaultTo : value; } - + public static List getShulkerContents(ItemStack stack) { // TODO: move somewhere else NonNullList contents = NonNullList.withSize(27, ItemStack.EMPTY); NBTTagCompound compound = stack.getTagCompound(); @@ -128,18 +95,4 @@ public static List getShulkerContents(ItemStack stack) { // TODO: mov } return contents; } - - @Deprecated - public static class Colors { - public static final int WHITE = Utils.toRGBA(255, 255, 255, 255); - public static final int BLACK = Utils.toRGBA(0, 0, 0, 255); - public static final int RED = Utils.toRGBA(255, 0, 0, 255); - public static final int GREEN = Utils.toRGBA(0, 255, 0, 255); - public static final int BLUE = Utils.toRGBA(0, 0, 255, 255); - public static final int ORANGE = Utils.toRGBA(255, 128, 0, 255); - public static final int PURPLE = Utils.toRGBA(163, 73, 163, 255); - public static final int GRAY = Utils.toRGBA(127, 127, 127, 255); - public static final int DARK_RED = Utils.toRGBA(64, 0, 0, 255); - public static final int YELLOW = Utils.toRGBA(255, 255, 0, 255); - } } diff --git a/src/main/java/com/matt/forgehax/util/blocks/BlockEntry.java b/src/main/java/com/matt/forgehax/util/blocks/BlockEntry.java index 29246632e..aac546d0f 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/BlockEntry.java +++ b/src/main/java/com/matt/forgehax/util/blocks/BlockEntry.java @@ -9,14 +9,21 @@ import com.matt.forgehax.util.blocks.properties.PropertyFactory; import com.matt.forgehax.util.serialization.ISerializableJson; import java.io.IOException; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; import javax.annotation.Nonnull; import joptsimple.internal.Strings; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -/** Created on 5/19/2017 by fr1kin */ +/** + * Created on 5/19/2017 by fr1kin + */ public class BlockEntry implements ISerializableJson, Globals { + private enum OpenMode { READ, WRITE, @@ -48,7 +55,9 @@ public BlockEntry(String uniqueId) { public BlockEntry(Block block, int meta, boolean check) throws BlockDoesNotExistException { meta = Math.max(meta, 0); - if (check) BlockOptionHelper.requiresValidBlock(block, meta); + if (check) { + BlockOptionHelper.requiresValidBlock(block, meta); + } this.block = block; this.meta = BlockOptionHelper.getAllBlocks(block).size() > 1 ? meta : -1; this.uniqueId = getResourceName() + (isMetadata() ? ("::" + getMetadata()) : Strings.EMPTY); @@ -80,17 +89,17 @@ public String getUniqueName() { public String getResourceName() { return block != null - ? (block.getRegistryName() != null ? block.getRegistryName().toString() : block.toString()) - : Strings.EMPTY; + ? (block.getRegistryName() != null ? block.getRegistryName().toString() : block.toString()) + : Strings.EMPTY; } public String getPrettyName() { return block != null - ? ((block.getRegistryName() != null - ? block.getRegistryName().getResourcePath() - : block.toString()) - + (isMetadata() ? ":" + meta : Strings.EMPTY)) - : Strings.EMPTY; + ? ((block.getRegistryName() != null + ? block.getRegistryName().getResourcePath() + : block.toString()) + + (isMetadata() ? ":" + meta : Strings.EMPTY)) + : Strings.EMPTY; } public Block getBlock() { @@ -111,17 +120,17 @@ private T getProperty(@Nonnull Class clazz, OpenMo return properties.getOrDefault(clazz, PropertyFactory.getImmutableInstance(clazz)).cast(); case WRITE: return properties - .computeIfAbsent( - clazz, - c -> { - IBlockProperty property = PropertyFactory.newInstance(c); - registerProperty(property); - return property; - }) - .cast(); + .computeIfAbsent( + clazz, + c -> { + IBlockProperty property = PropertyFactory.newInstance(c); + registerProperty(property); + return property; + }) + .cast(); } throw new IllegalArgumentException( - String.format("No such property \"%s\" (Possibly not registered?)", clazz.getSimpleName())); + String.format("No such property \"%s\" (Possibly not registered?)", clazz.getSimpleName())); } /** @@ -150,11 +159,16 @@ public T getReadableProperty(@Nonnull Class clazz) public T getWritableProperty(@Nonnull Class clazz) { return getProperty(clazz, OpenMode.WRITE); } - - /** Unregisters any property that is not necessary. Call this after using getWritableProperty */ + + /** + * Unregisters any property that is not necessary. Call this after using getWritableProperty + */ public void cleanupProperties() { - for (IBlockProperty property : properties.values()) - if (!property.isNecessary()) unregisterProperty(property); + for (IBlockProperty property : properties.values()) { + if (!property.isNecessary()) { + unregisterProperty(property); + } + } } boolean isEqual(Block block, int meta) { @@ -170,7 +184,9 @@ public String helpText() { builder.append(option.toString()); builder.append("="); builder.append(option.helpText()); - if (it.hasNext()) builder.append(", "); + if (it.hasNext()) { + builder.append(", "); + } } builder.append("}"); return builder.toString(); @@ -206,13 +222,15 @@ public void deserialize(final JsonReader reader) throws IOException { @Override public boolean equals(Object obj) { - if (obj instanceof BlockEntry) + if (obj instanceof BlockEntry) { return getUniqueName().compareTo(((BlockEntry) obj).getUniqueName()) == 0; - else if (obj instanceof IBlockState) { + } else if (obj instanceof IBlockState) { return isEqual( - ((IBlockState) obj).getBlock(), - ((IBlockState) obj).getBlock().getMetaFromState((IBlockState) obj)); - } else return hashCode() == obj.hashCode(); + ((IBlockState) obj).getBlock(), + ((IBlockState) obj).getBlock().getMetaFromState((IBlockState) obj)); + } else { + return hashCode() == obj.hashCode(); + } } @Override diff --git a/src/main/java/com/matt/forgehax/util/blocks/BlockOptionHelper.java b/src/main/java/com/matt/forgehax/util/blocks/BlockOptionHelper.java index a9c3a2e9e..20ceebc31 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/BlockOptionHelper.java +++ b/src/main/java/com/matt/forgehax/util/blocks/BlockOptionHelper.java @@ -15,8 +15,11 @@ import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; -/** Created on 5/18/2017 by fr1kin */ +/** + * Created on 5/18/2017 by fr1kin + */ public class BlockOptionHelper { + public static boolean isAir(String name) { return Objects.equals(Blocks.AIR.getRegistryName(), new ResourceLocation(name)); } @@ -34,20 +37,22 @@ public static Collection getAllBlocks(Block block) { } public static void getAllBlocksMatchingByUnlocalized( - final Collection found, String regex) { + final Collection found, String regex) { final Pattern pattern = Pattern.compile(regex); Block.REGISTRY.forEach( - block -> - getAllBlocks(block) - .forEach( - stack -> { - Matcher matcher = pattern.matcher(stack.getUnlocalizedName().toLowerCase()); - if (matcher.find()) - try { - found.add(new BlockEntry(block, stack.getMetadata(), false)); - } catch (BlockDoesNotExistException e) {; - } - })); + block -> + getAllBlocks(block) + .forEach( + stack -> { + Matcher matcher = pattern.matcher(stack.getUnlocalizedName().toLowerCase()); + if (matcher.find()) { + try { + found.add(new BlockEntry(block, stack.getMetadata(), false)); + } catch (BlockDoesNotExistException e) { + ; + } + } + })); } public static Collection getAllBlocksMatchingByUnlocalized(String regex) { @@ -57,22 +62,24 @@ public static Collection getAllBlocksMatchingByUnlocalized(String re } public static void getAllBlocksMatchingByLocalized( - final Collection found, String regex) { + final Collection found, String regex) { final Pattern pattern = Pattern.compile(regex); Block.REGISTRY.forEach( - block -> - getAllBlocks(block) - .forEach( - stack -> { - Matcher matcher = - pattern.matcher( - stack.getDisplayName().replaceAll(" ", "_").toLowerCase()); - if (matcher.find()) - try { - found.add(new BlockEntry(block, stack.getMetadata(), false)); - } catch (BlockDoesNotExistException e) {; - } - })); + block -> + getAllBlocks(block) + .forEach( + stack -> { + Matcher matcher = + pattern.matcher( + stack.getDisplayName().replaceAll(" ", "_").toLowerCase()); + if (matcher.find()) { + try { + found.add(new BlockEntry(block, stack.getMetadata(), false)); + } catch (BlockDoesNotExistException e) { + ; + } + } + })); } public static Collection getAllBlocksMatchingByLocalized(String regex) { @@ -89,18 +96,26 @@ public static Collection getAllBlockMatching(String regex) { } public static boolean isValidMetadataValue(Block block, int meta) { - for (ItemStack stack : getAllBlocks(block)) if (stack.getMetadata() == meta) return true; + for (ItemStack stack : getAllBlocks(block)) { + if (stack.getMetadata() == meta) { + return true; + } + } return false; } public static BlockData fromUniqueName(String uniqueName) - throws BlockDoesNotExistException, BadBlockEntryFormatException { + throws BlockDoesNotExistException, BadBlockEntryFormatException { String[] split = uniqueName.split("::"); - if (split.length < 1) throw new BadBlockEntryFormatException(); + if (split.length < 1) { + throw new BadBlockEntryFormatException(); + } String name = split[0]; int meta = SafeConverter.toInteger(split.length > 1 ? split[1] : -1, -1); Block block = Block.getBlockFromName(name); - if (block == null) throw new BlockDoesNotExistException(uniqueName + " is not a valid block"); + if (block == null) { + throw new BlockDoesNotExistException(uniqueName + " is not a valid block"); + } BlockData data = new BlockData(); data.block = block; data.meta = meta; @@ -108,17 +123,20 @@ public static BlockData fromUniqueName(String uniqueName) } public static void requiresValidBlock(Block block, int metadataId) - throws BlockDoesNotExistException { - if (block == null || block.equals(Blocks.AIR)) + throws BlockDoesNotExistException { + if (block == null || block.equals(Blocks.AIR)) { throw new BlockDoesNotExistException("Attempted to create entry for a non-existent block"); - if (!BlockOptionHelper.isValidMetadataValue(block, metadataId)) + } + if (!BlockOptionHelper.isValidMetadataValue(block, metadataId)) { throw new BlockDoesNotExistException( - String.format( - "Attempted to create entry for block \"%s\" with a invalid meta id of \"%d\"", - block.getRegistryName().toString(), metadataId)); + String.format( + "Attempted to create entry for block \"%s\" with a invalid meta id of \"%d\"", + block.getRegistryName().toString(), metadataId)); + } } public static class BlockData { + public Block block = null; public int meta = -1; } diff --git a/src/main/java/com/matt/forgehax/util/blocks/exceptions/BadBlockEntryFormatException.java b/src/main/java/com/matt/forgehax/util/blocks/exceptions/BadBlockEntryFormatException.java index 5b2f2c6e4..1f2d13821 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/exceptions/BadBlockEntryFormatException.java +++ b/src/main/java/com/matt/forgehax/util/blocks/exceptions/BadBlockEntryFormatException.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.blocks.exceptions; -/** Created on 5/19/2017 by fr1kin */ +/** + * Created on 5/19/2017 by fr1kin + */ public class BadBlockEntryFormatException extends Exception { + public BadBlockEntryFormatException() { super(); } diff --git a/src/main/java/com/matt/forgehax/util/blocks/exceptions/BlockDoesNotExistException.java b/src/main/java/com/matt/forgehax/util/blocks/exceptions/BlockDoesNotExistException.java index d0d9806ab..8e07c037f 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/exceptions/BlockDoesNotExistException.java +++ b/src/main/java/com/matt/forgehax/util/blocks/exceptions/BlockDoesNotExistException.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.blocks.exceptions; -/** Created on 5/15/2017 by fr1kin */ +/** + * Created on 5/15/2017 by fr1kin + */ public class BlockDoesNotExistException extends Exception { + public BlockDoesNotExistException(String msg) { super(msg); } diff --git a/src/main/java/com/matt/forgehax/util/blocks/properties/BoundProperty.java b/src/main/java/com/matt/forgehax/util/blocks/properties/BoundProperty.java index 274e69e01..a63a41e99 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/properties/BoundProperty.java +++ b/src/main/java/com/matt/forgehax/util/blocks/properties/BoundProperty.java @@ -9,8 +9,11 @@ import java.util.Iterator; import javax.annotation.Nullable; -/** Created on 5/21/2017 by fr1kin */ +/** + * Created on 5/21/2017 by fr1kin + */ public class BoundProperty implements IBlockProperty { + private static final String HEADING = "bounds"; private final Collection bounds = Sets.newHashSet(); @@ -26,7 +29,11 @@ public boolean remove(int minY, int maxY) { @Nullable public Bound get(int minY, int maxY) { - for (Bound bound : bounds) if (bound.getMin() == minY && bound.getMax() == maxY) return bound; + for (Bound bound : bounds) { + if (bound.getMin() == minY && bound.getMax() == maxY) { + return bound; + } + } return null; } @@ -38,7 +45,11 @@ public boolean isWithinBoundaries(int posY) { if (bounds.isEmpty()) { return true; } else { - for (Bound bound : bounds) if (bound.isWithinBound(posY)) return true; + for (Bound bound : bounds) { + if (bound.isWithinBound(posY)) { + return true; + } + } return false; } } @@ -82,7 +93,9 @@ public String helpText() { builder.append(','); builder.append(bound.getMax()); builder.append(']'); - if (it.hasNext()) builder.append(", "); + if (it.hasNext()) { + builder.append(", "); + } } builder.append('}'); return builder.toString(); @@ -99,11 +112,14 @@ public String toString() { } public static class Bound { + private final int min; private final int max; public Bound(int min, int max) throws IllegalArgumentException { - if (min > max) throw new IllegalArgumentException("min cannot be greater than max"); + if (min > max) { + throw new IllegalArgumentException("min cannot be greater than max"); + } this.min = min; this.max = max; } @@ -127,6 +143,7 @@ public boolean equals(Object obj) { } private static class ImmutableBoundProperty extends BoundProperty { + @Override public boolean add(int minY, int maxY) { return false; diff --git a/src/main/java/com/matt/forgehax/util/blocks/properties/ColorProperty.java b/src/main/java/com/matt/forgehax/util/blocks/properties/ColorProperty.java index 76aa3e902..4dda6ac27 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/properties/ColorProperty.java +++ b/src/main/java/com/matt/forgehax/util/blocks/properties/ColorProperty.java @@ -2,15 +2,19 @@ import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Color; +import com.matt.forgehax.util.color.Colors; import java.io.IOException; import net.minecraft.util.math.MathHelper; -/** Created on 5/20/2017 by fr1kin */ +/** + * Created on 5/20/2017 by fr1kin + */ public class ColorProperty implements IBlockProperty { + private static final String HEADING = "color"; - private static final int DEFAULT_COLOR_BUFFER = Utils.Colors.WHITE; - private static final int[] DEFAULT_COLOR_ARRAY = Utils.toRGBAArray(DEFAULT_COLOR_BUFFER); + private static final int DEFAULT_COLOR_BUFFER = Colors.WHITE.toBuffer(); + private static final int[] DEFAULT_COLOR_ARRAY = Color.of(DEFAULT_COLOR_BUFFER).toIntegerArray(); private int r; private int g; @@ -40,7 +44,7 @@ public int getAlpha() { } public int[] getAsArray() { - return new int[] {r, g, b, a}; + return new int[]{r, g, b, a}; } public int getAsBuffer() { @@ -52,11 +56,11 @@ public void set(int r, int g, int b, int a) { this.g = MathHelper.clamp(g, 0, 255); this.b = MathHelper.clamp(b, 0, 255); this.a = MathHelper.clamp(a, 0, 255); - this.buffer = Utils.toRGBA(this.r, this.g, this.b, this.a); + this.buffer = Color.of(r, g, b, a).toBuffer(); } public void set(int buffer) { - int[] rgba = Utils.toRGBAArray(buffer); + int[] rgba = Color.of(buffer).toIntegerArray(); set(rgba[0], rgba[1], rgba[2], rgba[3]); } @@ -91,6 +95,7 @@ public String toString() { } private static class ImmutableColor extends ColorProperty { + @Override public int getRed() { return DEFAULT_COLOR_ARRAY[0]; @@ -122,9 +127,11 @@ public int[] getAsArray() { } @Override - public void set(int buffer) {} + public void set(int buffer) { + } @Override - public void set(int r, int g, int b, int a) {} + public void set(int r, int g, int b, int a) { + } } } diff --git a/src/main/java/com/matt/forgehax/util/blocks/properties/DimensionProperty.java b/src/main/java/com/matt/forgehax/util/blocks/properties/DimensionProperty.java index 358f13ba3..edcbab507 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/properties/DimensionProperty.java +++ b/src/main/java/com/matt/forgehax/util/blocks/properties/DimensionProperty.java @@ -11,8 +11,11 @@ import net.minecraft.world.DimensionType; import net.minecraftforge.common.DimensionManager; -/** Created on 5/23/2017 by fr1kin */ +/** + * Created on 5/23/2017 by fr1kin + */ public class DimensionProperty implements IBlockProperty { + private static final String HEADING = "dimensions"; private Collection dimensions = Sets.newHashSet(); @@ -24,7 +27,8 @@ private boolean add(DimensionType type) { public boolean add(int id) { try { return add(DimensionManager.getProviderType(id)); - } catch (Exception e) {; // will throw exception if id does not exist + } catch (Exception e) { + ; // will throw exception if id does not exist return false; } } @@ -42,13 +46,15 @@ public boolean remove(int id) { } public boolean contains(int id) { - if (dimensions.isEmpty()) return true; // true if none other - else + if (dimensions.isEmpty()) { + return true; // true if none other + } else { try { return dimensions.contains(DimensionManager.getProviderType(id)); } catch (Exception e) { return false; } + } } @Override @@ -65,11 +71,12 @@ public void deserialize(JsonReader reader) throws IOException { reader.beginArray(); while (reader.hasNext() && reader.peek().equals(JsonToken.STRING)) { String dim = reader.nextString(); - for (DimensionType type : DimensionType.values()) + for (DimensionType type : DimensionType.values()) { if (Objects.equals(type.getName(), dim)) { add(type); break; } + } } } @@ -85,7 +92,9 @@ public String helpText() { while (it.hasNext()) { String name = it.next().getName(); builder.append(name); - if (it.hasNext()) builder.append(", "); + if (it.hasNext()) { + builder.append(", "); + } } builder.append("}"); return builder.toString(); @@ -102,6 +111,7 @@ public String toString() { } private static class ImmutableDimension extends DimensionProperty { + @Override public boolean add(int id) { return false; diff --git a/src/main/java/com/matt/forgehax/util/blocks/properties/IBlockProperty.java b/src/main/java/com/matt/forgehax/util/blocks/properties/IBlockProperty.java index aa869f01b..4ceec7fe0 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/properties/IBlockProperty.java +++ b/src/main/java/com/matt/forgehax/util/blocks/properties/IBlockProperty.java @@ -2,8 +2,11 @@ import com.matt.forgehax.util.serialization.ISerializableJson; -/** Created on 5/20/2017 by fr1kin */ +/** + * Created on 5/20/2017 by fr1kin + */ public interface IBlockProperty extends ISerializableJson { + /** * If the current mutable instance is containing unique data. If this method returns false, then * the property may be switched to an immutable instance of itself. diff --git a/src/main/java/com/matt/forgehax/util/blocks/properties/PropertyFactory.java b/src/main/java/com/matt/forgehax/util/blocks/properties/PropertyFactory.java index 101db7d2a..5b8fec955 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/properties/PropertyFactory.java +++ b/src/main/java/com/matt/forgehax/util/blocks/properties/PropertyFactory.java @@ -5,17 +5,20 @@ import java.util.function.Supplier; import javax.annotation.Nullable; -/** Created on 6/4/2017 by fr1kin */ +/** + * Created on 6/4/2017 by fr1kin + */ public class PropertyFactory { + private static final Map, Supplier> - PROPERTY_FACTORY = Maps.newHashMap(); + PROPERTY_FACTORY = Maps.newHashMap(); private static final Map, IBlockProperty> CLASS_TO_IMMUTABLE = - Maps.newHashMap(); + Maps.newHashMap(); private static final Map> HEADING_TO_CLASS = - Maps.newHashMap(); + Maps.newHashMap(); public static void registerPropertyFactory( - Class clazz, Supplier factory) { + Class clazz, Supplier factory) { IBlockProperty temp = factory.get(); CLASS_TO_IMMUTABLE.put(clazz, temp.newImmutableInstance()); HEADING_TO_CLASS.put(temp.toString(), clazz); @@ -25,7 +28,9 @@ public static void registerPropertyFactory( public static T newInstance(Class clazz) { if (clazz != null) { Supplier supplier = PROPERTY_FACTORY.get(clazz); - if (supplier != null) return supplier.get().cast(); + if (supplier != null) { + return supplier.get().cast(); + } } return null; } diff --git a/src/main/java/com/matt/forgehax/util/blocks/properties/TagProperty.java b/src/main/java/com/matt/forgehax/util/blocks/properties/TagProperty.java index 4abc7cfe3..66e0338e7 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/properties/TagProperty.java +++ b/src/main/java/com/matt/forgehax/util/blocks/properties/TagProperty.java @@ -8,8 +8,11 @@ import java.util.Iterator; import joptsimple.internal.Strings; -/** Created on 5/23/2017 by fr1kin */ +/** + * Created on 5/23/2017 by fr1kin + */ public class TagProperty implements IBlockProperty { + private static final String HEADING = "tags"; private final Collection tags = Sets.newTreeSet(String.CASE_INSENSITIVE_ORDER); @@ -56,7 +59,9 @@ public String helpText() { while (it.hasNext()) { String tag = it.next(); builder.append(tag); - if (it.hasNext()) builder.append(", "); + if (it.hasNext()) { + builder.append(", "); + } } builder.append("}"); return builder.toString(); @@ -73,6 +78,7 @@ public String toString() { } private static class ImmutableBlockTag extends TagProperty { + @Override public boolean add(String tag) { return false; diff --git a/src/main/java/com/matt/forgehax/util/blocks/properties/ToggleProperty.java b/src/main/java/com/matt/forgehax/util/blocks/properties/ToggleProperty.java index 4c1e963ae..03f9bd494 100644 --- a/src/main/java/com/matt/forgehax/util/blocks/properties/ToggleProperty.java +++ b/src/main/java/com/matt/forgehax/util/blocks/properties/ToggleProperty.java @@ -4,8 +4,11 @@ import com.google.gson.stream.JsonWriter; import java.io.IOException; -/** Created on 5/24/2017 by fr1kin */ +/** + * Created on 5/24/2017 by fr1kin + */ public class ToggleProperty implements IBlockProperty { + private static final String HEADING = "enabled"; private boolean enabled = true; @@ -27,8 +30,11 @@ public void disable() { } public void toggle() { - if (enabled) disable(); - else enable(); + if (enabled) { + disable(); + } else { + enable(); + } } @Override @@ -62,21 +68,26 @@ public String toString() { } private static class ImmutableToggle extends ToggleProperty { + @Override public boolean isEnabled() { return true; } @Override - public void setEnabled(boolean enabled) {} + public void setEnabled(boolean enabled) { + } @Override - public void enable() {} + public void enable() { + } @Override - public void disable() {} + public void disable() { + } @Override - public void toggle() {} + public void toggle() { + } } } diff --git a/src/main/java/com/matt/forgehax/util/classloader/AbstractClassLoader.java b/src/main/java/com/matt/forgehax/util/classloader/AbstractClassLoader.java index d3e513fd1..557265974 100644 --- a/src/main/java/com/matt/forgehax/util/classloader/AbstractClassLoader.java +++ b/src/main/java/com/matt/forgehax/util/classloader/AbstractClassLoader.java @@ -14,10 +14,14 @@ import net.minecraft.launchwrapper.Launch; import net.minecraft.launchwrapper.LaunchClassLoader; -/** Created on 2/13/2018 by fr1kin */ +/** + * Created on 2/13/2018 by fr1kin + */ public abstract class AbstractClassLoader { - protected AbstractClassLoader() {} - + + protected AbstractClassLoader() { + } + /** * The class that must be extended * @@ -25,7 +29,7 @@ protected AbstractClassLoader() {} */ @Nullable public abstract Class getInheritedClass(); - + /** * The optional annotation class that must be on top of every class * @@ -33,7 +37,7 @@ protected AbstractClassLoader() {} */ @Nullable public abstract Class getAnnotationClass(); - + /** * Gets all the classes in the package that extend 'extendsClass' and are annotated with * 'annotationClass' @@ -45,31 +49,28 @@ protected AbstractClassLoader() {} */ @SuppressWarnings("unchecked") public Collection> filterClassPaths( - ClassLoader classLoader, Collection classPaths) throws IOException { + ClassLoader classLoader, Collection classPaths) throws IOException { return ClassLoaderHelper.getLoadedClasses(classLoader, classPaths) - .stream() - .filter(this::checkAnnotation) - .filter(this::checkInheritedClass) - .map(this::wildCast) - .filter(this::valid) - .collect(Collectors.toList()); + .stream() + .filter(this::checkAnnotation) + .filter(this::checkInheritedClass) + .map(this::wildCast) + .filter(this::valid) + .collect(Collectors.toList()); } - + /** * Initializes all the classes from ::create and returns a list of non-null instances created from * the provided classes - * - * @param classes - * @return */ public Collection loadClasses(Collection> classes) { return classes.stream().map(this::create).filter(Objects::nonNull).collect(Collectors.toList()); } - + public E loadClass(Class clazz) { return loadClasses(Collections.singleton(clazz)).stream().findFirst().orElse(null); } - + protected boolean valid(Class clazz) { try { return clazz.getDeclaredConstructor() != null; @@ -78,46 +79,46 @@ protected boolean valid(Class clazz) { return false; } } - + protected E create(Class clazz) { try { return clazz.getDeclaredConstructor().newInstance(); } catch (InstantiationException - | IllegalAccessException - | InvocationTargetException - | NoSuchMethodException e) { + | IllegalAccessException + | InvocationTargetException + | NoSuchMethodException e) { getLog() - .error( - "Failed to initialize class " - + clazz.getSimpleName() - + ": " - + e.getClass().getSimpleName() - + " - " - + e.getMessage() - + " - caused by: " - + e.getCause()); + .error( + "Failed to initialize class " + + clazz.getSimpleName() + + ": " + + e.getClass().getSimpleName() + + " - " + + e.getMessage() + + " - caused by: " + + e.getCause()); e.printStackTrace(); return null; } } - + @SuppressWarnings("unchecked") private Class wildCast(Class clazz) { return (Class) clazz; } - + private boolean checkAnnotation(Class clazz) { return getAnnotationClass() == null || clazz.isAnnotationPresent(getAnnotationClass()); } - + private boolean checkInheritedClass(Class clazz) { return getInheritedClass() == null || getInheritedClass().isAssignableFrom(clazz); } - + // // // - + public static LaunchClassLoader getFMLClassLoader() { return Launch.classLoader; } diff --git a/src/main/java/com/matt/forgehax/util/classloader/ClassLoaderHelper.java b/src/main/java/com/matt/forgehax/util/classloader/ClassLoaderHelper.java index 82698b8ce..b645e65c5 100644 --- a/src/main/java/com/matt/forgehax/util/classloader/ClassLoaderHelper.java +++ b/src/main/java/com/matt/forgehax/util/classloader/ClassLoaderHelper.java @@ -1,6 +1,9 @@ package com.matt.forgehax.util.classloader; -import static com.matt.forgehax.util.FileHelper.*; +import static com.matt.forgehax.util.FileHelper.asFilePath; +import static com.matt.forgehax.util.FileHelper.asPackagePath; +import static com.matt.forgehax.util.FileHelper.getFileExtension; +import static com.matt.forgehax.util.FileHelper.newFileSystem; import com.google.common.collect.Lists; import com.matt.forgehax.util.Streamables; @@ -14,59 +17,69 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.jar.JarFile; import java.util.stream.Collectors; import sun.net.www.protocol.file.FileURLConnection; public class ClassLoaderHelper { + private static void searchDirectory( - final Path directory, final Function function) { + final Path directory, final Function function) { Optional.ofNullable(directory) - .filter(Files::exists) - .filter(Files::isDirectory) - .ifPresent( - dir -> { - try { - Files.list(dir) - .forEach( - path -> { - if (function.apply(path)) searchDirectory(path, function); - }); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); + .filter(Files::exists) + .filter(Files::isDirectory) + .ifPresent( + dir -> { + try { + Files.list(dir) + .forEach( + path -> { + if (function.apply(path)) { + searchDirectory(path, function); + } + }); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } - + public static List getJarPathsInDirectory(final Path directory, boolean recursive) { final List results = Lists.newArrayList(); searchDirectory( - directory, - path -> { - if (Files.isDirectory(path)) return recursive; - else if (getFileExtension(path).equals("jar")) return results.add(directory); - return false; - }); + directory, + path -> { + if (Files.isDirectory(path)) { + return recursive; + } else if (getFileExtension(path).equals("jar")) { + return results.add(directory); + } + return false; + }); return results; } - + public static List getJarPathsInDirectory(File directory, boolean recursive) { return getJarPathsInDirectory(directory.toPath(), recursive); } - + public static List getJarPathsInDirectory(String directory, boolean recursive) { return getJarPathsInDirectory(Paths.get(directory), recursive); } - + public static List getJarPathsInDirectory(String directory) { boolean recursive = directory.endsWith("/*") || directory.endsWith("\\*"); return getJarPathsInDirectory( - Paths.get(recursive ? directory.substring(0, directory.length() - 2) : directory), - recursive); + Paths.get(recursive ? directory.substring(0, directory.length() - 2) : directory), + recursive); } - + /** * Generates a list of all files inside the directory (recursively). * @@ -77,30 +90,33 @@ public static List getJarPathsInDirectory(String directory) { public static List getClassPathsInDirectory(Path directory, boolean recursive) { final List results = Lists.newArrayList(); searchDirectory( - directory, - path -> { - if (Files.isDirectory(path)) return recursive; - else if (getFileExtension(path).equals("class")) results.add(path); - return false; - }); + directory, + path -> { + if (Files.isDirectory(path)) { + return recursive; + } else if (getFileExtension(path).equals("class")) { + results.add(path); + } + return false; + }); return results; } - + public static List getClassPathsInDirectory(File directory, boolean recursive) { return getClassPathsInDirectory(directory.toPath(), recursive); } - + public static List getClassPathsInDirectory(String directory, boolean recursive) { return getClassPathsInDirectory(Paths.get(directory), recursive); } - + public static List getClassPathsInDirectory(String directory) { boolean recursive = directory.endsWith("/*") || directory.endsWith("\\*"); return getClassPathsInDirectory( - Paths.get(recursive ? directory.substring(0, directory.length() - 2) : directory), - recursive); + Paths.get(recursive ? directory.substring(0, directory.length() - 2) : directory), + recursive); } - + /** * Generates a list of all the paths that have the file extension '.class' * @@ -111,63 +127,63 @@ public static List getClassPathsInDirectory(String directory) { * @throws IOException if there is an issue opening/reading the files */ public static List getClassPathsInJar(JarFile jarFile, String packageDir, boolean recursive) - throws IOException { + throws IOException { Objects.requireNonNull(jarFile); Objects.requireNonNull(packageDir); - + // open new file system to the jar file final FileSystem fs = newFileSystem(jarFile.getName()); final Path root = fs.getRootDirectories().iterator().next(); final Path packagePath = root.resolve(packageDir); - + return Streamables.enumerationStream(jarFile.entries()) - .map(entry -> root.resolve(entry.getName())) - .filter(path -> getFileExtension(path).equals("class")) - .filter( - path -> - recursive - || path.getNameCount() - == packagePath.getNameCount() - + 1) // name count = directories, +1 for the class file name - .filter( - path -> - path.toString().startsWith(path.getFileSystem().getSeparator() + packageDir) - && path.toString().length() - > (packageDir.length() + 2)) // 2 = root (first) '/' + suffix '/' - .collect(Collectors.toList()); + .map(entry -> root.resolve(entry.getName())) + .filter(path -> getFileExtension(path).equals("class")) + .filter( + path -> + recursive + || path.getNameCount() + == packagePath.getNameCount() + + 1) // name count = directories, +1 for the class file name + .filter( + path -> + path.toString().startsWith(path.getFileSystem().getSeparator() + packageDir) + && path.toString().length() + > (packageDir.length() + 2)) // 2 = root (first) '/' + suffix '/' + .collect(Collectors.toList()); } - + public static List getClassPathsInJar(File file, String packagePath, boolean recursive) - throws IOException { + throws IOException { Objects.requireNonNull(file); return getClassPathsInJar(new JarFile(file), packagePath, recursive); } - + public static List getClassPathsInJar(Path path, String packagePath, boolean recursive) - throws IOException { + throws IOException { Objects.requireNonNull(path); return getClassPathsInJar(path.toFile(), packagePath, recursive); } - + public static List getClassPathsInJar(JarFile jarFile, String packageDir) - throws IOException { + throws IOException { boolean recursive = packageDir.endsWith(".*"); return getClassPathsInJar( - jarFile, - recursive ? packageDir.substring(0, packageDir.length() - 2) : packageDir, - recursive); + jarFile, + recursive ? packageDir.substring(0, packageDir.length() - 2) : packageDir, + recursive); } - + public static List getClassPathsInJar(File file, String packagePath) throws IOException { Objects.requireNonNull(file); return getClassPathsInJar(new JarFile(file.getPath()), packagePath); } - + public static List getClassPathsInJar(Path path, String packagePath) throws IOException { Objects.requireNonNull(path); return getClassPathsInJar(path.toFile(), packagePath); } - + /** * Will attempt to find every class inside the package recursively. * @@ -175,88 +191,91 @@ public static List getClassPathsInJar(Path path, String packagePath) throw * @param packageDir name of package to search * @param recursive if the scan should look into sub directories * @return list of all the classes found - * @throws IOException */ public static List getClassPathsInPackage( - final ClassLoader classLoader, String packageDir, final boolean recursive) - throws IOException { + final ClassLoader classLoader, String packageDir, final boolean recursive) + throws IOException { Objects.requireNonNull(packageDir); Objects.requireNonNull(classLoader); - + List results = Lists.newArrayList(); - + final String pkgdir = asFilePath(packageDir); Enumeration inside = classLoader.getResources(pkgdir); Streamables.enumerationStream(inside) - .forEach( - url -> { - URLConnection connection; - try { - connection = url.openConnection(); - - // get the path to the jar/folder containing the classes - String path = - URLDecoder.decode(url.getPath(), "UTF-8") - .replace('\\', '/'); // get path and covert backslashes to forward slashes - path = - path.substring( - path.indexOf('/') + 1, - path.length()); // remove the initial '/' or 'file:/' appended to the path - - if (!System.getProperty("os.name").startsWith("Windows")) { - path = "/" + path; - } - - // the root directory to the jar/folder containing the classes - String rootDir = path.substring(0, path.indexOf(pkgdir)); - // package directory - String packDir = path.substring(path.lastIndexOf(pkgdir), path.length()); - - if (connection instanceof FileURLConnection) { - final Path root = Paths.get(rootDir).normalize(); - getClassPathsInDirectory(path, recursive) - .stream() - .map(root::relativize) - .forEach(results::add); - } else if (connection instanceof JarURLConnection) { - results.addAll( - getClassPathsInJar( - ((JarURLConnection) connection).getJarFile(), packDir, recursive)); - } else throw new UnknownConnectionType(); - } catch (Exception e) { - throw new RuntimeException(e); - } - }); - + .forEach( + url -> { + URLConnection connection; + try { + connection = url.openConnection(); + + // get the path to the jar/folder containing the classes + String path = + URLDecoder.decode(url.getPath(), "UTF-8") + .replace('\\', '/'); // get path and covert backslashes to forward slashes + path = + path.substring( + path.indexOf('/') + 1, + path.length()); // remove the initial '/' or 'file:/' appended to the path + + if (!System.getProperty("os.name").startsWith("Windows")) { + path = "/" + path; + } + + // the root directory to the jar/folder containing the classes + String rootDir = path.substring(0, path.indexOf(pkgdir)); + // package directory + String packDir = path.substring(path.lastIndexOf(pkgdir), path.length()); + + if (connection instanceof FileURLConnection) { + final Path root = Paths.get(rootDir).normalize(); + getClassPathsInDirectory(path, recursive) + .stream() + .map(root::relativize) + .forEach(results::add); + } else if (connection instanceof JarURLConnection) { + results.addAll( + getClassPathsInJar( + ((JarURLConnection) connection).getJarFile(), packDir, recursive)); + } else { + throw new UnknownConnectionType(); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + return results; } - + public static List getClassPathsInPackage(final ClassLoader classLoader, String packageDir) - throws IOException { + throws IOException { boolean recursive = packageDir.endsWith(".*"); return getClassPathsInPackage( - classLoader, - recursive ? packageDir.substring(0, packageDir.length() - 2) : packageDir, - recursive); + classLoader, + recursive ? packageDir.substring(0, packageDir.length() - 2) : packageDir, + recursive); } - + public static List> getLoadedClasses( - final ClassLoader classLoader, Collection paths) { + final ClassLoader classLoader, Collection paths) { Objects.requireNonNull(classLoader); Objects.requireNonNull(paths); return paths - .stream() - .map( - path -> { - try { - return Class.forName(asPackagePath(path), false, classLoader); - } catch (ClassNotFoundException e) { - return null; - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + .stream() + .map( + path -> { + try { + return Class.forName(asPackagePath(path), false, classLoader); + } catch (ClassNotFoundException e) { + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + public static class UnknownConnectionType extends Exception { + } - - public static class UnknownConnectionType extends Exception {} } diff --git a/src/main/java/com/matt/forgehax/util/classloader/CustomClassLoaders.java b/src/main/java/com/matt/forgehax/util/classloader/CustomClassLoaders.java index e807e4f81..d93334bfa 100644 --- a/src/main/java/com/matt/forgehax/util/classloader/CustomClassLoaders.java +++ b/src/main/java/com/matt/forgehax/util/classloader/CustomClassLoaders.java @@ -10,10 +10,13 @@ import java.nio.file.Files; import java.nio.file.Path; -/** Created on 2/16/2018 by fr1kin */ +/** + * Created on 2/16/2018 by fr1kin + */ public class CustomClassLoaders { + public static ClassLoader newFsClassLoader(ClassLoader parent, FileSystem fs) - throws RuntimeException { + throws RuntimeException { try { return new FsClassLoader(parent, fs); } catch (MalformedURLException e) { @@ -22,10 +25,11 @@ public static ClassLoader newFsClassLoader(ClassLoader parent, FileSystem fs) } private static class FsClassLoader extends URLClassLoader { + private final Path root; private FsClassLoader(ClassLoader parent, Path path) throws MalformedURLException { - super(new URL[] {path.toUri().toURL()}, parent); + super(new URL[]{path.toUri().toURL()}, parent); this.root = path; } diff --git a/src/main/java/com/matt/forgehax/util/color/Color.java b/src/main/java/com/matt/forgehax/util/color/Color.java index c01bcc2f5..41973acad 100644 --- a/src/main/java/com/matt/forgehax/util/color/Color.java +++ b/src/main/java/com/matt/forgehax/util/color/Color.java @@ -2,75 +2,78 @@ import java.util.Objects; -/** Created on 2/5/2018 by fr1kin */ +/** + * Created on 2/5/2018 by fr1kin + */ public abstract class Color { + public static int clamp(int c) { return Math.min(255, Math.max(0, c)); } - + public static float clamp(float c) { return Math.min(1.f, Math.max(0.f, c)); } - + public static Color ofInteger() { return ColorBuffer.getFactory(); } - + public static Color ofFloat() { return Color4F.getFactory(); } - + public static Color of(int buffer) { return ofInteger().set(buffer); } - + public static Color of(int red, int green, int blue, int alpha) { return ofInteger().set(red, green, blue, alpha); } - + public static Color of(int red, int green, int blue) { return ofInteger().set(red, green, blue); } - + public static Color of(int[] color) { return ofInteger().set(color); } - + public static Color of(float red, float green, float blue, float alpha) { return ofFloat().set(red, green, blue, alpha); } - + public static Color of(float red, float green, float blue) { return ofFloat().set(red, green, blue); } - + public static Color of(float[] color) { return ofFloat().set(color); } - + public static Color of(double red, double green, double blue, double alpha) { return ofFloat().set(red, green, blue, alpha); } - + public static Color of(double red, double green, double blue) { return ofFloat().set(red, green, blue); } - + public static Color of(double[] color) { return ofFloat().set(color); } - + // // // - + /** * Set color by buffer * * @param buffer color buffer */ public abstract Color set(int buffer); - + /** * Set the RGBA accordingly * @@ -82,6 +85,7 @@ public static Color of(double[] color) { public Color set(int red, int green, int blue, int alpha) { return set((red << 16) + (green << 8) + blue + (alpha << 24)); } + /** * Set the RGB accordingly, using 255 (maximum) for the alpha * @@ -92,7 +96,7 @@ public Color set(int red, int green, int blue, int alpha) { public Color set(int red, int green, int blue) { return set(red, green, blue, 255); } - + public Color set(int[] color) { Objects.requireNonNull(color); switch (color.length) { @@ -104,7 +108,7 @@ public Color set(int[] color) { throw new IllegalArgumentException("color[] must be of length 3 or 4"); } } - + /** * Set the RGBA accordingly * @@ -114,6 +118,7 @@ public Color set(int[] color) { * @param alpha as float 0-1 */ public abstract Color set(float red, float green, float blue, float alpha); + /** * Set the RGBA accordingly, using 1.f (maximum) for the alpha * @@ -124,7 +129,7 @@ public Color set(int[] color) { public Color set(float red, float green, float blue) { return set(red, green, blue, 1.f); } - + public Color set(float[] color) { Objects.requireNonNull(color); switch (color.length) { @@ -136,7 +141,7 @@ public Color set(float[] color) { throw new IllegalArgumentException("color[] must be of length 3 or 4"); } } - + /** * Set the RGBA accordingly Will cast all arguments to floats and use set(ffff) * @@ -148,6 +153,7 @@ public Color set(float[] color) { public Color set(double red, double green, double blue, double alpha) { return set((float) red, (float) green, (float) blue, (float) alpha); } + /** * Set the RGBA accordingly, using 1.D (maximum) for the alpha Will cast all arguments to floats * and use set(ffff) @@ -159,7 +165,7 @@ public Color set(double red, double green, double blue, double alpha) { public Color set(double red, double green, double blue) { return set(red, green, blue, 1.D); } - + public Color set(double[] color) { Objects.requireNonNull(color); switch (color.length) { @@ -171,32 +177,35 @@ public Color set(double[] color) { throw new IllegalArgumentException("color[] must be of length 3 or 4"); } } - + /** * Red color ranging from 0-255 * * @return red as integer */ public abstract int getRed(); + /** * Green color ranging from 0-255 * * @return green as integer */ public abstract int getGreen(); + /** * Blue color ranging from 0-255 * * @return blue as integer */ public abstract int getBlue(); + /** * Alpha color ranging from 0-255 * * @return alpha as integer */ public abstract int getAlpha(); - + /** * Set red ranging from 0-255 * @@ -205,6 +214,7 @@ public Color set(double[] color) { public Color setRed(int red) { return set(red, getGreen(), getBlue(), getAlpha()); } + /** * Set green ranging from 0-255 * @@ -213,6 +223,7 @@ public Color setRed(int red) { public Color setGreen(int green) { return set(getRed(), green, getBlue(), getAlpha()); } + /** * Set blue ranging from 0-255 * @@ -221,6 +232,7 @@ public Color setGreen(int green) { public Color setBlue(int blue) { return set(getRed(), getGreen(), blue, getAlpha()); } + /** * Set alpha ranging from 0-255 * @@ -229,32 +241,35 @@ public Color setBlue(int blue) { public Color setAlpha(int alpha) { return set(getRed(), getGreen(), getBlue(), alpha); } - + /** * Red color ranging from 0-1 * * @return red as float */ public abstract float getRedAsFloat(); + /** * Green color ranging from 0-1 * * @return green as float */ public abstract float getGreenAsFloat(); + /** * Blue color ranging from 0-1 * * @return blue as float */ public abstract float getBlueAsFloat(); + /** * Alpha color ranging from 0-1 * * @return alpha as float */ public abstract float getAlphaAsFloat(); - + /** * Set red ranging from 0-1 * @@ -263,6 +278,7 @@ public Color setAlpha(int alpha) { public Color setRed(float red) { return set(red, getGreenAsFloat(), getBlueAsFloat(), getAlphaAsFloat()); } + /** * Set green ranging from 0-1 * @@ -271,6 +287,7 @@ public Color setRed(float red) { public Color setGreen(float green) { return set(getRedAsFloat(), green, getBlueAsFloat(), getAlphaAsFloat()); } + /** * Set blue ranging from 0-1 * @@ -279,6 +296,7 @@ public Color setGreen(float green) { public Color setBlue(float blue) { return set(getRedAsFloat(), getGreenAsFloat(), blue, getAlphaAsFloat()); } + /** * Set alpha ranging from 0-1 * @@ -287,7 +305,7 @@ public Color setBlue(float blue) { public Color setAlpha(float alpha) { return set(getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat(), alpha); } - + /** * Red color ranging from 0-1 NOTE: double is overkill for color, this is just a convenience * method that returns a float casted as a double @@ -297,6 +315,7 @@ public Color setAlpha(float alpha) { public double getRedAsDouble() { return getRedAsFloat(); } + /** * Green color ranging from 0-1 NOTE: double is overkill for color, this is just a convenience * method that returns a float casted as a double @@ -306,6 +325,7 @@ public double getRedAsDouble() { public double getGreenAsDouble() { return getGreenAsFloat(); } + /** * Blue color ranging from 0-1 NOTE: double is overkill for color, this is just a convenience * method that returns a float casted as a double @@ -315,6 +335,7 @@ public double getGreenAsDouble() { public double getBlueAsDouble() { return getBlueAsFloat(); } + /** * Alpha color ranging from 0-1 NOTE: double is overkill for color, this is just a convenience * method that returns a float casted as a double @@ -324,7 +345,7 @@ public double getBlueAsDouble() { public double getAlphaAsDouble() { return getAlphaAsFloat(); } - + /** * Set red ranging from 0-1 NOTE: double is overkill for color, this is just a convenience method * that will cast the argument as a double @@ -334,6 +355,7 @@ public double getAlphaAsDouble() { public Color setRed(double red) { return setRed((float) red); } + /** * Set green ranging from 0-1 NOTE: double is overkill for color, this is just a convenience * method that will cast the argument as a double @@ -343,6 +365,7 @@ public Color setRed(double red) { public Color setGreen(double green) { return setGreen((float) green); } + /** * Set blue ranging from 0-1 NOTE: double is overkill for color, this is just a convenience method * that will cast the argument as a double @@ -352,6 +375,7 @@ public Color setGreen(double green) { public Color setBlue(double blue) { return setBlue((float) blue); } + /** * Set alpha ranging from 0-1 NOTE: double is overkill for color, this is just a convenience * method that will cast the argument as a double @@ -361,7 +385,7 @@ public Color setBlue(double blue) { public Color setAlpha(double alpha) { return setAlpha((float) alpha); } - + /** * Gets the color as an integer buffer. * @@ -370,25 +394,25 @@ public Color setAlpha(double alpha) { public int toBuffer() { return (getRed() << 16) + (getGreen() << 8) + getBlue() + (getAlpha() << 24); } - + /** * Converts the color to a integer array {r,g,b,a} * * @return integer array containing the color */ public int[] toIntegerArray() { - return new int[] {getRed(), getGreen(), getBlue(), getAlpha()}; + return new int[]{getRed(), getGreen(), getBlue(), getAlpha()}; } - + /** * Converts the color to a float array {r,g,b,a} * * @return float array containing the color */ public float[] toFloatArray() { - return new float[] {getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat(), getAlphaAsFloat()}; + return new float[]{getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat(), getAlphaAsFloat()}; } - + /** * Converts the color to a double array {r,g,b,a} NOTE: double is overkill for color, this is just * a convenience method @@ -397,15 +421,15 @@ public float[] toFloatArray() { */ public double[] toDoubleArray() { float[] array = toFloatArray(); - return new double[] {array[0], array[1], array[2], array[3]}; + return new double[]{array[0], array[1], array[2], array[3]}; } - + @Override public abstract String toString(); - + @Override public abstract int hashCode(); - + @Override public boolean equals(Object obj) { return this == obj || (obj instanceof Color && hashCode() == obj.hashCode()); diff --git a/src/main/java/com/matt/forgehax/util/color/Color4F.java b/src/main/java/com/matt/forgehax/util/color/Color4F.java index e24895781..4937b6a6e 100644 --- a/src/main/java/com/matt/forgehax/util/color/Color4F.java +++ b/src/main/java/com/matt/forgehax/util/color/Color4F.java @@ -2,8 +2,11 @@ import java.util.Arrays; -/** Created on 2/6/2018 by fr1kin */ +/** + * Created on 2/6/2018 by fr1kin + */ public class Color4F extends Color { + private static final Color FACTORY = new Color4F(); public static Color getFactory() { @@ -15,8 +18,9 @@ public static Color getFactory() { // private final float[] color = new float[4]; - - private Color4F() {} + + private Color4F() { + } private Color4F(float red, float green, float blue, float alpha) { color[0] = red; @@ -28,10 +32,10 @@ private Color4F(float red, float green, float blue, float alpha) { @Override public Color set(int buffer) { return set( - (float) (buffer >> 16 & 255) / 255.f, - (float) (buffer >> 8 & 255) / 255.f, - (float) (buffer & 255) / 255.f, - (float) (buffer >> 24 & 255) / 255.f); + (float) (buffer >> 16 & 255) / 255.f, + (float) (buffer >> 8 & 255) / 255.f, + (float) (buffer & 255) / 255.f, + (float) (buffer >> 24 & 255) / 255.f); } @Override @@ -87,8 +91,8 @@ public float[] toFloatArray() { @Override public String toString() { return String.format( - "r=%.2f,g=%.2f,b=%.2f,a=%.2f", - getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat(), getAlphaAsFloat()); + "r=%.2f,g=%.2f,b=%.2f,a=%.2f", + getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat(), getAlphaAsFloat()); } @Override diff --git a/src/main/java/com/matt/forgehax/util/color/ColorBuffer.java b/src/main/java/com/matt/forgehax/util/color/ColorBuffer.java index 6178865c9..1b5e5088b 100644 --- a/src/main/java/com/matt/forgehax/util/color/ColorBuffer.java +++ b/src/main/java/com/matt/forgehax/util/color/ColorBuffer.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.color; -/** Created on 2/5/2018 by fr1kin */ +/** + * Created on 2/5/2018 by fr1kin + */ public class ColorBuffer extends Color { + private static final Color FACTORY = new ColorBuffer(); public static Color getFactory() { @@ -30,7 +33,7 @@ public Color set(int buffer) { @Override public Color set(float red, float green, float blue, float alpha) { return set( - (int) (red * 255.f), (int) (green * 255.f), (int) (blue * 255.f), (int) (alpha * 255.f)); + (int) (red * 255.f), (int) (green * 255.f), (int) (blue * 255.f), (int) (alpha * 255.f)); } @Override @@ -80,7 +83,7 @@ public int toBuffer() { @Override public float[] toFloatArray() { - return new float[] {getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat(), getAlphaAsFloat()}; + return new float[]{getRedAsFloat(), getGreenAsFloat(), getBlueAsFloat(), getAlphaAsFloat()}; } @Override diff --git a/src/main/java/com/matt/forgehax/util/color/Colors.java b/src/main/java/com/matt/forgehax/util/color/Colors.java index 20fa014e6..8a3244773 100644 --- a/src/main/java/com/matt/forgehax/util/color/Colors.java +++ b/src/main/java/com/matt/forgehax/util/color/Colors.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.color; -/** Created on 2/6/2018 by fr1kin */ +/** + * Created on 2/6/2018 by fr1kin + */ public interface Colors { + Color WHITE = Color.of(255, 255, 255, 255); Color BLACK = Color.of(0, 0, 0, 255); Color RED = Color.of(255, 0, 0, 255); diff --git a/src/main/java/com/matt/forgehax/util/command/BaseCommandBuilder.java b/src/main/java/com/matt/forgehax/util/command/BaseCommandBuilder.java index b56a629c9..1a34a8404 100644 --- a/src/main/java/com/matt/forgehax/util/command/BaseCommandBuilder.java +++ b/src/main/java/com/matt/forgehax/util/command/BaseCommandBuilder.java @@ -1,6 +1,10 @@ package com.matt.forgehax.util.command; -import com.google.common.collect.*; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.common.collect.Sets; import com.matt.forgehax.util.command.callbacks.CallbackData; import java.util.Collection; import java.util.List; @@ -9,26 +13,32 @@ import joptsimple.OptionParser; import joptsimple.OptionSet; -/** Created on 6/6/2017 by fr1kin */ +/** + * Created on 6/6/2017 by fr1kin + */ public abstract class BaseCommandBuilder { + protected final Map data = Maps.newHashMap(); - + private List> optionBuilders; private List> processors; private Multimap> callbacks; - + @SuppressWarnings("unchecked") protected T insert(String entry, Object o) { Object g = data.get(entry); - if (g != null && o == null) data.remove(entry); - else if (o != null) data.put(entry, o); + if (g != null && o == null) { + data.remove(entry); + } else if (o != null) { + data.put(entry, o); + } return (T) this; } - + protected boolean has(String entry) { return data.get(entry) != null; } - + @SuppressWarnings("unchecked") protected Collection getCallbacks(CallbackType type) { if (callbacks == null) { @@ -37,7 +47,7 @@ protected Collection getCallbacks(CallbackType type) { } return (Collection) callbacks.get(type); } - + protected Collection> getOptionBuilders() { if (optionBuilders == null) { optionBuilders = Lists.newArrayList(); @@ -45,7 +55,7 @@ protected Collection> getOptionBuilders() { } return optionBuilders; } - + protected Collection> getProcessors() { if (processors == null) { processors = Lists.newArrayList(); @@ -53,56 +63,57 @@ protected Collection> getProcessors() { } return processors; } - - protected BaseCommandBuilder() {} - + + protected BaseCommandBuilder() { + } + public T parent(Command parent) { return insert(Command.PARENT, parent); } - + public T name(String name) { return insert(Command.NAME, name); } - + public T description(String description) { return insert(Command.DESCRIPTION, description); } - + public T processor(Consumer processor) { getProcessors().add(processor); return (T) this; } - + public T options(Consumer optionBuilder) { getOptionBuilders().add(optionBuilder); return (T) this; } - + public T help(Consumer consumer) { return insert(Command.HELP, consumer); } - + public T success(Consumer consumer) { getCallbacks(CallbackType.SUCCESS).add(consumer); return (T) this; } - + public T failure(Consumer consumer) { getCallbacks(CallbackType.FAILURE).add(consumer); return (T) this; } - + public T helpOption(boolean b) { return insert(Command.HELPAUTOGEN, b); } - + public T requiredArgs(int required) { return insert(Command.REQUIREDARGS, required); } - + public Map getData() { return data; } - + public abstract R build(); } diff --git a/src/main/java/com/matt/forgehax/util/command/CallbackType.java b/src/main/java/com/matt/forgehax/util/command/CallbackType.java index 210b69fc8..26e59107b 100644 --- a/src/main/java/com/matt/forgehax/util/command/CallbackType.java +++ b/src/main/java/com/matt/forgehax/util/command/CallbackType.java @@ -1,6 +1,8 @@ package com.matt.forgehax.util.command; -/** Created on 6/2/2017 by fr1kin */ +/** + * Created on 6/2/2017 by fr1kin + */ public enum CallbackType { SUCCESS, FAILURE, diff --git a/src/main/java/com/matt/forgehax/util/command/Command.java b/src/main/java/com/matt/forgehax/util/command/Command.java index 7c59408dd..afc88a1c8 100644 --- a/src/main/java/com/matt/forgehax/util/command/Command.java +++ b/src/main/java/com/matt/forgehax/util/command/Command.java @@ -1,6 +1,10 @@ package com.matt.forgehax.util.command; -import com.google.common.collect.*; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.google.common.collect.Sets; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import com.matt.forgehax.Globals; @@ -19,7 +23,13 @@ import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; import javax.annotation.Nonnull; @@ -28,10 +38,13 @@ import joptsimple.OptionSet; import joptsimple.internal.Strings; -/** Created on 5/14/2017 by fr1kin */ +/** + * Created on 5/14/2017 by fr1kin + */ public class Command implements Comparable, ISerializer, GsonConstant { + private static final Path SETTINGS_DIR = Helper.getFileManager().getMkConfigDirectory("settings"); - + public static final String NAME = "Command.name"; public static final String DESCRIPTION = "Command.description"; public static final String OPTIONBUILDERS = "Command.optionbuilder"; @@ -41,206 +54,230 @@ public class Command implements Comparable, ISerializer, GsonConstant { public static final String HELPAUTOGEN = "Command.helpAutoGen"; public static final String CALLBACKS = "Command.callbacks"; public static final String REQUIREDARGS = "Command.requiredArgs"; - + private final String name; private final String description; - + protected final OptionParser parser = new OptionParser(); - + protected final Collection> processors = Lists.newArrayList(); - + protected final Consumer help; - + private final Set children = Sets.newHashSet(); - + protected final Multimap> callbacks = - Multimaps.newSetMultimap(Maps.newHashMap(), Sets::newLinkedHashSet); - + Multimaps.newSetMultimap(Maps.newHashMap(), Sets::newLinkedHashSet); + private final int requiredArgs; - + private Command parent; - + @SuppressWarnings("unchecked") protected Command(Map data) throws CommandBuildException { try { this.name = (String) data.get(NAME); Objects.requireNonNull(this.name, "Command requires name"); - + this.description = (String) data.getOrDefault(DESCRIPTION, Strings.EMPTY); this.help = (Consumer) data.get(HELP); - + Collection> processors = - (Collection>) data.get(PROCESSORS); - if (processors != null) this.processors.addAll(processors); - + (Collection>) data.get(PROCESSORS); + if (processors != null) { + this.processors.addAll(processors); + } + // Set command parent Command parent = (Command) data.get(PARENT); - if (parent != null) parent.addChild(this); - + if (parent != null) { + parent.addChild(this); + } + // By default, auto generate help option // User must specify not to add it Boolean helpAutoGen = (Boolean) data.getOrDefault(HELPAUTOGEN, true); if (helpAutoGen) { parser.acceptsAll(Arrays.asList("help", "?"), "Help text for options"); } - + // Execute custom option builder (if it exists) Collection> optionBuilders = - (Collection>) data.get(OPTIONBUILDERS); + (Collection>) data.get(OPTIONBUILDERS); if (optionBuilders != null) { - for (Consumer c : optionBuilders) c.accept(this.parser); + for (Consumer c : optionBuilders) { + c.accept(this.parser); + } } - + // Add any callbacks created by the builder Multimap> callbacks = - (Multimap>) data.get(CALLBACKS); + (Multimap>) data.get(CALLBACKS); if (callbacks != null) { this.callbacks.putAll(callbacks); } - + this.requiredArgs = Math.max(SafeConverter.toInteger(data.getOrDefault(REQUIREDARGS, 0)), 0); } catch (Throwable t) { throw new CommandBuildException("Failed to build command", t); } } - + public boolean isGlobal() { return false; } - + public String getName() { return name; } - + public String getAbsoluteName() { return (getParent() != null && !getParent().isGlobal()) - ? (getParent().getAbsoluteName() + "." + getName()) - : getName(); + ? (getParent().getAbsoluteName() + "." + getName()) + : getName(); } - + public String getDescription() { return description; } - + public String getPrintText() { return getName() + " - " + getDescription(); } - + public String getOptionHelpText() { StringWriter writer = new StringWriter(); try { parser.printHelpOn(writer); - } catch (IOException e) {; + } catch (IOException e) { + ; } finally { try { writer.close(); - } catch (IOException e) {; + } catch (IOException e) { + ; } } return writer.toString(); } - + @Nullable public Command getParent() { return parent; } - + protected void setParent(Command parent) { - if (this.parent != null && parent != null) + if (this.parent != null && parent != null) { throw new CommandParentNonNullException("Command parent already exists"); + } this.parent = parent; } - + public boolean leaveParent() { return parent != null && parent.removeChild(this); } - + public CommandBuilders builders() { return CommandBuilders.newInstance(this); } - + public boolean addChild(@Nonnull Command child) { boolean b; - if (b = children.add(child)) child.setParent(this); + if (b = children.add(child)) { + child.setParent(this); + } return b; } - + public boolean removeChild(@Nonnull Command child) { boolean b; // if child was removed, set parent to null. - if (b = children.remove(child)) child.setParent(null); + if (b = children.remove(child)) { + child.setParent(null); + } return b; } - + @Nullable public Command getChild(String name) { - for (Command command : children) if (command.getName().equalsIgnoreCase(name)) return command; + for (Command command : children) { + if (command.getName().equalsIgnoreCase(name)) { + return command; + } + } return null; } - + public Collection getChildren() { return Collections.unmodifiableCollection(children); } - + public void getChildrenDeep(final Collection all) { all.addAll(getChildren()); children.forEach(child -> child.getChildrenDeep(all)); } - + public Collection getChildrenDeep() { Collection all = Sets.newHashSet(); getChildrenDeep(all); return all; // does not need to be unmodifiable since we are creating a duplicate containing all // children } - + public void abandonChildren() { children.forEach(Command::leaveParent); } - + @SuppressWarnings("unchecked") @Nullable protected Consumer addCallback( - CallbackType type, Consumer consumer) { + CallbackType type, Consumer consumer) { return callbacks.put(type, (Consumer) consumer) ? consumer : null; } - + protected boolean removeCallback(CallbackType type, Consumer consumer) { return callbacks.remove(type, consumer); } - + protected void invokeCallbacks(CallbackType type, T data) { callbacks.get(type).forEach(c -> c.accept(data)); } - + protected boolean processHelp(ExecuteData data) - throws CommandExecuteException, NullPointerException { + throws CommandExecuteException, NullPointerException { if (help != null) { help.accept(data); return true; } else if (data.options().has("help")) { Helper.printMessageNaked(getOptionHelpText()); return true; - } else return false; + } else { + return false; + } } - + protected boolean processMain(ExecuteData data) - throws CommandExecuteException, NullPointerException { + throws CommandExecuteException, NullPointerException { if (processors != null) { - for (Consumer c : processors) + for (Consumer c : processors) { try { c.accept(data); - if (data.isStopped()) break; + if (data.isStopped()) { + break; + } } catch (Throwable t) { data.markFailed(); throw t; } + } return true; - } else return false; + } else { + return false; + } } - + protected boolean processChildren(@Nonnull String[] args) - throws CommandExecuteException, NullPointerException { + throws CommandExecuteException, NullPointerException { if (args.length > 0) { final String lookup = (args[0] != null ? args[0] : Strings.EMPTY).toLowerCase(); Command child = getChild(lookup); @@ -249,59 +286,68 @@ protected boolean processChildren(@Nonnull String[] args) return true; } else { // no match found, try and infer List results = - children - .stream() - .filter(cmd -> cmd.getName().toLowerCase().startsWith(lookup)) - .collect(Collectors.toList()); - + children + .stream() + .filter(cmd -> cmd.getName().toLowerCase().startsWith(lookup)) + .collect(Collectors.toList()); + if (results.size() == 1) { // if found 1 result, use that results.get(0).run(CommandHelper.forward(args)); return true; } else if (results.size() > 1) { throw new CommandExecuteException( - String.format( - "Ambiguous command \"%s\": %s", - lookup, - results.stream().map(Command::getName).collect(Collectors.joining(", ")))); + String.format( + "Ambiguous command \"%s\": %s", + lookup, + results.stream().map(Command::getName).collect(Collectors.joining(", ")))); } } } return false; } - + protected boolean preprocessor(String[] args) { return true; } - + @SuppressWarnings("Duplicates") public void run(@Nonnull String[] args) throws CommandExecuteException, NullPointerException { if (!processChildren(args)) { // attempt to match child commands first OptionSet options; String[] required; - - if (!preprocessor(args)) return; - + + if (!preprocessor(args)) { + return; + } + if (requiredArgs > 0) { if (args.length == 0) { ConsoleIO.write(getPrintText()); return; } - if (args.length < requiredArgs) throw new CommandExecuteException("Missing argument(s)"); + if (args.length < requiredArgs) { + throw new CommandExecuteException("Missing argument(s)"); + } required = - Arrays.copyOfRange(args, 0, requiredArgs); // do not pass through option processor + Arrays.copyOfRange(args, 0, requiredArgs); // do not pass through option processor String[] nargs; - if (args.length > requiredArgs) nargs = Arrays.copyOfRange(args, requiredArgs, args.length); - else nargs = new String[0]; + if (args.length > requiredArgs) { + nargs = Arrays.copyOfRange(args, requiredArgs, args.length); + } else { + nargs = new String[0]; + } options = parser.parse(nargs); } else { options = parser.parse(args); required = new String[0]; } ExecuteData data = new ExecuteData(this, options, required); - + // only process main if no help was processed - if (!processHelp(data)) processMain(data); - + if (!processHelp(data)) { + processMain(data); + } + switch (data.state()) { case SUCCESS: invokeCallbacks(CallbackType.SUCCESS, new CallbackData(this)); @@ -312,11 +358,11 @@ public void run(@Nonnull String[] args) throws CommandExecuteException, NullPoin } } } - + private Path getSettingsPath() { return SETTINGS_DIR.resolve(getAbsoluteName() + ".json"); } - + @Override public void serialize() { if (this instanceof ISerializableJson) { @@ -328,31 +374,33 @@ public void serialize() { writer.beginArray(); serializable.serialize(writer); writer.endArray(); - + Files.write(path, sw.toString().getBytes()); } catch (Throwable t) { Helper.printStackTrace(t); Globals.LOGGER.warn( - String.format("Could not serialize \"%s\": %s", getAbsoluteName(), t.getMessage())); + String.format("Could not serialize \"%s\": %s", getAbsoluteName(), t.getMessage())); } finally { try { sw.close(); - } catch (IOException e) {; + } catch (IOException e) { + ; } finally { try { writer.close(); - } catch (IOException e) {; + } catch (IOException e) { + ; } } } } } - + public void serializeAll() { serialize(); getChildren().forEach(Command::serializeAll); } - + @Override public void deserialize() { if (this instanceof ISerializableJson) { @@ -360,49 +408,55 @@ public void deserialize() { Path path = getSettingsPath(); StringReader sr = null; JsonReader reader = null; - if (Files.exists(path)) + if (Files.exists(path)) { try { sr = new StringReader(new String(Files.readAllBytes(path))); reader = new JsonReader(sr); - + reader.beginArray(); serializable.deserialize(reader); reader.endArray(); } catch (Throwable t) { Helper.printStackTrace(t); Globals.LOGGER.warn( - String.format("Could not deserialize \"%s\": %s", getAbsoluteName(), t.getMessage())); + String.format("Could not deserialize \"%s\": %s", getAbsoluteName(), t.getMessage())); } finally { - if (sr != null) sr.close(); + if (sr != null) { + sr.close(); + } try { - if (reader != null) reader.close(); - } catch (IOException e) {; + if (reader != null) { + reader.close(); + } + } catch (IOException e) { + ; } } + } } } - + public void deserializeAll() { deserialize(); getChildren().forEach(Command::deserializeAll); } - + @Override public int compareTo(Command o) { return String.CASE_INSENSITIVE_ORDER.compare(getAbsoluteName(), o.getAbsoluteName()); } - + @Override public boolean equals(Object o) { return o instanceof Command - && getAbsoluteName().equalsIgnoreCase(((Command) o).getAbsoluteName()); + && getAbsoluteName().equalsIgnoreCase(((Command) o).getAbsoluteName()); } - + @Override public int hashCode() { return getAbsoluteName().toLowerCase().hashCode(); } - + @Override public String toString() { return getAbsoluteName(); diff --git a/src/main/java/com/matt/forgehax/util/command/CommandBuilder.java b/src/main/java/com/matt/forgehax/util/command/CommandBuilder.java index 6b3131f12..d7e0687cd 100644 --- a/src/main/java/com/matt/forgehax/util/command/CommandBuilder.java +++ b/src/main/java/com/matt/forgehax/util/command/CommandBuilder.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.command; -/** Created on 5/14/2017 by fr1kin */ +/** + * Created on 5/14/2017 by fr1kin + */ public class CommandBuilder extends BaseCommandBuilder { + @Override public Command build() { return new Command(data); diff --git a/src/main/java/com/matt/forgehax/util/command/CommandBuilders.java b/src/main/java/com/matt/forgehax/util/command/CommandBuilders.java index 4ffb999f6..6aa2e4a97 100644 --- a/src/main/java/com/matt/forgehax/util/command/CommandBuilders.java +++ b/src/main/java/com/matt/forgehax/util/command/CommandBuilders.java @@ -2,44 +2,47 @@ import com.matt.forgehax.util.serialization.ISerializableJson; -/** Created on 6/3/2017 by fr1kin */ +/** + * Created on 6/3/2017 by fr1kin + */ public class CommandBuilders { + private static final CommandBuilders INSTANCE = new CommandBuilders(); - + public static CommandBuilders getInstance() { return INSTANCE; } - + public static CommandBuilders newInstance(Command parent) { return new CommandBuilders(parent); } - + private final Command parent; - + public CommandBuilders(Command parent) { this.parent = parent; } - + public CommandBuilders() { this(null); } - + public CommandBuilder newCommandBuilder() { return new CommandBuilder().parent(parent); } - + public StubBuilder newStubBuilder() { return new StubBuilder().parent(parent); } - + public SettingBuilder newSettingBuilder() { return new SettingBuilder().parent(parent); } - + public > SettingEnumBuilder newSettingEnumBuilder() { return new SettingEnumBuilder().parent(parent); } - + public OptionsBuilder newOptionsBuilder() { return new OptionsBuilder().parent(parent); } diff --git a/src/main/java/com/matt/forgehax/util/command/CommandGlobal.java b/src/main/java/com/matt/forgehax/util/command/CommandGlobal.java index d78daecc2..51d7334f4 100644 --- a/src/main/java/com/matt/forgehax/util/command/CommandGlobal.java +++ b/src/main/java/com/matt/forgehax/util/command/CommandGlobal.java @@ -4,44 +4,49 @@ import javax.annotation.Nonnull; import joptsimple.internal.Strings; -/** Created on 6/2/2017 by fr1kin */ +/** + * Created on 6/2/2017 by fr1kin + */ public class CommandGlobal extends CommandStub { + private static final CommandGlobal INSTANCE = new CommandGlobal(); - + public static CommandGlobal getInstance() { return INSTANCE; } - + private CommandGlobal() { super( - CommandBuilders.getInstance() - .newStubBuilder() - .name(Strings.EMPTY) - .helpOption(false) - .getData()); + CommandBuilders.getInstance() + .newStubBuilder() + .name(Strings.EMPTY) + .helpOption(false) + .getData()); } - + @Override public boolean isGlobal() { return true; } - + @Override public String getName() { return Strings.EMPTY; } - + @Override public String getAbsoluteName() { return Strings.EMPTY; } - + @Override public void run(@Nonnull String[] args) throws CommandExecuteException, NullPointerException { if (!processChildren(args)) { - if (args.length > 0) + if (args.length > 0) { throw new CommandExecuteException(String.format("Unknown command \"%s\"", args[0])); - else throw new CommandExecuteException("Missing argument(s)"); + } else { + throw new CommandExecuteException("Missing argument(s)"); + } } } } diff --git a/src/main/java/com/matt/forgehax/util/command/CommandHelper.java b/src/main/java/com/matt/forgehax/util/command/CommandHelper.java index 71b9595ee..cff54f6c6 100644 --- a/src/main/java/com/matt/forgehax/util/command/CommandHelper.java +++ b/src/main/java/com/matt/forgehax/util/command/CommandHelper.java @@ -7,21 +7,26 @@ import java.util.StringTokenizer; import joptsimple.internal.Strings; -/** Created on 5/15/2017 by fr1kin */ +/** + * Created on 5/15/2017 by fr1kin + */ public class CommandHelper { + private static final String[] EMPTY_STRING_ARRAY = new String[0]; public static final String MOD_PROPERTY_SEPARATOR = ":"; - - /** Moves the argument array forward by one or returns an empty array if not possible */ + + /** + * Moves the argument array forward by one or returns an empty array if not possible + */ public static String[] forward(String[] args) { return args.length > 0 ? Arrays.copyOfRange(args, 1, args.length) : EMPTY_STRING_ARRAY; } public static String join(String[] args, String separator, int startIndex, int endIndex) { return Strings.join( - Arrays.copyOfRange(args, startIndex, endIndex), - com.google.common.base.Strings.nullToEmpty(separator)); + Arrays.copyOfRange(args, startIndex, endIndex), + com.google.common.base.Strings.nullToEmpty(separator)); } public static String join(String[] args, String separator) { @@ -30,7 +35,7 @@ public static String join(String[] args, String separator) { public static String toUniqueId(String parent, String child) { return makeParserFriendly( - !Strings.isNullOrEmpty(parent) ? (parent + MOD_PROPERTY_SEPARATOR + child) : child); + !Strings.isNullOrEmpty(parent) ? (parent + MOD_PROPERTY_SEPARATOR + child) : child); } public static String makeParserFriendly(String string) { @@ -38,8 +43,10 @@ public static String makeParserFriendly(String string) { } public static void requireArguments(List args, int requiredArguments) - throws CommandExecuteException { - if (args.size() < requiredArguments) throw new CommandExecuteException("Missing argument(s)"); + throws CommandExecuteException { + if (args.size() < requiredArguments) { + throw new CommandExecuteException("Missing argument(s)"); + } } /** @@ -47,7 +54,7 @@ public static void requireArguments(List args, int requiredArguments) * * @param toProcess the command line to process. * @return the command line broken into strings. An empty or null toProcess parameter results in a - * zero sized array. + * zero sized array. */ public static String[] translate(String toProcess) { if (toProcess == null || toProcess.length() == 0) { diff --git a/src/main/java/com/matt/forgehax/util/command/CommandStub.java b/src/main/java/com/matt/forgehax/util/command/CommandStub.java index cc96a0094..03e8e5801 100644 --- a/src/main/java/com/matt/forgehax/util/command/CommandStub.java +++ b/src/main/java/com/matt/forgehax/util/command/CommandStub.java @@ -15,86 +15,95 @@ import net.minecraftforge.fml.client.registry.ClientRegistry; import org.lwjgl.input.Keyboard; -/** Created on 6/8/2017 by fr1kin */ +/** + * Created on 6/8/2017 by fr1kin + */ public class CommandStub extends Command implements IKeyBind, ISerializableJson { + public static final String KEYBIND = "Command.keybind"; public static final String KEYBIND_OPTIONS = "Command.keybind_options"; - + private final KeyBinding bind; - + protected CommandStub(Map data) throws CommandBuildException { super(data); - + // key binding Integer keyCode = (Integer) data.getOrDefault(KEYBIND, -1); if (keyCode != -1) { bind = new KeyBinding(getAbsoluteName(), keyCode, "ForgeHax"); ClientRegistry.registerKeyBinding(bind); - + Boolean genOptions = (Boolean) data.getOrDefault(KEYBIND_OPTIONS, true); if (genOptions) { parser.accepts("bind", "Bind to the given key").withRequiredArg(); parser.accepts("unbind", "Sets bind to KEY_NONE"); - + this.processors.add( - dt -> { - if (dt.hasOption("bind")) { - String key = dt.getOptionAsString("bind").toUpperCase(); - - int kc = Keyboard.getKeyIndex(key); - if (Keyboard.getKeyIndex(key) == Keyboard.KEY_NONE) - throw new CommandExecuteException( - String.format("\"%s\" is not a valid key name", key)); - - bind(kc); - serialize(); - - dt.write(String.format("Bound %s to key %s [code=%d]", getAbsoluteName(), key, kc)); - dt.stopProcessing(); - } else if (dt.hasOption("unbind")) { - unbind(); - serialize(); - - dt.write(String.format("Unbound %s", getAbsoluteName())); - dt.stopProcessing(); + dt -> { + if (dt.hasOption("bind")) { + String key = dt.getOptionAsString("bind").toUpperCase(); + + int kc = Keyboard.getKeyIndex(key); + if (Keyboard.getKeyIndex(key) == Keyboard.KEY_NONE) { + throw new CommandExecuteException( + String.format("\"%s\" is not a valid key name", key)); } - }); + + bind(kc); + serialize(); + + dt.write(String.format("Bound %s to key %s [code=%d]", getAbsoluteName(), key, kc)); + dt.stopProcessing(); + } else if (dt.hasOption("unbind")) { + unbind(); + serialize(); + + dt.write(String.format("Unbound %s", getAbsoluteName())); + dt.stopProcessing(); + } + }); this.processors.add( - dt -> { - if (!dt.options().hasOptions() && dt.getArgumentCount() > 0) { - dt.write( - String.format( - "Unknown command \"%s\"", Strings.nullToEmpty(dt.getArgumentAsString(0)))); - } - }); + dt -> { + if (!dt.options().hasOptions() && dt.getArgumentCount() > 0) { + dt.write( + String.format( + "Unknown command \"%s\"", Strings.nullToEmpty(dt.getArgumentAsString(0)))); + } + }); } } else { bind = null; } } - + @Override public void serialize(JsonWriter writer) throws IOException { writer.beginObject(); - + writer.name("bind"); - if (bind != null) writer.value(bind.getKeyCode()); - else writer.value(-1); - + if (bind != null) { + writer.value(bind.getKeyCode()); + } else { + writer.value(-1); + } + writer.endObject(); } - + @Override public void deserialize(JsonReader reader) throws IOException { reader.beginObject(); - + reader.nextName(); int kc = reader.nextInt(); - if (kc > -1) bind(kc); - + if (kc > -1) { + bind(kc); + } + reader.endObject(); } - + @Override public void bind(int keyCode) { if (bind != null) { @@ -102,17 +111,17 @@ public void bind(int keyCode) { KeyBinding.resetKeyBindingArrayAndHash(); } } - + @Nullable public KeyBinding getBind() { return bind; } - + @Override public void onKeyPressed() { invokeCallbacks(CallbackType.KEY_PRESSED, new CallbackData(this)); } - + @Override public void onKeyDown() { invokeCallbacks(CallbackType.KEY_DOWN, new CallbackData(this)); diff --git a/src/main/java/com/matt/forgehax/util/command/ExecuteData.java b/src/main/java/com/matt/forgehax/util/command/ExecuteData.java index 8b6d63530..d1993822c 100644 --- a/src/main/java/com/matt/forgehax/util/command/ExecuteData.java +++ b/src/main/java/com/matt/forgehax/util/command/ExecuteData.java @@ -7,70 +7,82 @@ import com.matt.forgehax.util.command.exception.CommandExecuteException; import com.matt.forgehax.util.command.exception.MissingEntryException; import com.matt.forgehax.util.console.ConsoleWriter; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; import javax.annotation.Nullable; import joptsimple.OptionSet; -/** Created on 6/6/2017 by fr1kin */ +/** + * Created on 6/6/2017 by fr1kin + */ public class ExecuteData implements Globals, ConsoleWriter { + public enum State { NONE, SUCCESS, FAILED, ; } - + private final Command command; private final OptionSet options; - + private final List arguments = Lists.newArrayList(); - - @Nullable private Map data = null; - + + @Nullable + private Map data = null; + private State state = State.FAILED; - + private boolean stopped = false; - + public ExecuteData(Command command, OptionSet options, Object[] extraArguments) { this.command = command; this.options = options; this.arguments.addAll(Arrays.asList(extraArguments)); this.arguments.addAll(options.nonOptionArguments()); } - + public State state() { return state; } - + private void setState(State state, State... conditions) { - for (State s : conditions) if (this.state.equals(s)) return; + for (State s : conditions) { + if (this.state.equals(s)) { + return; + } + } this.state = state; } - + public void markSuccess(State... conditions) { setState(State.SUCCESS, conditions); } - + public void markFailed(State... conditions) { setState(State.FAILED, conditions); } - + public void unmark() { state = State.NONE; } - + public Command command() { return this.command; } - + public OptionSet options() { return this.options; } - + public List arguments() { return this.arguments; } - + public T getArgument(int index) { try { return (T) arguments.get(index); @@ -78,15 +90,15 @@ public T getArgument(int index) { return null; } } - + public String getArgumentAsString(int index) { return SafeConverter.toString(getArgument(index)); } - + public int getArgumentCount() { return arguments.size(); } - + public Object getOption(String name, Object defaultValue) { try { return getOptions(name).get(0); @@ -94,38 +106,45 @@ public Object getOption(String name, Object defaultValue) { return defaultValue; } } - + public Object getOption(String name) { return getOption(name, null); } - + public String getOptionAsString(String name) { return String.valueOf(getOption(name)); } - + public List getOptions(String name) { - if (options.has(name)) + if (options.has(name)) { try { return options.valuesOf(name); - } catch (Throwable t) {; + } catch (Throwable t) { + ; } + } return Collections.emptyList(); } - + public boolean hasOption(String name) { return options.has(name); } - + public void set(String name, T element) { - if (data == null) data = Maps.newHashMap(); - if (element == null) data.remove(name); - else data.put(name, element); + if (data == null) { + data = Maps.newHashMap(); + } + if (element == null) { + data.remove(name); + } else { + data.put(name, element); + } } - + public boolean has(String name) { return data != null && data.get(name) != null; } - + @SuppressWarnings("unchecked") public T get(String name, T defaultValue) { try { @@ -136,33 +155,33 @@ public T get(String name, T defaultValue) { return defaultValue; } } - + public T get(String name) { return get(name, null); } - + public void requiresEntry(String name) throws MissingEntryException { if (get(name) == null) { markFailed(); throw new MissingEntryException(String.format("Missing data entry \"%s\"", name)); } } - + public void requiredArguments(int numberRequired) { if (arguments.size() < numberRequired) { markFailed(); throw new CommandExecuteException("Missing argument(s)"); } } - + public boolean isStopped() { return stopped; } - + public void startProcessing() { stopped = false; } - + public void stopProcessing() { stopped = true; } diff --git a/src/main/java/com/matt/forgehax/util/command/Options.java b/src/main/java/com/matt/forgehax/util/command/Options.java index bb0a4566e..131557bbf 100644 --- a/src/main/java/com/matt/forgehax/util/command/Options.java +++ b/src/main/java/com/matt/forgehax/util/command/Options.java @@ -6,32 +6,39 @@ import com.matt.forgehax.util.console.ConsoleIO; import com.matt.forgehax.util.serialization.ISerializableJson; import java.io.IOException; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; -/** Created on 6/4/2017 by fr1kin */ +/** + * Created on 6/4/2017 by fr1kin + */ public class Options extends Command - implements Collection, ISerializableJson { + implements Collection, ISerializableJson { + public static final String SUPPLIER = "Options.supplier"; public static final String FACTORY = "Options.factory"; public static final String DEFAULTS = "Options.defaults"; - + private final Collection contents; private final Function factory; - + private final Collection defaults; - + @SuppressWarnings("unchecked") protected Options(Map data) throws CommandBuildException { super(data); try { Supplier> supplier = (Supplier>) data.get(SUPPLIER); Objects.requireNonNull(supplier, "Missing supplier"); - + this.contents = supplier.get(); this.factory = (Function) data.get(FACTORY); - + Supplier> defaults = (Supplier>) data.get(DEFAULTS); if (defaults != null) { this.defaults = supplier.get(); @@ -40,12 +47,12 @@ protected Options(Map data) throws CommandBuildException { } else { this.defaults = Collections.emptyList(); } - + } catch (Throwable t) { throw new CommandBuildException("Failed to build options", t); } } - + @Override protected boolean preprocessor(String[] args) { if (args.length > 0) { @@ -59,85 +66,89 @@ protected boolean preprocessor(String[] args) { } return true; } - + public Collection contents() { return contents; } - + public E get(Object o) { - for (E element : this) if (Objects.equals(element, o)) return element; + for (E element : this) { + if (Objects.equals(element, o)) { + return element; + } + } return null; } - + @Override public int size() { return contents.size(); } - + @Override public boolean isEmpty() { return contents.isEmpty(); } - + @Override public boolean contains(Object o) { return contents.contains(o); } - + @Override public Iterator iterator() { return contents.iterator(); } - + @Override public Object[] toArray() { return contents.toArray(); } - + @Override public T[] toArray(T[] a) { return contents.toArray(a); } - + @Override public boolean add(E e) { return contents.add(e); } - + @Override public boolean remove(Object o) { return contents.remove(o); } - + @Override public boolean containsAll(Collection c) { return contents.containsAll(c); } - + @Override public boolean addAll(Collection c) { return contents.addAll(c); } - + @Override public boolean removeAll(Collection c) { return contents.removeAll(c); } - + @Override public boolean retainAll(Collection c) { return contents.retainAll(c); } - + @Override public void clear() { contents.clear(); } - + @Override public void serialize(JsonWriter writer) throws IOException { writer.beginObject(); - + writer.name("data"); writer.beginObject(); for (E element : contents) { @@ -145,14 +156,14 @@ public void serialize(JsonWriter writer) throws IOException { element.serialize(writer); } writer.endObject(); - + writer.endObject(); } - + @Override public void deserialize(JsonReader reader) throws IOException { reader.beginObject(); - + reader.nextName(); // data reader.beginObject(); clear(); // clear current contents @@ -165,10 +176,10 @@ public void deserialize(JsonReader reader) throws IOException { } } reader.endObject(); - + reader.endObject(); } - + @Override public String toString() { return getAbsoluteName(); diff --git a/src/main/java/com/matt/forgehax/util/command/OptionsBuilder.java b/src/main/java/com/matt/forgehax/util/command/OptionsBuilder.java index 9beed29ab..abc58217a 100644 --- a/src/main/java/com/matt/forgehax/util/command/OptionsBuilder.java +++ b/src/main/java/com/matt/forgehax/util/command/OptionsBuilder.java @@ -5,21 +5,24 @@ import java.util.function.Function; import java.util.function.Supplier; -/** Created on 6/5/2017 by fr1kin */ +/** + * Created on 6/5/2017 by fr1kin + */ public class OptionsBuilder - extends BaseCommandBuilder, Options> { + extends BaseCommandBuilder, Options> { + public OptionsBuilder supplier(Supplier> supplier) { return insert(Options.SUPPLIER, supplier); } - + public OptionsBuilder factory(Function factory) { return insert(Options.FACTORY, factory); } - + public OptionsBuilder defaults(Supplier> defaults) { return insert(Options.DEFAULTS, defaults); } - + @Override public Options build() { return new Options(data); diff --git a/src/main/java/com/matt/forgehax/util/command/Setting.java b/src/main/java/com/matt/forgehax/util/command/Setting.java index 12fc19ccd..7f698f024 100644 --- a/src/main/java/com/matt/forgehax/util/command/Setting.java +++ b/src/main/java/com/matt/forgehax/util/command/Setting.java @@ -18,8 +18,11 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -/** Created on 6/2/2017 by fr1kin */ +/** + * Created on 6/2/2017 by fr1kin + */ public class Setting extends Command implements ISerializableJson { + public static final String DEFAULTVALUE = "Setting.defaultValue"; public static final String CONVERTER = "Setting.converter"; public static final String COMPARATOR = "Setting.comparator"; @@ -27,185 +30,193 @@ public class Setting extends Command implements ISerializableJson { public static final String MAXVALUE = "Setting.maxvalue"; public static final String RESETAUTOGEN = "Setting.resetAutoGen"; public static final String DEFAULTPROCESSOR = "Setting.defaultProcessor"; - + private final E defaultValue; private final TypeConverter converter; private final Comparator comparator; - + private final E minValue; private final E maxValue; - + private E value; - + @SuppressWarnings("unchecked") protected Setting(Map data) throws CommandBuildException { super(data); try { this.converter = (TypeConverter) data.get(CONVERTER); Objects.requireNonNull(this.converter, "Setting requires converter"); - + this.defaultValue = (E) data.get(DEFAULTVALUE); this.comparator = (Comparator) data.get(COMPARATOR); this.minValue = (E) data.get(MINVALUE); this.maxValue = (E) data.get(MAXVALUE); - + Boolean defaultProcessor = (Boolean) data.getOrDefault(DEFAULTPROCESSOR, true); if (defaultProcessor) { processors.add( - in -> { - in.requiredArguments(1); - Object arg = in.getArgument(0); - if (arg != null) { - rawSet(String.valueOf(arg)); - serialize(); - in.markSuccess(); - } else in.markFailed(); - }); + in -> { + in.requiredArguments(1); + Object arg = in.getArgument(0); + if (arg != null) { + rawSet(String.valueOf(arg)); + serialize(); + in.markSuccess(); + } else { + in.markFailed(); + } + }); } - + Boolean resetAutoGen = (Boolean) data.getOrDefault(RESETAUTOGEN, true); if (resetAutoGen) { parser.acceptsAll(Arrays.asList("r", "reset"), "Sets the command to its default value"); } - + // set with constraints set(defaultValue, true); } catch (Throwable t) { throw new CommandBuildException("Failed to build setting", t); } } - + public E get() { return value; } - + public E getMin() { return minValue; } - + public E getMax() { return maxValue; } - + public E getDefault() { return defaultValue; } - + @Nonnull public Class getType() { return converter.type(); } - + public boolean getAsBoolean() { return SafeConverter.toBoolean(get()); } - + public byte getAsByte() { return SafeConverter.toByte(get()); } - + public char getAsCharacter() { return SafeConverter.toCharacter(get()); } - + public double getAsDouble() { return SafeConverter.toDouble(get()); } - + public float getAsFloat() { return SafeConverter.toFloat(get()); } - + public int getAsInteger() { return SafeConverter.toInteger(get()); } - + public long getAsLong() { return SafeConverter.toLong(get()); } - + public short getAsShort() { return SafeConverter.toShort(get()); } - + public String getAsString() { return converter.toString(get()); } - + public boolean set(E value, boolean silent) { if (comparator != null && value != null && this.value != null) { // clamp value to minimum and maximum value - if (minValue != null && comparator.compare(value, minValue) < 0) value = minValue; - else if (maxValue != null && comparator.compare(value, maxValue) > 0) value = maxValue; + if (minValue != null && comparator.compare(value, minValue) < 0) { + value = minValue; + } else if (maxValue != null && comparator.compare(value, maxValue) > 0) { + value = maxValue; + } } if (!Objects.equals(get(), value)) { if (!silent) { ConsoleIO.write(String.format("%s = %s", getAbsoluteName(), converter.toStringSafe(value))); OnChangeCallback cb = new OnChangeCallback<>(this, get(), value); invokeCallbacks(CallbackType.CHANGE, cb); - if (cb.isCanceled()) return false; + if (cb.isCanceled()) { + return false; + } } this.value = value; return true; } return false; } - + public boolean set(E value) { return set(value, false); } - + public boolean rawSet(String value, boolean silent) { return set(converter.parseSafe(value), silent); } - + public boolean rawSet(String value) { return rawSet(value, false); } - + public boolean reset() { return set(defaultValue); } - + public TypeConverter getConverter() { return converter; } - + @Override public String getPrintText() { return getName() + " = " + getAsString() + " - " + getDescription(); } - + @Override public boolean addChild(@Nonnull Command child) { throw new UnsupportedOperationException( - "Command::addChild is not supported for a Setting type"); + "Command::addChild is not supported for a Setting type"); } - + @Override public boolean removeChild(@Nonnull Command child) { return false; } - + @Nullable @Override public Command getChild(String name) { return null; } - + @Override public Collection getChildren() { return Collections.emptySet(); } - + @Override - public void getChildrenDeep(Collection all) {} - + public void getChildrenDeep(Collection all) { + } + @Override public Collection getChildrenDeep() { return Collections.emptySet(); } - + @Override protected boolean preprocessor(String[] args) { if (args.length > 0) { @@ -218,24 +229,24 @@ protected boolean preprocessor(String[] args) { } return true; } - + @Override public void serialize(JsonWriter writer) throws IOException { writer.beginObject(); - + writer.name("value"); writer.value(getAsString()); - + writer.endObject(); } - + @Override public void deserialize(JsonReader reader) throws IOException { reader.beginObject(); - + reader.nextName(); // value rawSet(reader.nextString(), true); - + reader.endObject(); } } diff --git a/src/main/java/com/matt/forgehax/util/command/SettingBuilder.java b/src/main/java/com/matt/forgehax/util/command/SettingBuilder.java index 4306e7da8..780b46f23 100644 --- a/src/main/java/com/matt/forgehax/util/command/SettingBuilder.java +++ b/src/main/java/com/matt/forgehax/util/command/SettingBuilder.java @@ -7,43 +7,48 @@ import java.util.Comparator; import java.util.function.Consumer; -/** Created on 6/3/2017 by fr1kin */ +/** + * Created on 6/3/2017 by fr1kin + */ public class SettingBuilder extends BaseCommandBuilder, Setting> - implements Globals { + implements Globals { + public SettingBuilder changed(Consumer> consumer) { getCallbacks(CallbackType.CHANGE).add(consumer); return this; } - + public SettingBuilder defaultTo(E defaultValue) { return insert(Setting.DEFAULTVALUE, defaultValue).type(defaultValue.getClass()); } - + public SettingBuilder converter(TypeConverter converter) { return insert(Setting.CONVERTER, converter).comparator(converter.comparator()); } - + public SettingBuilder comparator(Comparator comparator) { return insert(Setting.COMPARATOR, comparator); } - + public SettingBuilder min(E minValue) { return insert(Setting.MINVALUE, minValue); } - + public SettingBuilder max(E maxValue) { return insert(Setting.MAXVALUE, maxValue); } - + public SettingBuilder type(Class clazz) { - if (has(Setting.CONVERTER)) return this; + if (has(Setting.CONVERTER)) { + return this; + } return converter(TypeConverterRegistry.get(clazz)); } - + public SettingBuilder customProcessor() { return insert(Setting.DEFAULTPROCESSOR, false); } - + @Override public Setting build() { return new Setting<>(has(Command.REQUIREDARGS) ? data : requiredArgs(1).data); diff --git a/src/main/java/com/matt/forgehax/util/command/SettingEnumBuilder.java b/src/main/java/com/matt/forgehax/util/command/SettingEnumBuilder.java index 99f964a9c..99a34da35 100644 --- a/src/main/java/com/matt/forgehax/util/command/SettingEnumBuilder.java +++ b/src/main/java/com/matt/forgehax/util/command/SettingEnumBuilder.java @@ -10,85 +10,89 @@ import net.minecraft.util.math.MathHelper; import org.apache.commons.lang3.StringUtils; -/** Created on 8/5/2017 by fr1kin */ +/** + * Created on 8/5/2017 by fr1kin + */ public class SettingEnumBuilder> - extends BaseCommandBuilder, Setting> { + extends BaseCommandBuilder, Setting> { + public SettingEnumBuilder changed(Consumer> consumer) { getCallbacks(CallbackType.CHANGE).add(consumer); return this; } - + public SettingEnumBuilder defaultTo(E defaultValue) { return insert(Setting.DEFAULTVALUE, defaultValue).convertFrom(defaultValue.getClass()); } - + private SettingEnumBuilder converter(TypeConverter converter) { return insert(Setting.CONVERTER, converter).comparator(converter.comparator()); } - + private SettingEnumBuilder comparator(Comparator comparator) { return insert(Setting.COMPARATOR, comparator); } - + private SettingEnumBuilder min(E minValue) { return insert(Setting.MINVALUE, minValue); } - + private SettingEnumBuilder max(E maxValue) { return insert(Setting.MAXVALUE, maxValue); } - + private SettingEnumBuilder convertFrom(Class clazz) { TypeConverter converter = TypeConverterRegistry.get(clazz); - if (converter == null) + if (converter == null) { converter = - new TypeConverter() { - @Override - public String label() { - return clazz.getName(); - } - - @Override - public Class type() { - return (Class) clazz; - } - - @Override - public E parse(String value) { - return Arrays.stream(type().getEnumConstants()) - .filter(e -> e.name().toLowerCase().contains(value.toLowerCase())) - .min( - Comparator.comparing( - e -> - StringUtils.getLevenshteinDistance( - e.name().toLowerCase(), value.toLowerCase()))) - .orElseGet( - () -> { - E[] values = type().getEnumConstants(); - try { - int index = Integer.valueOf(value); - return values[MathHelper.clamp(index, 0, values.length - 1)]; - } catch (NumberFormatException e) { - return values[0]; - } - }); - } - - @Override - public String toString(E value) { - return value.name(); - } - - @Nullable - @Override - public Comparator comparator() { - return Enum::compareTo; - } - }; - + new TypeConverter() { + @Override + public String label() { + return clazz.getName(); + } + + @Override + public Class type() { + return (Class) clazz; + } + + @Override + public E parse(String value) { + return Arrays.stream(type().getEnumConstants()) + .filter(e -> e.name().toLowerCase().contains(value.toLowerCase())) + .min( + Comparator.comparing( + e -> + StringUtils.getLevenshteinDistance( + e.name().toLowerCase(), value.toLowerCase()))) + .orElseGet( + () -> { + E[] values = type().getEnumConstants(); + try { + int index = Integer.valueOf(value); + return values[MathHelper.clamp(index, 0, values.length - 1)]; + } catch (NumberFormatException e) { + return values[0]; + } + }); + } + + @Override + public String toString(E value) { + return value.name(); + } + + @Nullable + @Override + public Comparator comparator() { + return Enum::compareTo; + } + }; + } + E min; E max; - + try { E[] constants = (E[]) clazz.getEnumConstants(); min = constants[0]; @@ -97,10 +101,10 @@ public Comparator comparator() { min = null; max = null; } - + return converter(converter).comparator(converter.comparator()).min(min).max(max); } - + @Override public Setting build() { return new Setting<>(has(Command.REQUIREDARGS) ? data : requiredArgs(1).data); diff --git a/src/main/java/com/matt/forgehax/util/command/StubBuilder.java b/src/main/java/com/matt/forgehax/util/command/StubBuilder.java index 4fee20516..b22be89b1 100644 --- a/src/main/java/com/matt/forgehax/util/command/StubBuilder.java +++ b/src/main/java/com/matt/forgehax/util/command/StubBuilder.java @@ -4,34 +4,37 @@ import java.util.function.Consumer; import org.lwjgl.input.Keyboard; -/** Created on 6/8/2017 by fr1kin */ +/** + * Created on 6/8/2017 by fr1kin + */ public class StubBuilder extends BaseCommandBuilder { + public StubBuilder kpressed(Consumer consumer) { getCallbacks(CallbackType.KEY_PRESSED).add(consumer); return this; } - + public StubBuilder kdown(Consumer consumer) { getCallbacks(CallbackType.KEY_DOWN).add(consumer); return this; } - + public StubBuilder bind(int keyCode) { return insert(CommandStub.KEYBIND, keyCode); } - + public StubBuilder bind() { return bind(Keyboard.KEY_NONE); } - + public StubBuilder nobind() { return bind(-1); } - + public StubBuilder bindOptions(boolean b) { return insert(CommandStub.KEYBIND_OPTIONS, b); } - + @Override public CommandStub build() { return new CommandStub(data); diff --git a/src/main/java/com/matt/forgehax/util/command/callbacks/CallbackData.java b/src/main/java/com/matt/forgehax/util/command/callbacks/CallbackData.java index a0699016d..71e045d1c 100644 --- a/src/main/java/com/matt/forgehax/util/command/callbacks/CallbackData.java +++ b/src/main/java/com/matt/forgehax/util/command/callbacks/CallbackData.java @@ -3,14 +3,17 @@ import com.matt.forgehax.util.command.Command; import com.matt.forgehax.util.console.ConsoleWriter; -/** Created on 6/8/2017 by fr1kin */ +/** + * Created on 6/8/2017 by fr1kin + */ public class CallbackData implements ConsoleWriter { + private final Command command; - + public CallbackData(Command command) { this.command = command; } - + public T command() { return (T) command; } diff --git a/src/main/java/com/matt/forgehax/util/command/callbacks/CancelableCallbackData.java b/src/main/java/com/matt/forgehax/util/command/callbacks/CancelableCallbackData.java index abc02b2fb..cf0dda8de 100644 --- a/src/main/java/com/matt/forgehax/util/command/callbacks/CancelableCallbackData.java +++ b/src/main/java/com/matt/forgehax/util/command/callbacks/CancelableCallbackData.java @@ -2,22 +2,25 @@ import com.matt.forgehax.util.command.Command; -/** Created on 6/8/2017 by fr1kin */ +/** + * Created on 6/8/2017 by fr1kin + */ public class CancelableCallbackData extends CallbackData { + private boolean canceled = false; - + public CancelableCallbackData(Command command) { super(command); } - + public boolean isCanceled() { return canceled; } - + public void setCanceled(boolean canceled) { this.canceled = canceled; } - + public void cancel() { setCanceled(true); } diff --git a/src/main/java/com/matt/forgehax/util/command/callbacks/OnChangeCallback.java b/src/main/java/com/matt/forgehax/util/command/callbacks/OnChangeCallback.java index fbce6c2e7..1394fec81 100644 --- a/src/main/java/com/matt/forgehax/util/command/callbacks/OnChangeCallback.java +++ b/src/main/java/com/matt/forgehax/util/command/callbacks/OnChangeCallback.java @@ -2,21 +2,24 @@ import com.matt.forgehax.util.command.Command; -/** Created on 6/8/2017 by fr1kin */ +/** + * Created on 6/8/2017 by fr1kin + */ public class OnChangeCallback extends CancelableCallbackData { + private final E from; private final E to; - + public OnChangeCallback(Command command, E from, E to) { super(command); this.from = from; this.to = to; } - + public E getFrom() { return from; } - + public E getTo() { return to; } diff --git a/src/main/java/com/matt/forgehax/util/command/exception/CommandBuildException.java b/src/main/java/com/matt/forgehax/util/command/exception/CommandBuildException.java index cfb689985..4ce65e818 100644 --- a/src/main/java/com/matt/forgehax/util/command/exception/CommandBuildException.java +++ b/src/main/java/com/matt/forgehax/util/command/exception/CommandBuildException.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.command.exception; -/** Created on 6/6/2017 by fr1kin */ +/** + * Created on 6/6/2017 by fr1kin + */ public class CommandBuildException extends RuntimeException { + public CommandBuildException(String message, Throwable cause) { super(message, cause); } diff --git a/src/main/java/com/matt/forgehax/util/command/exception/CommandExecuteException.java b/src/main/java/com/matt/forgehax/util/command/exception/CommandExecuteException.java index 60e51c74c..1ef32e40b 100644 --- a/src/main/java/com/matt/forgehax/util/command/exception/CommandExecuteException.java +++ b/src/main/java/com/matt/forgehax/util/command/exception/CommandExecuteException.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.command.exception; -/** Created on 5/14/2017 by fr1kin */ +/** + * Created on 5/14/2017 by fr1kin + */ public class CommandExecuteException extends RuntimeException { + /** * Constructs a new runtime exception with {@code null} as its detail message. The cause is not * initialized, and may subsequently be initialized by a call to {@link #initCause}. @@ -9,18 +12,18 @@ public class CommandExecuteException extends RuntimeException { public CommandExecuteException() { super(); } - + /** * Constructs a new runtime exception with the specified detail message. The cause is not * initialized, and may subsequently be initialized by a call to {@link #initCause}. * * @param message the detail message. The detail message is saved for later retrieval by the - * {@link #getMessage()} method. + * {@link #getMessage()} method. */ public CommandExecuteException(String message) { super(message); } - + /** * Constructs a new runtime exception with the specified detail message and cause. * @@ -28,44 +31,43 @@ public CommandExecuteException(String message) { * incorporated in this runtime exception's detail message. * * @param message the detail message (which is saved for later retrieval by the {@link - * #getMessage()} method). + * #getMessage()} method). * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). - * (A null value is permitted, and indicates that the cause is nonexistent or - * unknown.) + * (A null value is permitted, and indicates that the cause is nonexistent or unknown.) * @since 1.4 */ public CommandExecuteException(String message, Throwable cause) { super(message, cause); } - + /** * Constructs a new runtime exception with the specified cause and a detail message of - * (cause==null ? null : cause.toString()) (which typically contains the class and detail + * (cause==null ? null : cause.toString()) (which typically contains the class and + * detail * message of cause). This constructor is useful for runtime exceptions that are little * more than wrappers for other throwables. * * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method). - * (A null value is permitted, and indicates that the cause is nonexistent or - * unknown.) + * (A null value is permitted, and indicates that the cause is nonexistent or unknown.) * @since 1.4 */ public CommandExecuteException(Throwable cause) { super(cause); } - + /** * Constructs a new runtime exception with the specified detail message, cause, suppression * enabled or disabled, and writable stack trace enabled or disabled. * * @param message the detail message. * @param cause the cause. (A {@code null} value is permitted, and indicates that the cause is - * nonexistent or unknown.) + * nonexistent or unknown.) * @param enableSuppression whether or not suppression is enabled or disabled * @param writableStackTrace whether or not the stack trace should be writable * @since 1.7 */ protected CommandExecuteException( - String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } } diff --git a/src/main/java/com/matt/forgehax/util/command/exception/CommandParentNonNullException.java b/src/main/java/com/matt/forgehax/util/command/exception/CommandParentNonNullException.java index dbeaa179e..b348d8d46 100644 --- a/src/main/java/com/matt/forgehax/util/command/exception/CommandParentNonNullException.java +++ b/src/main/java/com/matt/forgehax/util/command/exception/CommandParentNonNullException.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.command.exception; -/** Created on 6/3/2017 by fr1kin */ +/** + * Created on 6/3/2017 by fr1kin + */ public class CommandParentNonNullException extends RuntimeException { + public CommandParentNonNullException(String msg) { super(msg); } diff --git a/src/main/java/com/matt/forgehax/util/command/exception/MissingEntryException.java b/src/main/java/com/matt/forgehax/util/command/exception/MissingEntryException.java index ace61cd99..5403c3571 100644 --- a/src/main/java/com/matt/forgehax/util/command/exception/MissingEntryException.java +++ b/src/main/java/com/matt/forgehax/util/command/exception/MissingEntryException.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.command.exception; -/** Created on 6/8/2017 by fr1kin */ +/** + * Created on 6/8/2017 by fr1kin + */ public class MissingEntryException extends CommandExecuteException { + public MissingEntryException(String message) { super(message); } diff --git a/src/main/java/com/matt/forgehax/util/command/flags/ICommandFlag.java b/src/main/java/com/matt/forgehax/util/command/flags/ICommandFlag.java index 283858b09..4783efe62 100644 --- a/src/main/java/com/matt/forgehax/util/command/flags/ICommandFlag.java +++ b/src/main/java/com/matt/forgehax/util/command/flags/ICommandFlag.java @@ -1,4 +1,8 @@ package com.matt.forgehax.util.command.flags; -/** Created on 6/8/2017 by fr1kin */ -public interface ICommandFlag {} +/** + * Created on 6/8/2017 by fr1kin + */ +public interface ICommandFlag { + +} diff --git a/src/main/java/com/matt/forgehax/util/command/options/BlockEntryProcessor.java b/src/main/java/com/matt/forgehax/util/command/options/BlockEntryProcessor.java index 7d855d034..39017102d 100644 --- a/src/main/java/com/matt/forgehax/util/command/options/BlockEntryProcessor.java +++ b/src/main/java/com/matt/forgehax/util/command/options/BlockEntryProcessor.java @@ -2,78 +2,85 @@ import com.google.common.collect.Sets; import com.matt.forgehax.util.SafeConverter; -import com.matt.forgehax.util.Utils; import com.matt.forgehax.util.blocks.BlockEntry; import com.matt.forgehax.util.blocks.BlockOptionHelper; import com.matt.forgehax.util.blocks.properties.BoundProperty; import com.matt.forgehax.util.blocks.properties.ColorProperty; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.command.ExecuteData; import com.matt.forgehax.util.command.exception.CommandExecuteException; import java.util.Collection; -/** Created on 6/6/2017 by fr1kin */ +/** + * Created on 6/6/2017 by fr1kin + */ public class BlockEntryProcessor { + public static void buildCollection(ExecuteData data) { data.requiredArguments(1); data.requiresEntry("meta"); - + String arg = data.getArgumentAsString(0); - + int meta = data.get("meta"); - + boolean id = data.options().has("id"); boolean regex = data.options().has("regex"); - - if (id && regex) throw new CommandExecuteException("Cannot contain both id and regex flag"); - + + if (id && regex) { + throw new CommandExecuteException("Cannot contain both id and regex flag"); + } + Collection process = Sets.newHashSet(); - + try { - if (regex) process.addAll(BlockOptionHelper.getAllBlocksMatchingByUnlocalized(arg)); - else + if (regex) { + process.addAll(BlockOptionHelper.getAllBlocksMatchingByUnlocalized(arg)); + } else { process.add( - id ? new BlockEntry(SafeConverter.toInteger(arg), meta) : new BlockEntry(arg, meta)); + id ? new BlockEntry(SafeConverter.toInteger(arg), meta) : new BlockEntry(arg, meta)); + } } catch (Throwable t) { throw new CommandExecuteException(t.getMessage()); } - + data.set("entries", process); } - + public static void processColor(ExecuteData data) { data.requiresEntry("entries"); - + Collection entries = data.get("entries"); boolean isColorPresent = data.get("isColorPresent", false); - + if (isColorPresent) { - final int colorBuffer = data.get("colorBuffer", Utils.Colors.WHITE); + final int colorBuffer = data.get("colorBuffer", Colors.WHITE.toBuffer()); entries.forEach(entry -> entry.getWritableProperty(ColorProperty.class).set(colorBuffer)); } } - + public static void processBounds(ExecuteData data) { if (data.hasOption("bounds")) { data.requiresEntry("entries"); final Collection entries = data.get("entries"); - + data.getOptions("bounds") - .forEach( - p -> { - String value = String.valueOf(p); - String[] mm = value.split("-"); - if (mm.length > 1) { - int min = SafeConverter.toInteger(mm[0]); - int max = SafeConverter.toInteger(mm[1]); - entries.forEach( - entry -> entry.getWritableProperty(BoundProperty.class).add(min, max)); - } else { - throw new IllegalArgumentException( - String.format( - "Invalid argument \"%s\" given for bounds option. Should be formatted like min-max", - value)); - } - }); + .forEach( + p -> { + String value = String.valueOf(p); + String[] mm = value.split("-"); + if (mm.length > 1) { + int min = SafeConverter.toInteger(mm[0]); + int max = SafeConverter.toInteger(mm[1]); + entries.forEach( + entry -> entry.getWritableProperty(BoundProperty.class).add(min, max)); + } else { + throw new IllegalArgumentException( + String.format( + "Invalid argument \"%s\" given for bounds option. Should be formatted like min-max", + value)); + } + }); } } } diff --git a/src/main/java/com/matt/forgehax/util/command/options/OptionBuilders.java b/src/main/java/com/matt/forgehax/util/command/options/OptionBuilders.java index aff579e79..23653467e 100644 --- a/src/main/java/com/matt/forgehax/util/command/options/OptionBuilders.java +++ b/src/main/java/com/matt/forgehax/util/command/options/OptionBuilders.java @@ -3,32 +3,35 @@ import java.util.Arrays; import joptsimple.OptionParser; -/** Created on 6/6/2017 by fr1kin */ +/** + * Created on 6/6/2017 by fr1kin + */ public class OptionBuilders { + public static void rgba(OptionParser parser) { parser.acceptsAll(Arrays.asList("red", "r"), "red").withRequiredArg(); parser.acceptsAll(Arrays.asList("green", "g"), "green").withRequiredArg(); parser.acceptsAll(Arrays.asList("blue", "b"), "blue").withRequiredArg(); parser.acceptsAll(Arrays.asList("alpha", "a"), "alpha").withRequiredArg(); } - + public static void meta(OptionParser parser) { parser.acceptsAll(Arrays.asList("meta", "m"), "blocks metadata id").withRequiredArg(); } - + public static void id(OptionParser parser) { parser.acceptsAll(Arrays.asList("id", "i"), "searches for block by id instead of name"); } - + public static void regex(OptionParser parser) { parser.acceptsAll( - Arrays.asList("regex", "e"), - "searches for blocks by using the argument as a regex expression"); + Arrays.asList("regex", "e"), + "searches for blocks by using the argument as a regex expression"); } - + public static void bounds(OptionParser parser) { parser - .accepts("bounds", "Will only draw blocks from within the min-max bounds given") - .withRequiredArg(); + .accepts("bounds", "Will only draw blocks from within the min-max bounds given") + .withRequiredArg(); } } diff --git a/src/main/java/com/matt/forgehax/util/command/options/OptionProcessors.java b/src/main/java/com/matt/forgehax/util/command/options/OptionProcessors.java index f072ebe6f..5295a3a79 100644 --- a/src/main/java/com/matt/forgehax/util/command/options/OptionProcessors.java +++ b/src/main/java/com/matt/forgehax/util/command/options/OptionProcessors.java @@ -1,32 +1,36 @@ package com.matt.forgehax.util.command.options; import com.matt.forgehax.util.SafeConverter; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Color; import com.matt.forgehax.util.command.ExecuteData; import net.minecraft.util.math.MathHelper; -/** Created on 6/6/2017 by fr1kin */ +/** + * Created on 6/6/2017 by fr1kin + */ public class OptionProcessors { + public static void rgba(ExecuteData data) { int r = SafeConverter.toInteger(data.getOption("red"), 255); int g = SafeConverter.toInteger(data.getOption("green"), 255); int b = SafeConverter.toInteger(data.getOption("blue"), 255); int a = SafeConverter.toInteger(data.getOption("alpha"), 255); data.set( - "colorBuffer", - Utils.toRGBA( - MathHelper.clamp(r, 0, 255), - MathHelper.clamp(g, 0, 255), - MathHelper.clamp(b, 0, 255), - MathHelper.clamp(a, 0, 255))); + "colorBuffer", + Color.of( + MathHelper.clamp(r, 0, 255), + MathHelper.clamp(g, 0, 255), + MathHelper.clamp(b, 0, 255), + MathHelper.clamp(a, 0, 255) + ).toBuffer()); data.set( - "isColorPresent", - data.hasOption("red") - || data.hasOption("green") - || data.hasOption("blue") - || data.hasOption("alpha")); + "isColorPresent", + data.hasOption("red") + || data.hasOption("green") + || data.hasOption("blue") + || data.hasOption("alpha")); } - + public static void meta(ExecuteData data) { data.set("meta", SafeConverter.toInteger(data.getOption("meta"), 0)); } diff --git a/src/main/java/com/matt/forgehax/util/command/v2/AbstractCmd.java b/src/main/java/com/matt/forgehax/util/command/v2/AbstractCmd.java deleted file mode 100644 index cd4e53e71..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/AbstractCmd.java +++ /dev/null @@ -1,230 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.Immutables; -import com.matt.forgehax.util.command.v2.argument.ArgHelper; -import com.matt.forgehax.util.command.v2.argument.IArg; -import com.matt.forgehax.util.command.v2.argument.IOption; -import com.matt.forgehax.util.command.v2.callback.ICmdCallback; -import com.matt.forgehax.util.command.v2.exception.CmdExceptions; -import com.matt.forgehax.util.command.v2.exception.CmdRuntimeException; -import com.matt.forgehax.util.command.v2.flag.ICmdFlag; -import com.matt.forgehax.util.command.v2.serializers.CmdFlagSerializer; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** Created on 12/26/2017 by fr1kin */ -public abstract class AbstractCmd implements ICmd { - private final String name; - private final Collection aliases; - private final String description; - private final IParentCmd parent; - private final List> arguments; - private final List> options; - - protected final Set> flags = Sets.newCopyOnWriteArraySet(); - protected final Set callbacks = Sets.newCopyOnWriteArraySet(); - - public AbstractCmd( - String name, - @Nullable Collection aliases, - String description, - @Nullable IParentCmd parent, - @Nullable Collection> arguments, - @Nullable Collection> options) - throws CmdRuntimeException.CreationFailure { - CmdExceptions.checkIfNullOrEmpty(name, "name empty or null"); - CmdExceptions.checkIfNullOrEmpty(description, "description empty or null"); - - this.name = name; - this.aliases = Immutables.copyToList(aliases); - this.description = description; - this.parent = parent; - this.arguments = Immutables.copyToList(arguments); - this.options = Immutables.copyToList(options); - - // make sure no alias with the same name as the command exists - if (this.aliases.stream().anyMatch(name::equalsIgnoreCase)) - throw new CmdRuntimeException.CreationFailure("alias cannot be root name"); - - if (ArgHelper.isInvalidArgumentOrder(this.arguments)) - throw new CmdRuntimeException.CreationFailure( - "required arguments are not allowed after non-required arguments"); - - __initialize(); - } - - /** Method that is called at the end of the super constructor. Useful for adding flags. */ - protected void __initialize() {} - - @Override - public String getName() { - return name; - } - - @Override - public String getAbsoluteName() { - return parent == null ? name : parent.getAbsoluteName() + "." + name; - } - - @Nonnull - @Override - public Collection getAliases() { - return aliases; - } - - @Override - public boolean isIdentifiableAs(String name) { - return CmdHelper.isNameValid(name) - && (getName().equalsIgnoreCase(name) - || getAbsoluteName().equalsIgnoreCase(name) - || getAliases().stream().anyMatch(alias -> alias.equalsIgnoreCase(name))); - } - - @Override - public boolean isConflictingWith(ICmd other) { - return isAbsoluteNameMatching(other.getAbsoluteName()) - || (!getAliases().isEmpty() - && other - .getAliases() - .isEmpty() // we don't want to compute this is neither has aliases assigned - && getAliases() - .stream() - .anyMatch(alias -> other.getAliases().stream().anyMatch(alias::equalsIgnoreCase))); - } - - @Override - public String getDescription() { - return description; - } - - @Nullable - @Override - public IParentCmd getParent() { - return parent; - } - - @Override - public List> getArguments() { - return arguments; - } - - @Override - public int getArgumentCount() { - return arguments.size(); - } - - @Override - public List> getOptions() { - return options; - } - - @Override - public String getHelpText(IHelpTextFormatter formatter) { - return null; // TODO: finish - } - - @Override - public String getSyntaxHelpText() { - return null; // TODO: finish - } - - @Override - public Collection> getFlags() { - return ImmutableSet.copyOf(flags); - } - - @Override - public boolean addFlag(Enum flag) { - return flags.add(flag); - } - - @Override - public boolean removeFlag(Enum flag) { - return flags.remove(flag); - } - - @Override - public boolean containsFlag(Enum flag) { - return !flags.isEmpty() && flags.contains(flag); - } - - @Override - public void clearFlags() { - flags.clear(); - } - - @Nonnull - @Override - public Collection getCallbacks() { - return ImmutableSet.copyOf(callbacks); - } - - @Nonnull - @Override - public Collection getCallbacksOfType(Class clazz) { - return callbacks - .stream() - .filter(clazz::isInstance) - .map(clazz::cast) - .collect(Immutables.toImmutableSet()); - } - - @Override - public boolean addCallback(ICmdCallback callback) { - return callbacks.add(callback); - } - - @Override - public boolean removeCallback(ICmdCallback callback) { - return callbacks.remove(callback); - } - - @Override - public int compareTo(ICmd other) { - return other == null ? 1 : String.CASE_INSENSITIVE_ORDER.compare(getName(), other.getName()); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof ICmd && isAbsoluteNameMatching(((ICmd) obj).getAbsoluteName()); - } - - @SuppressWarnings("unchecked") - @Override - public void serialize(JsonWriter writer) throws IOException { - writer.beginObject(); // { - - writer.name("flags"); - CmdFlagSerializer.getInstance().serialize(this, writer); - - writer.endObject(); // } - } - - @SuppressWarnings("unchecked") - @Override - public void deserialize(JsonReader reader) throws IOException { - reader.beginObject(); // { - - while (reader.hasNext()) { - switch (reader.nextName()) { - case "flags": - { - CmdFlagSerializer.getInstance().deserialize(this, reader); - break; - } - default: - reader.skipValue(); - } - } - - reader.endObject(); // } - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/AbstractCmdBuilder.java b/src/main/java/com/matt/forgehax/util/command/v2/AbstractCmdBuilder.java deleted file mode 100644 index 2966e5df7..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/AbstractCmdBuilder.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.matt.forgehax.util.command.v2.argument.*; -import com.matt.forgehax.util.command.v2.callback.ICmdCallback; -import com.matt.forgehax.util.command.v2.flag.ICmdFlag; -import java.util.*; -import java.util.function.Function; -import javax.annotation.Nullable; - -/** Created on 12/26/2017 by fr1kin */ -public abstract class AbstractCmdBuilder { - @Nullable protected final IParentCmd parent; - - protected String name; - protected String description; - - protected List aliases = Lists.newArrayList(); - - protected List> arguments = Lists.newArrayList(); - protected List> options = Lists.newArrayList(); - - protected Set> flags = Sets.newHashSet(); - protected Set callbacks = Sets.newHashSet(); - - public AbstractCmdBuilder(@Nullable IParentCmd parent) { - this.parent = parent; - } - - protected R getThis() { - return (R) this; - } - - /** - * Set the name of the command. - * - * @param name commands name - * @return this - */ - public R name(String name) { - this.name = name; - return getThis(); - } - - /** - * Set the description for the command - * - * @param description describes what the command does - * @return this - */ - public R description(String description) { - this.description = description; - return getThis(); - } - - /** - * Sets aliases for the command that can be alternatively used - * - * @param aliases alternative names for this command - * @return this - */ - public R aliases(Collection aliases) { - this.aliases.addAll(aliases); - return getThis(); - } - - public R aliases(String... aliases) { - return aliases(Arrays.asList(aliases)); - } - - /** - * Adds argument by providing a builder, which returns the argument object to use - * - * @param function provides an argument builder, returns an argument - * @param type - * @return this - */ - public R argument(Function, IArg> function) { - this.arguments.add(function.apply(new ArgBuilder())); - return getThis(); - } - - /** - * Adds arguments with varargs - * - * @param arguments argument(s) to add - * @return this - */ - public R arguments(IArg... arguments) { - this.arguments.addAll(Arrays.asList(arguments)); - return getThis(); - } - - /** - * Add option via function that provides a builder. - * - * @param function provides a builder, returns the object to add - * @return this - */ - public R option(Function function) { - this.options.add(function.apply(new Object())); - return getThis(); - } - - /** - * Add varargs of options - * - * @param options varargs of options - * @return this - */ - public R options(Collection> options) { - this.options.addAll(options); - return getThis(); - } - - public R options(IOption... options) { - return options(Arrays.asList(options)); - } - - public R flags(Collection> flags) { - this.flags.addAll(flags); - return getThis(); - } - - public R flags(Enum[] flags) { - return flags(Arrays.asList(flags)); - } - - public R flag(Enum flag) { - return flags(Collections.singleton(flag)); - } - - public R callbacks(Collection flags) { - this.callbacks.addAll(flags); - return getThis(); - } - - public R callbacks(ICmdCallback[] flags) { - return callbacks(Arrays.asList(flags)); - } - - public R callback(ICmdCallback flag) { - return callbacks(Collections.singleton(flag)); - } - - public abstract V build(); -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/CmdBuilders.java b/src/main/java/com/matt/forgehax/util/command/v2/CmdBuilders.java deleted file mode 100644 index afc341ba9..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/CmdBuilders.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import javax.annotation.Nullable; - -public class CmdBuilders { - private static final CmdBuilders INSTANCE = new CmdBuilders(); - - public static CmdBuilders getInstance() { - return INSTANCE; - } - - @Nullable private final IParentCmd parent; - - public CmdBuilders(IParentCmd parent) { - this.parent = parent; - } - - public CmdBuilders() { - this(null); - } - - public ParentCmdBuilder newParent() { - return new ParentCmdBuilder(parent); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/CmdHelper.java b/src/main/java/com/matt/forgehax/util/command/v2/CmdHelper.java deleted file mode 100644 index 61b4fcaee..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/CmdHelper.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import com.matt.forgehax.util.command.v2.argument.IArg; -import com.matt.forgehax.util.command.v2.callback.ICmdCallback; -import com.matt.forgehax.util.command.v2.exception.CmdMissingArgumentException; -import com.matt.forgehax.util.command.v2.flag.ICmdFlag; -import java.util.*; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import joptsimple.internal.Strings; -import org.apache.commons.lang3.StringUtils; - -/** Created on 1/30/2018 by fr1kin */ -public class CmdHelper { - private static final Pattern VALID_CHARACTERS_PATTERN = Pattern.compile("^[A-Za-z0-9-_]+$"); - - public static void requireArgument(String[] args, ICmd cmd, IArg arg) - throws CmdMissingArgumentException { - if (args.length == 0 || Strings.isNullOrEmpty(CmdHelper.firstOf(args))) - throw new CmdMissingArgumentException(cmd, arg); - } - - public static boolean isNameValid(String name) { - return VALID_CHARACTERS_PATTERN.matcher(name).matches(); - } - - public static String getBestMatchingName(ICmd command, String name, String defaultTo) { - return getSortedMatching(command.getAllNames(), name, true) - .stream() - .findFirst() - .orElse(defaultTo); - } - - public static String getBestMatchingName(ICmd command, String name) { - return getBestMatchingName(command, name, null); - } - - public static List getSortedMatching( - Collection strings, String match, final boolean ignoreCase) { - Objects.requireNonNull(match); - final String m = ignoreCase ? match.toLowerCase() : match; - return strings - .stream() - .filter(str -> ignoreCase ? str.toLowerCase().startsWith(m) : str.startsWith(m)) - .sorted( - (str1, str2) -> { - String s1 = ignoreCase ? str1.toLowerCase() : str1; - String s2 = ignoreCase ? str2.toLowerCase() : str2; - int d1 = StringUtils.getLevenshteinDistance(s1, m); - int d2 = StringUtils.getLevenshteinDistance(s2, m); - int diff = d1 - d2; - return diff == 0 ? s1.compareTo(s2) : diff; - }) - .collect(Collectors.toList()); - } - - public static T registerAll( - T cmd, Iterable callbacks, Iterable> flags) { - callbacks.forEach(cmd::addCallback); - flags.forEach(cmd::addFlag); - return cmd; - } - - public static int compare(ICmd cmd1, ICmd cmd2) { - Objects.requireNonNull(cmd1); - Objects.requireNonNull(cmd2); - return Objects.compare(cmd1, cmd2, ICmd::compareTo); - } - - public static String firstOf(String[] args, String defaultTo) { - return args.length > 0 ? args[0] : defaultTo; - } - - public static String firstOf(String[] args) { - return firstOf(args, null); - } - - public static String lastOf(String[] args, String defaultTo) { - return args.length > 0 ? args[args.length - 1] : defaultTo; - } - - public static String lastOf(String[] args) { - return lastOf(args, null); - } - - public static String[] nextOf(String[] args) { - return args.length > 0 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]; - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/ICmd.java b/src/main/java/com/matt/forgehax/util/command/v2/ICmd.java deleted file mode 100644 index cd67a7857..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/ICmd.java +++ /dev/null @@ -1,216 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import com.google.common.collect.ImmutableList; -import com.matt.forgehax.util.command.v2.argument.IArg; -import com.matt.forgehax.util.command.v2.argument.IOption; -import com.matt.forgehax.util.command.v2.callback.ICmdCallback; -import com.matt.forgehax.util.command.v2.exception.CmdAmbiguousException; -import com.matt.forgehax.util.command.v2.exception.CmdMissingArgumentException; -import com.matt.forgehax.util.command.v2.exception.CmdUnknownException; -import com.matt.forgehax.util.command.v2.flag.ICmdFlag; -import com.matt.forgehax.util.serialization.ISerializableJson; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** Created on 12/25/2017 by fr1kin */ - -/* - Features: - Name Immutable Name of the command - Description Immutable Description of the command - Aliases Immutable Alternative names of the command - Parent Immutable Parent of the command - Arguments Immutable Command arguments (if any) - Options Immutable Command options (if any) - Flags Mutable Command flags (if any) - Callbacks Mutable Command callback -*/ -public interface ICmd extends ISerializableJson, Comparable { - /** - * The formal name for this command - * - * @return formal name - */ - String getName(); - - String getAbsoluteName(); - - /** - * Alternative names for this command. - * - * @return list of alternative names or an empty array list if none exist. - */ - @Nonnull - Collection getAliases(); - - /** - * Returns names and aliases - * - * @return list of names and aliases - */ - default Collection getAllNames() { - return getAliases().isEmpty() - ? Collections.singleton(getName()) - : ImmutableList.builder().add(getName()).addAll(getAliases()).build(); - } - - /** - * Check if the string matches this commands name - * - * @param name - * @return - */ - default boolean isNameMatching(String name) { - return getName().equalsIgnoreCase(name); - } - - default boolean isNameMatching(ICmd other) { - return isNameMatching(other.getName()); - } - - default boolean isAbsoluteNameMatching(String name) { - return getAbsoluteName().equalsIgnoreCase(name); - } - - default boolean isAbsoluteNameMatching(ICmd other) { - return isAbsoluteNameMatching(other.getAbsoluteName()); - } - - /** - * If this command can be identified by the given name. Command names are case insensitive. - * - * @param name - * @return - */ - default boolean isIdentifiableAs(final String name) { - return CmdHelper.isNameValid(name) - && (isNameMatching(name) - || isAbsoluteNameMatching(name) - || getAliases().stream().anyMatch(alias -> alias.equalsIgnoreCase(name))); - } - - /** - * Check if these two commands have conflicting naming schemes - * - * @param other - * @return - */ - default boolean isConflictingWith(ICmd other) { - return isNameMatching(other.getName()); - } - - /** - * Commands description - * - * @return description - */ - String getDescription(); - - /** - * The parent of this command - * - * @return null if no parent - */ - @Nullable - IParentCmd getParent(); - - List> getArguments(); - - default IArg getArgument(int index, IArg defaultTo) { - return (index > -1 && index < getArgumentCount()) ? getArguments().get(index) : defaultTo; - } - - default IArg getArgument(int index) { - return getArgument(index, null); - } - - default int getArgumentCount() { - return getArguments().size(); - } - - default int getRequiredArgumentCount() { - return (int) getArguments().stream().filter(IArg::isRequired).count(); - } - - default int getOptionalArgumentCount() { - return (int) getArguments().stream().filter(arg -> !arg.isRequired()).count(); - } - - List> getOptions(); - - default IOption getOption(String name, IOption defaultTo) { - return getOptions().stream().filter(o -> o.contains(name)).findFirst().orElse(defaultTo); - } - - @Nullable - default IOption getOption(String name) { - return getOption(name, null); - } - - String getHelpText(IHelpTextFormatter formatter); - - String getSyntaxHelpText(); - - /** - * Array of flags designated to this command - * - * @return empty list if command has no flags - */ - Collection> getFlags(); - - /** - * Adds a flag to the command - * - * @param flag flag - * @return true if added, otherwise false - */ - boolean addFlag(Enum flag); - - /** - * Removes a flag to the command - * - * @param flag flag - * @return true if removed, otherwise false - */ - boolean removeFlag(Enum flag); - - /** - * Checks if the command contains the flag - * - * @param flag flag - * @return true if contains, otherwise false - */ - boolean containsFlag(Enum flag); - - /** Remove all the flags this command has */ - void clearFlags(); - - @Nonnull - Collection getCallbacks(); - - @Nonnull - Collection getCallbacksOfType(Class clazz); - - boolean addCallback(ICmdCallback callback); - - boolean removeCallback(ICmdCallback callback); - - /** - * Process the command - * - * @param args command arguments - * @return true if the command was processed successfully - * @throws CmdMissingArgumentException if there are many missing arguments - */ - boolean process(String[] args) - throws CmdUnknownException, CmdMissingArgumentException, CmdAmbiguousException; - - @Override - default String getUniqueHeader() { - return getAbsoluteName(); // no not overload this, will experience weird results when - // serializing - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/IHelpTextFormatter.java b/src/main/java/com/matt/forgehax/util/command/v2/IHelpTextFormatter.java deleted file mode 100644 index d14fdbdac..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/IHelpTextFormatter.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -/** Created on 12/25/2017 by fr1kin */ -public interface IHelpTextFormatter { - void format(); -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/IParentCmd.java b/src/main/java/com/matt/forgehax/util/command/v2/IParentCmd.java deleted file mode 100644 index 3438e849a..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/IParentCmd.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import java.util.Collection; - -/** Created on 12/25/2017 by fr1kin */ -public interface IParentCmd extends ICmd { - Collection getChildren(); - - Collection getChildrenDeep(); - - boolean addChild(ICmd command); - - boolean removeChild(ICmd command); - - CmdBuilders makeChild(); - - ICmd findChild(final String name); -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/ParentCmd.java b/src/main/java/com/matt/forgehax/util/command/v2/ParentCmd.java deleted file mode 100644 index eddd6740e..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/ParentCmd.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.command.v2.argument.*; -import com.matt.forgehax.util.command.v2.converter.ConverterFactory; -import com.matt.forgehax.util.command.v2.exception.CmdAmbiguousException; -import com.matt.forgehax.util.command.v2.exception.CmdMissingArgumentException; -import com.matt.forgehax.util.command.v2.exception.CmdRuntimeException; -import com.matt.forgehax.util.command.v2.exception.CmdUnknownException; -import com.matt.forgehax.util.command.v2.serializers.CmdChildrenSerializer; -import com.matt.forgehax.util.command.v2.serializers.CmdFlagSerializer; -import com.matt.forgehax.util.serialization.Serializers; -import java.io.IOException; -import java.util.*; -import java.util.stream.Collectors; -import javax.annotation.Nullable; -import org.apache.commons.lang3.StringUtils; - -/** Created on 12/26/2017 by fr1kin */ -public class ParentCmd extends AbstractCmd implements IParentCmd { - private static final Collection> ARGUMENTS = - Collections.singleton( - new ArgBuilder() - .description("child command") - .shortDescription("cmd") - .required() - .converter( - ConverterFactory.newBuilder() - .type(ICmd.class) - .label("cmd") - .comparator(CmdHelper::compare) - .valuesOf( - (input, stream) -> - stream - .filter( - cmd -> - cmd.getName() - .toLowerCase() - .startsWith(input.toLowerCase())) - .sorted( - Comparator.comparing( - cmd -> cmd.getName().toLowerCase(), - Comparator.comparingInt( - name -> - StringUtils.getLevenshteinDistance( - name, input)) - .thenComparing(String::compareToIgnoreCase)))) - .toString(ICmd::getName) - .serializer(Serializers.nullSerializer()) - .build()) - .build()); - - private final List children = Lists.newCopyOnWriteArrayList(); - - public ParentCmd( - String name, - @Nullable Collection aliases, - String description, - @Nullable IParentCmd parent, - @Nullable Collection> options) - throws CmdRuntimeException.CreationFailure { - super(name, aliases, description, parent, ARGUMENTS, options); - } - - @SuppressWarnings("unchecked") - protected IArg getChildrenArgument() { - return (IArg) getArgument(0); - } - - protected void checkConflictingChildren(ICmd command) { - if (children.stream().anyMatch(command::isConflictingWith)) - throw new CmdRuntimeException("tried to add command that conflicts with another child"); - } - - @Override - public Collection getChildren() { - return ImmutableList.copyOf(children); - } - - @Override - public Collection getChildrenDeep() { - return children - .stream() - .collect( - Lists::newArrayList, - (l, e) -> { - l.add(e); - if (e instanceof IParentCmd) l.addAll(((IParentCmd) e).getChildrenDeep()); - }, - List::addAll); - } - - @Override - public boolean addChild(ICmd command) { - checkConflictingChildren(command); - return children.add(command); - } - - @Override - public boolean removeChild(ICmd command) { - return children.remove(command); - } - - @Override - public CmdBuilders makeChild() { - return new CmdBuilders(this); - } - - @Override - public ICmd findChild(final String name) { - return children - .stream() - .filter(cmd -> cmd.isNameMatching(name) || cmd.isAbsoluteNameMatching(name)) - .findFirst() - .orElse(null); - } - - @Override - public boolean process(String[] args) - throws CmdUnknownException, CmdMissingArgumentException, CmdAmbiguousException { - CmdHelper.requireArgument(args, this, getChildrenArgument()); - Parser parser = new Parser<>(this, args); - - @SuppressWarnings("unchecked") - ArgMap child = (ArgMap) parser.getArgument(0).get(); - - List matching = child.values(0, children.stream()).collect(Collectors.toList()); - - if (matching.isEmpty()) throw new CmdUnknownException(this, child.getInput(0)); - else if (matching.size() > 1) - throw new CmdAmbiguousException(this, child.getInput(0), matching); - - return matching.get(0).process(parser.getRemaining()); - } - - @Override - public void serialize(JsonWriter writer) throws IOException { - writer.beginObject(); // { - - writer.name("flags"); - CmdFlagSerializer.getInstance().serialize(this, writer); - - writer.name("children"); - CmdChildrenSerializer.getInstance().serialize(this, writer); - - writer.endObject(); // } - } - - @Override - public void deserialize(JsonReader reader) throws IOException { - reader.beginObject(); // { - - while (reader.hasNext()) { - switch (reader.nextName()) { - case "flags": - { - CmdFlagSerializer.getInstance().deserialize(this, reader); - break; - } - case "children": - { - CmdChildrenSerializer.getInstance().deserialize(this, reader); - break; - } - default: - reader.skipValue(); - } - } - - reader.endObject(); // } - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/ParentCmdBuilder.java b/src/main/java/com/matt/forgehax/util/command/v2/ParentCmdBuilder.java deleted file mode 100644 index 88b12b48c..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/ParentCmdBuilder.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import javax.annotation.Nullable; - -public class ParentCmdBuilder extends AbstractCmdBuilder { - public ParentCmdBuilder(@Nullable IParentCmd parent) { - super(parent); - } - - @Override - public IParentCmd build() { - return CmdHelper.registerAll( - new ParentCmd(name, aliases, description, parent, options), callbacks, flags); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/Parser.java b/src/main/java/com/matt/forgehax/util/command/v2/Parser.java deleted file mode 100644 index bf15ebcaf..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/Parser.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.matt.forgehax.util.command.v2; - -import com.google.common.collect.Lists; -import com.matt.forgehax.util.ArrayHelper; -import com.matt.forgehax.util.command.v2.argument.*; -import com.matt.forgehax.util.command.v2.exception.CmdMissingArgumentException; -import java.util.*; -import java.util.stream.Collectors; - -/** Created on 4/18/2018 by fr1kin */ -public class Parser { - private final List> arguments; - private final List> options; - private final List remaining = Lists.newArrayList(); - - protected Parser(E command, String[] args) throws CmdMissingArgumentException { - this.arguments = - command.getArguments().stream().map(ArgBuilder::newArgMap).collect(Collectors.toList()); - - this.options = - command.getOptions().stream().map(OptionBuilder::newOptionMap).collect(Collectors.toList()); - - boolean stopOptions = false; - - int index = 0; - int argumentIndex = 0; - - for (; index < args.length; ++index) { - String next = args[index]; - - if (!stopOptions && isOption(next)) { - Extract parse = new Extract(next); - - // look for the option - Optional> opt = getOption(parse.name); - - if (opt.isPresent()) { // we have a match - OptionMap option = opt.get(); - if (!option.isFlag()) { - if (parse.value != null) { - option.withInput(parse.value); // already provided the argument - } else if (ArrayHelper.isInRange(args, index + 1)) { // we have another argument - String arg = args[++index]; // get next arg - - if (isOption(arg)) { - Extract p = new Extract(arg); - if (!getOption(p.name).isPresent()) { - option.withInput( - arg); // since there is no matching option, assume this was intended to be an - // argument - } else { - if (option.isRequired()) - throw new CmdMissingArgumentException(command, option); // no argument provided - else if (option.isOptional()) { - option.withDefaultValue(); // append the default value - --index; // go back to process the option we jumped to properly - } - } - } else { - option.withInput(arg); // normal value - } - } else { - if (option.isRequired()) - throw new CmdMissingArgumentException(command, option); // no argument provided - else if (option.isOptional()) { - option.withDefaultValue(); // use default argument since none was provided - } - } - } else { - option.withDefaultValue(); - } - continue; // stop - } - - // since this isn't an option, it will be interpreted as an argument - } - - if (argumentIndex > arguments.size() - 1) { - remaining.add(next); - continue; - } - - arguments.get(argumentIndex).withInput(next); - - ++argumentIndex; - stopOptions = true; // do not process anymore options - } - - for (int i = argumentIndex; i < arguments.size(); ++i) { - ArgMap arg = arguments.get(i); - if (arg.isRequired()) throw new CmdMissingArgumentException(command, arg); - else arg.withDefaultValue(); - } - } - - public Optional> getArgument(int index) { - return index > -1 && index < arguments.size() - ? Optional.of(arguments.get(index)) - : Optional.empty(); - } - - public Optional> getOption(String name) { - return options - .stream() - .filter(option -> option.contains(name)) - .findFirst() - .map(o -> (OptionMap) o); - } - - public String[] getRemaining() { - return remaining.toArray(new String[0]); - } - - // - // - // - - private static boolean isLongToken(String text) { - return text.startsWith("--") && text.length() > "--".length(); - } - - private static boolean isShortToken(String text) { - return text.startsWith("-") && !text.startsWith("--") && text.length() > "-".length(); - } - - private static boolean isOption(String text) { - return isLongToken(text) || isShortToken(text); - } - - private static String extractOption(String text) { - return isLongToken(text) - ? text.substring(2) - : text.substring(1); // remove the -- or - from the option - } - - private static String[] parseOption(String text) { - String name = extractOption(text); // remove the -- or - from the option - String arg = null; // possible argument - - // can be formatted like option=argument - if (name.contains("=")) { - String[] ss = name.split("="); - name = ss[0]; - arg = ss[1]; - } - - return new String[] {name, arg}; - } - - static final class Extract { - String name; - String value; - - Extract(String from) { - String[] ss = parseOption(from); - this.name = ss[0]; - this.value = ss[1]; - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgBuilder.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgBuilder.java deleted file mode 100644 index ec073816e..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgBuilder.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.google.common.base.MoreObjects; -import com.matt.forgehax.util.command.v2.converter.Converters; -import com.matt.forgehax.util.command.v2.converter.IConverter; - -public class ArgBuilder { - public static ArgMap newArgMap(IArg parent) { - return new ArgMap<>(parent); - } - - // - // - // - - private String _description; - private String _shortDescription; - private boolean _required; - private E _defaultValue; - private IConverter _converter; - - public ArgBuilder() {} - - ArgBuilder set_converter(IConverter converter) { - this._converter = MoreObjects.firstNonNull(this._converter, converter); - return this; - } - - /** - * Description for this argument. Preferably with details. Not required. If not provided, it will - * use the short description. - * - * @param description description of this argument - * @return this - */ - public ArgBuilder description(String description) { - this._description = description; - this._shortDescription = MoreObjects.firstNonNull(_shortDescription, description); - return this; - } - - /** - * A shorter description that can be used in the syntax helper. Not required. If not provided, it - * will use the description. - * - * @param shortDescription The shortest possible description for this argument. - * @return this - */ - public ArgBuilder shortDescription(String shortDescription) { - this._shortDescription = shortDescription; - this._description = MoreObjects.firstNonNull(_description, shortDescription); - return this; - } - - /** - * Flag this argument as required - * - * @return this - */ - public ArgBuilder required() { - this._required = true; - return this; - } - - /** - * Flag this argument as optional - * - * @return this - */ - public ArgBuilder optional() { - this._required = false; - return this; - } - - /** - * The default value for this argument. Not required and can be null. Will automatically set the - * converter if that has not been done already. - * - * @param defaultValue default value - * @return this - */ - public ArgBuilder defaultValue(E defaultValue) { - this._defaultValue = defaultValue; - return set_converter(Converters.get(defaultValue).orElse(null)); - } - - /** - * The converter used to change this value to and from a string. - * - * @param converter converter instance - * @return this - */ - public ArgBuilder converter(IConverter converter) { - this._converter = converter; - return this; - } - - /** - * Build the argument. - * - * @return new argument instance - */ - public IArg build() { - return new BaseArg<>(_description, _shortDescription, _required, _defaultValue, _converter); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgHelper.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgHelper.java deleted file mode 100644 index b842f7ff7..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgHelper.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.matt.forgehax.util.command.v2.converter.DefaultConverters; -import java.util.Collection; - -/** Created on 1/30/2018 by fr1kin */ -public class ArgHelper { - private static final IArg ARGUMENT_EMPTY = - new ArgBuilder() - .description("empty") - .shortDescription("empty") - .converter(DefaultConverters.EMPTY) - .optional() - .build(); - - /** - * Checks the required/non-required argument order to ensure that required argument(s) are not put - * after a non-required argument. - * - * @param arguments Array of arguments - * @return true if the order is wrong - */ - public static boolean isInvalidArgumentOrder(Collection> arguments) { - boolean allowed = true; - for (IArg arg : arguments) { - if (!arg.isRequired()) - allowed = false; // required arguments are not allowed after non-required arguments now - else if (!allowed) // this is a required argument, if allowed=false then you have tried to - // added a required argument after a non-required argument - return true; - } - return false; - } - - public static IArg emptyArgument() { - return (IArg) ARGUMENT_EMPTY; - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgMap.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgMap.java deleted file mode 100644 index 1f8ac1dfc..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/ArgMap.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.google.common.collect.Lists; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.command.v2.converter.exceptions.StringConversionException; -import com.matt.forgehax.util.command.v2.converter.exceptions.ValueParseException; -import java.io.IOException; -import java.util.*; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -public class ArgMap implements IArg, ValueMap { - private final IArg parent; - private final List inputs = Lists.newArrayList(); - - ArgMap(IArg parent) { - Objects.requireNonNull(parent); - this.parent = parent; - } - - @Override - public String getDescription() { - return parent.getDescription(); - } - - @Override - public String getShortDescription() { - return parent.getShortDescription(); - } - - @Override - public boolean isRequired() { - return parent.isRequired(); - } - - @Override - public boolean isOptional() { - return parent.isOptional(); - } - - @Nullable - @Override - public E getDefaultValue() { - return parent.getDefaultValue(); - } - - @Override - public Class getType() { - return parent.getType(); - } - - @Override - public String getLabel() { - return parent.getLabel(); - } - - @Override - public String toString(E value) throws StringConversionException { - return parent.toString(value); - } - - @Override - public E valueOf(String input, Stream stream) throws ValueParseException { - return parent.valueOf(input, stream); - } - - @Override - public Stream valuesOf(String input, Stream stream) throws ValueParseException { - return parent.valuesOf(input, stream); - } - - @Override - public void serialize(JsonWriter writer, @Nullable E instance) throws IOException { - parent.serialize(writer, instance); - } - - @Nullable - @Override - public E deserialize(JsonReader reader) throws IOException { - return parent.deserialize(reader); - } - - @Override - public int compare(E o1, E o2) { - return parent.compare(o1, o2); - } - - @Override - public Stream values(int index, Stream filter) { - return valuesOf(inputs.get(index), filter); - } - - @Override - public Collection getInputs() { - return inputs; - } - - @Override - public int getInputSize() { - return inputs.size(); - } - - @Override - public void withInputs(Iterable inputs) { - for (String s : inputs) this.inputs.add(s); - } - - @Override - public void withDefaultValue() { - withInput(toString(getDefaultValue())); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/BaseArg.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/BaseArg.java deleted file mode 100644 index e058c5177..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/BaseArg.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.command.v2.converter.IConverter; -import com.matt.forgehax.util.command.v2.converter.exceptions.StringConversionException; -import com.matt.forgehax.util.command.v2.converter.exceptions.ValueParseException; -import java.io.IOException; -import java.util.Objects; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -public class BaseArg implements IArg { - private final String description; - private final String shortDescription; - private final boolean required; - private final E defaultValue; - private final IConverter converter; - - public BaseArg( - String description, - String shortDescription, - boolean required, - @Nullable E defaultValue, - IConverter converter) { - Objects.requireNonNull(description); - Objects.requireNonNull(shortDescription); - Objects.requireNonNull(converter); - this.description = description; - this.shortDescription = shortDescription; - this.required = required; - this.defaultValue = defaultValue; - this.converter = converter; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public String getShortDescription() { - return shortDescription; - } - - @Override - public boolean isRequired() { - return required; - } - - @Override - public boolean isOptional() { - return !isRequired(); - } - - @Nullable - @Override - public E getDefaultValue() { - return defaultValue; - } - - @Override - public Class getType() { - return converter.getType(); - } - - @Nullable - @Override - public Class getPrimitiveType() { - return converter.getPrimitiveType(); - } - - @Override - public String getLabel() { - return converter.getLabel(); - } - - @Override - public String toString(E value) throws StringConversionException { - return converter.toString(value); - } - - @Nullable - @Override - public E valueOf(String input, Stream stream) throws ValueParseException { - return converter.valueOf(input, stream); - } - - @Override - public Stream valuesOf(String input, Stream stream) throws ValueParseException { - return converter.valuesOf(input, stream); - } - - @Override - public int compare(E o1, E o2) { - return converter.compare(o1, o2); - } - - @Override - public void serialize(JsonWriter writer, @Nullable E instance) throws IOException { - converter.serialize(writer, instance); - } - - @Nullable - @Override - public E deserialize(JsonReader reader) throws IOException { - return converter.deserialize(reader); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/BaseOption.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/BaseOption.java deleted file mode 100644 index 3fb8fd847..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/BaseOption.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.google.common.collect.ImmutableList; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.command.v2.converter.exceptions.StringConversionException; -import com.matt.forgehax.util.command.v2.converter.exceptions.ValueParseException; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -public class BaseOption implements IOption { - private final List names; - private final boolean flag; - private final String description; - private final IArg argument; - - public BaseOption(Collection names, boolean flag, String description, IArg argument) { - Objects.requireNonNull(names); - Objects.requireNonNull(description); - Objects.requireNonNull(argument); - this.names = ImmutableList.copyOf(names); - this.flag = flag; - this.description = description; - this.argument = argument; - } - - @Override - public Collection getNames() { - return names; - } - - @Override - public String getOptionDescription() { - return description; - } - - @Override - public String getDescription() { - return argument.getDescription(); - } - - @Override - public String getShortDescription() { - return argument.getShortDescription(); - } - - @Override - public boolean isRequired() { - return !flag && argument.isRequired(); - } - - @Override - public boolean isOptional() { - return !flag && argument.isOptional(); - } - - @Nullable - @Override - public E getDefaultValue() { - return argument.getDefaultValue(); - } - - @Override - public Class getType() { - return argument.getType(); - } - - @Override - public String getLabel() { - return argument.getLabel(); - } - - @Override - public String toString(E value) throws StringConversionException { - return argument.toString(value); - } - - @Override - public E valueOf(String input, Stream stream) throws ValueParseException { - return argument.valueOf(input, stream); - } - - @Override - public Stream valuesOf(String input, Stream stream) throws ValueParseException { - return argument.valuesOf(input, stream); - } - - @Override - public void serialize(JsonWriter writer, @Nullable E instance) throws IOException { - argument.serialize(writer, instance); - } - - @Nullable - @Override - public E deserialize(JsonReader reader) throws IOException { - return argument.deserialize(reader); - } - - @Override - public int compare(E o1, E o2) { - return argument.compare(o1, o2); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/IArg.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/IArg.java deleted file mode 100644 index df79a72b0..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/IArg.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.matt.forgehax.util.command.v2.converter.IConverter; -import javax.annotation.Nullable; - -public interface IArg extends IConverter { - /** - * Description of the command - * - * @return description - */ - String getDescription(); - - /** - * A shorter description (one word) - * - * @return short desc - */ - String getShortDescription(); - - /** - * If the argument is required - * - * @return required - */ - boolean isRequired(); - - /** - * If the argument is optional - * - * @return optional - */ - boolean isOptional(); - - /** - * The default value for this argument - * - * @return default value - */ - @Nullable - E getDefaultValue(); -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/IOption.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/IOption.java deleted file mode 100644 index 82fb61d3b..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/IOption.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.matt.forgehax.util.CaseSensitive; -import com.matt.forgehax.util.SafeConverter; -import java.util.Arrays; -import java.util.Collection; -import javax.annotation.Nullable; - -public interface IOption extends IArg { - /** - * Get a list of names for this option - * - * @return collection of names representing this option - */ - Collection getNames(); - - /** - * Gets the description for the option - * - * @return option description - */ - String getOptionDescription(); - - /** - * Gets the longest name for this option - * - * @return longest name - */ - @Nullable - default String getLongName() { - return getNames() - .stream() - .filter(name -> name.length() > 1) - .min(String::compareTo) - .orElse(null); - } - - /** - * Gets the short name for this option - * - * @return character representing the short name - */ - default Character getShortName() { - return getNames() - .stream() - .filter(name -> name.length() == 1) - .map(SafeConverter::toCharacter) - .min(Character::compare) - .orElse(Character.MIN_VALUE); - } - - /** - * If this option has no argument, then it will be a flag - * - * @return false if option is not required or optional - */ - default boolean isFlag() { - return !isRequired() && !isOptional(); - } - - default boolean contains(@CaseSensitive final Collection names) { - return getNames().stream().anyMatch(name -> names.stream().anyMatch(name::equals)); - } - - default boolean contains(@CaseSensitive final String... names) { - return contains(Arrays.asList(names)); - } - - default boolean matches(IOption option) { - return contains(option.getNames()); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/OptionBuilder.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/OptionBuilder.java deleted file mode 100644 index 60f78be6f..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/OptionBuilder.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.google.common.base.MoreObjects; -import com.google.common.collect.Sets; -import java.util.Arrays; -import java.util.Set; - -public class OptionBuilder { - public static OptionMap newOptionMap(IOption parent) { - return new OptionMap<>(parent); - } - - // - // - // - - private Set _names = Sets.newLinkedHashSet(); - private boolean _flag; - private String _description; - private IArg _argument; - - public OptionBuilder names(String... names) { - _names.addAll(Arrays.asList(names)); - return this; - } - - public OptionBuilder name(String name) { - return names(name); - } - - /** - * Description for this option. Preferably with details. Not required. If not provided, it will - * use the short description. - * - * @param description description of this option - * @return this - */ - public OptionBuilder description(String description) { - this._description = description; - return this; - } - - public OptionBuilder argument(IArg argument) { - this._argument = argument; - return this; - } - - public IOption build() { - return new BaseOption<>( - _names, - _argument == null, - _description, - MoreObjects.firstNonNull(_argument, ArgHelper.emptyArgument())); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/OptionMap.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/OptionMap.java deleted file mode 100644 index 17b0511c5..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/OptionMap.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import com.google.common.collect.Lists; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.command.v2.converter.exceptions.StringConversionException; -import com.matt.forgehax.util.command.v2.converter.exceptions.ValueParseException; -import java.io.IOException; -import java.util.*; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -public class OptionMap implements IOption, ValueMap { - private final IOption parent; - private final List inputs = Lists.newArrayList(); - - OptionMap(IOption parent) { - Objects.requireNonNull(parent); - this.parent = parent; - } - - @Override - public Collection getNames() { - return parent.getNames(); - } - - @Override - public String getOptionDescription() { - return parent.getOptionDescription(); - } - - @Override - public String getDescription() { - return parent.getDescription(); - } - - @Override - public String getShortDescription() { - return parent.getShortDescription(); - } - - @Override - public boolean isRequired() { - return parent.isRequired(); - } - - @Override - public boolean isOptional() { - return parent.isOptional(); - } - - @Nullable - @Override - public E getDefaultValue() { - return parent.getDefaultValue(); - } - - @Override - public Class getType() { - return parent.getType(); - } - - @Override - public String getLabel() { - return parent.getLabel(); - } - - @Override - public String toString(E value) throws StringConversionException { - return parent.toString(value); - } - - @Override - public E valueOf(String input, Stream stream) throws ValueParseException { - return parent.valueOf(input, stream); - } - - @Override - public Stream valuesOf(String input, Stream stream) throws ValueParseException { - return parent.valuesOf(input, stream); - } - - @Override - public void serialize(JsonWriter writer, @Nullable E instance) throws IOException { - parent.serialize(writer, instance); - } - - @Nullable - @Override - public E deserialize(JsonReader reader) throws IOException { - return parent.deserialize(reader); - } - - @Override - public int compare(E o1, E o2) { - return parent.compare(o1, o2); - } - - @Override - public Stream values(int index, Stream filter) { - return valuesOf(inputs.get(index), filter); - } - - @Override - public Collection getInputs() { - return inputs; - } - - @Override - public int getInputSize() { - return inputs.size(); - } - - @Override - public void withInputs(Iterable inputs) { - for (String s : inputs) this.inputs.add(s); - } - - @Override - public void withDefaultValue() { - withInput(toString(getDefaultValue())); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/argument/ValueMap.java b/src/main/java/com/matt/forgehax/util/command/v2/argument/ValueMap.java deleted file mode 100644 index 5ec12f965..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/argument/ValueMap.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.matt.forgehax.util.command.v2.argument; - -import java.util.Collection; -import java.util.Collections; -import java.util.Objects; -import java.util.stream.Stream; - -public interface ValueMap { - /** - * Get a stream of values from the input map with the given filter - * - * @param filter filter to apply - * @return stream of filtered values - */ - Stream values(int index, Stream filter); - - /** - * Get a stream of values from the input map. - * - * @return stream of values - */ - default Stream values(int index) { - return values(index, Stream.empty()); - } - - /** - * Get the most accurate value from a given filter - * - * @param filter filter for the data - * @return most accurate value from the input - */ - default E value(int index, Stream filter) { - return values(index, filter).findFirst().orElse(null); - } - - /** - * Get the most accurate value. - * - * @return most accurate value. - */ - default E value(int index) { - return value(index, Stream.empty()); - } - - default Stream firstValues(Stream filter) { - return values(0, filter); - } - - default Stream firstValues() { - return firstValues(Stream.empty()); - } - - default E firstValue(Stream filter) { - return firstValues(filter).findFirst().orElse(null); - } - - default E firstValue() { - return firstValue(Stream.empty()); - } - - /** - * Gets a collection of current inputs inserted into this map - * - * @return collection of inputs - */ - Collection getInputs(); - - /** - * Get the size of the inputs collection - * - * @return number of inputs - */ - int getInputSize(); - - default String getInput(int index) { - return null; // Utils.getOrDefault(getInputs(), index, null); // TODO - } - - /** - * Adds an iterable object to the input collection - * - * @param inputs iterable object to insert - */ - void withInputs(Iterable inputs); - - /** - * Adds a single object to the input collection - * - * @param input single string object - */ - default void withInput(String input) { - Objects.requireNonNull(input); - withInputs(Collections.singleton(input)); - } - - void withDefaultValue(); -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/callback/CmdCallbacks.java b/src/main/java/com/matt/forgehax/util/command/v2/callback/CmdCallbacks.java deleted file mode 100644 index fb92165a9..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/callback/CmdCallbacks.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.matt.forgehax.util.command.v2.callback; - -public class CmdCallbacks {} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/callback/ICmdCallback.java b/src/main/java/com/matt/forgehax/util/command/v2/callback/ICmdCallback.java deleted file mode 100644 index 4c6d78fab..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/callback/ICmdCallback.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.matt.forgehax.util.command.v2.callback; - -/** Created on 12/25/2017 by fr1kin */ -public interface ICmdCallback {} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/AbstractConverter.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/AbstractConverter.java deleted file mode 100644 index b472ab564..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/AbstractConverter.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; -import java.io.IOException; -import java.util.Objects; -import javax.annotation.Nullable; - -public abstract class AbstractConverter implements IConverter { - @Override - public void serialize(JsonWriter writer, @Nullable E instance) throws IOException { - if (instance == null) writer.nullValue(); - else writer.value(toString(instance)); - } - - @Nullable - @Override - public E deserialize(JsonReader reader) throws IOException { - if (reader.peek() == JsonToken.NULL) { - reader.skipValue(); - return null; - } else return valueOf(reader.nextString()); - } - - @Override - public int hashCode() { - return Objects.hash(getType(), getPrimitiveType()); - } - - @Override - public boolean equals(Object obj) { - return this == obj - || (obj instanceof IConverter - && Objects.equals(getType(), ((IConverter) obj).getType()) - && Objects.equals(getPrimitiveType(), ((IConverter) obj).getPrimitiveType())); - } - - @Override - public String toString() { - return getLabel(); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/BaseConverter.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/BaseConverter.java deleted file mode 100644 index 458cb70cf..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/BaseConverter.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.command.v2.converter.exceptions.StringConversionException; -import com.matt.forgehax.util.command.v2.converter.exceptions.ValueParseException; -import com.matt.forgehax.util.serialization.ISerializableImmutable; -import java.io.IOException; -import java.util.Comparator; -import java.util.Objects; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -public class BaseConverter extends AbstractConverter { - private final Class type; - private final Class primitiveType; - private final String label; - private final Comparator comparator; - private final ValuesConverter valuesConverter; - private final ValueConverter valueConverter; - private final StringConverter stringConverter; - private final ISerializableImmutable serializer; - - public BaseConverter( - Class type, - Class primitiveType, - String label, - Comparator comparator, - ValuesConverter valuesConverter, - ValueConverter valueConverter, - StringConverter stringConverter, - ISerializableImmutable serializer) { - Objects.requireNonNull(type, "missing type"); - Objects.requireNonNull(label, "missing label"); - Objects.requireNonNull(comparator, "missing comparator"); - Objects.requireNonNull(valuesConverter, "missing values converter"); - Objects.requireNonNull(valueConverter, "missing value converter"); - Objects.requireNonNull(stringConverter, "missing string converter"); - Objects.requireNonNull(serializer, "missing serializer"); - - this.type = type; - this.primitiveType = primitiveType; - this.label = label; - this.comparator = comparator; - this.valuesConverter = valuesConverter; - this.valueConverter = valueConverter; - this.stringConverter = stringConverter; - this.serializer = serializer; - } - - @Override - public Class getType() { - return type; - } - - @Nullable - @Override - public Class getPrimitiveType() { - return primitiveType; - } - - @Override - public String getLabel() { - return label; - } - - @Override - public Builder builder() { - return ConverterFactory.newBuilder() // copy the values directly to reduce memory overhead - .type(type) - .primitiveType(primitiveType) - .label(label) - .comparator(comparator) - .valuesOf(valuesConverter) - .valueOf(valueConverter) - .toString(stringConverter) - .serializer(serializer); - } - - @Override - public Stream valuesOf(String input, Stream stream) throws ValueParseException { - return valuesConverter.valuesOf(input, stream); - } - - @Nullable - @Override - public E valueOf(String input, Stream stream) throws ValueParseException { - return valueConverter.valueOf(input, stream); - } - - @Override - public String toString(E value) throws StringConversionException { - return stringConverter.toString(value); - } - - @Override - public int compare(E o1, E o2) { - return comparator.compare(o1, o2); - } - - @Override - public void serialize(JsonWriter writer, E instance) throws IOException { - serializer.serialize(writer, instance); - } - - @Override - public E deserialize(JsonReader reader) throws IOException { - return serializer.deserialize(reader); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/ConverterFactory.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/ConverterFactory.java deleted file mode 100644 index 08ac19033..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/ConverterFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import java.util.Comparator; - -public class ConverterFactory { - public static IConverter.Builder newBuilder() { - return new IConverter.Builder<>(); - } - - public static Comparator newEmptyComparator() { - return ((o1, o2) -> 0); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/Converters.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/Converters.java deleted file mode 100644 index 52b1b5635..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/Converters.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import com.google.common.collect.Lists; -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -public class Converters { - private static final List> CONVERTERS = Lists.newArrayList(); - - public static void register(IConverter converter) { - Objects.requireNonNull(converter); - if (!exists(converter)) CONVERTERS.add(converter); - } - - public static void unregister(IConverter converter) { - CONVERTERS.remove(converter); - } - - public static void unregister(Class clazz) { - get(clazz).ifPresent(Converters::unregister); - } - - @SuppressWarnings("unchecked") - public static Optional> get(final Class clazz) { - Objects.requireNonNull(clazz); - return CONVERTERS - .stream() - .filter(c -> clazz.equals(c.getType()) || clazz.equals(c.getPrimitiveType())) - .findFirst() - .map(c -> (IConverter) c); - } - - @SuppressWarnings("unchecked") - public static Optional> get(T o) { - return o == null ? Optional.empty() : get((Class) o.getClass()); - } - - public static boolean exists(Class clazz) { - return get(clazz).isPresent(); - } - - public static boolean exists(IConverter converter) { - return get(converter.getType()).isPresent(); - } - - static { - register(DefaultConverters.BOOLEAN); - register(DefaultConverters.BYTE); - register(DefaultConverters.CHARACTER); - register(DefaultConverters.DOUBLE); - register(DefaultConverters.FLOAT); - register(DefaultConverters.INTEGER); - register(DefaultConverters.LONG); - register(DefaultConverters.SHORT); - register(DefaultConverters.STRING); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/DefaultConverters.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/DefaultConverters.java deleted file mode 100644 index 598558c47..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/DefaultConverters.java +++ /dev/null @@ -1,444 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import com.matt.forgehax.util.command.v2.converter.exceptions.StringConversionException; -import com.matt.forgehax.util.command.v2.converter.exceptions.ValueParseException; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -public interface DefaultConverters { - IConverter BOOLEAN = - new AbstractConverter() { - private final String ACCEPTABLE_TRUE_BOOLEAN_STRINGS = - Stream.of( - "on", "t", "tr", "tru", "true", "e", "en", "ena", "enab", "enabl", "enable", - "enabled", "1") - .collect(Collectors.joining("|")); - - @Override - public Class getType() { - return Boolean.class; - } - - @Override - public Class getPrimitiveType() { - return boolean.class; - } - - @Override - public String getLabel() { - return "boolean"; - } - - @Override - public Stream valuesOf(String input, Stream stream) - throws ValueParseException { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public Boolean valueOf(String input, Stream stream) throws ValueParseException { - ValueParseException.requireNonNull(input); - return input.toLowerCase().matches(ACCEPTABLE_TRUE_BOOLEAN_STRINGS); - } - - @Override - public String toString(Boolean value) throws StringConversionException { - return Boolean.toString(value); - } - - @Override - public int compare(Boolean o1, Boolean o2) { - return Boolean.compare(o1, o2); - } - }; - - IConverter BYTE = - new AbstractConverter() { - @Override - public Class getType() { - return Byte.class; - } - - @Nullable - @Override - public Class getPrimitiveType() { - return byte.class; - } - - @Override - public String getLabel() { - return "byte"; - } - - @Override - public Stream valuesOf(String input, Stream stream) throws ValueParseException { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public Byte valueOf(String input, Stream stream) throws ValueParseException { - ValueParseException.requireNonNull(input); - try { - return Byte.valueOf(input); - } catch (NumberFormatException e) { - throw new ValueParseException(e); - } - } - - @Override - public String toString(Byte value) throws StringConversionException { - return Byte.toString(value); - } - - @Override - public int compare(Byte o1, Byte o2) { - return Byte.compare(o1, o2); - } - }; - - IConverter CHARACTER = - new AbstractConverter() { - @Override - public Class getType() { - return Character.class; - } - - @Nullable - @Override - public Class getPrimitiveType() { - return char.class; - } - - @Override - public String getLabel() { - return "char"; - } - - @Override - public Stream valuesOf(String input, Stream stream) { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public Character valueOf(String input, Stream stream) - throws ValueParseException { - ValueParseException.requireNonNull(input); - if (input.length() != 1) - throw new ValueParseException( - new IllegalArgumentException( - "String \"" + String.valueOf(input) + "\" must be 1 character in length")); - return input.charAt(0); - } - - @Override - public String toString(Character value) throws StringConversionException { - return String.valueOf(value); - } - - @Override - public int compare(Character o1, Character o2) { - return Character.compare(o1, o2); - } - }; - - IConverter DOUBLE = - new AbstractConverter() { - @Override - public Class getType() { - return Double.class; - } - - @Nullable - @Override - public Class getPrimitiveType() { - return double.class; - } - - @Override - public String getLabel() { - return "double"; - } - - @Override - public Stream valuesOf(String input, Stream stream) { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public Double valueOf(String input, Stream stream) throws ValueParseException { - ValueParseException.requireNonNull(input); - try { - return Double.valueOf(input); - } catch (NumberFormatException e) { - throw new ValueParseException(e); - } - } - - @Override - public String toString(Double value) throws StringConversionException { - return Double.toString(value); - } - - @Override - public int compare(Double o1, Double o2) { - return Double.compare(o1, o2); - } - }; - - IConverter FLOAT = - new AbstractConverter() { - @Override - public Class getType() { - return Float.class; - } - - @Nullable - @Override - public Class getPrimitiveType() { - return float.class; - } - - @Override - public String getLabel() { - return "float"; - } - - @Override - public Stream valuesOf(String input, Stream stream) { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public Float valueOf(String input, Stream stream) throws ValueParseException { - ValueParseException.requireNonNull(input); - try { - return Float.valueOf(input); - } catch (NumberFormatException e) { - throw new ValueParseException(e); - } - } - - @Override - public String toString(Float value) throws StringConversionException { - return Float.toString(value); - } - - @Override - public int compare(Float o1, Float o2) { - return Float.compare(o1, o2); - } - }; - - IConverter INTEGER = - new AbstractConverter() { - @Override - public Class getType() { - return Integer.class; - } - - @Nullable - @Override - public Class getPrimitiveType() { - return int.class; - } - - @Override - public String getLabel() { - return "integer"; - } - - @Override - public Stream valuesOf(String input, Stream stream) - throws ValueParseException { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public Integer valueOf(String input, Stream stream) throws ValueParseException { - ValueParseException.requireNonNull(input); - try { - return Integer.valueOf(input); - } catch (NumberFormatException e) { - throw new ValueParseException(e); - } - } - - @Override - public String toString(Integer value) throws StringConversionException { - return Integer.toString(value); - } - - @Override - public int compare(Integer o1, Integer o2) { - return Integer.compare(o1, o2); - } - }; - - IConverter LONG = - new AbstractConverter() { - @Override - public Class getType() { - return Long.class; - } - - @Nullable - @Override - public Class getPrimitiveType() { - return long.class; - } - - @Override - public String getLabel() { - return "long"; - } - - @Override - public Stream valuesOf(String input, Stream stream) throws ValueParseException { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public Long valueOf(String input, Stream stream) throws ValueParseException { - ValueParseException.requireNonNull(input); - try { - return Long.valueOf(input); - } catch (NumberFormatException e) { - throw new ValueParseException(e); - } - } - - @Override - public String toString(Long value) throws StringConversionException { - return Long.toString(value); - } - - @Override - public int compare(Long o1, Long o2) { - return Long.compare(o1, o2); - } - }; - - IConverter SHORT = - new AbstractConverter() { - @Override - public Class getType() { - return Short.class; - } - - @Nullable - @Override - public Class getPrimitiveType() { - return short.class; - } - - @Override - public String getLabel() { - return "short"; - } - - @Override - public Stream valuesOf(String input, Stream stream) - throws ValueParseException { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public Short valueOf(String input, Stream stream) throws ValueParseException { - ValueParseException.requireNonNull(input); - try { - return Short.valueOf(input); - } catch (NumberFormatException e) { - throw new ValueParseException(e); - } - } - - @Override - public String toString(Short value) throws StringConversionException { - return Short.toString(value); - } - - @Override - public int compare(Short o1, Short o2) { - return Short.compare(o1, o2); - } - }; - - IConverter STRING = - new AbstractConverter() { - @Override - public Class getType() { - return String.class; - } - - @Override - public String getLabel() { - return "string"; - } - - @Override - public Stream valuesOf(String input, Stream stream) - throws ValueParseException { - return Stream.of(valueOf(input)); - } - - @Nullable - @Override - public String valueOf(String input, Stream stream) throws ValueParseException { - return String.valueOf(input); - } - - @Override - public String toString(String value) throws StringConversionException { - return String.valueOf(value); - } - - @Override - public int compare(String o1, String o2) { - return Objects.compare(o1, o2, String::compareTo); - } - }; - - IConverter EMPTY = - new AbstractConverter() { - @Override - public Class getType() { - return Object.class; - } - - @Override - public String getLabel() { - return "empty"; - } - - @Override - public String toString(Object value) throws StringConversionException { - return "empty"; - } - - @Override - public Object valueOf(String input, Stream stream) throws ValueParseException { - return null; - } - - @Override - public Stream valuesOf(String input, Stream stream) - throws ValueParseException { - return null; - } - - @Override - public int compare(Object o1, Object o2) { - return 0; - } - }; -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/IConverter.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/IConverter.java deleted file mode 100644 index 135a877d6..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/IConverter.java +++ /dev/null @@ -1,179 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import com.matt.forgehax.util.serialization.ISerializableImmutable; -import java.util.Comparator; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -public interface IConverter - extends ValuesConverter, - ValueConverter, - StringConverter, - Comparator, - ISerializableImmutable { - /** - * Class type this object is converting - * - * @return class - */ - Class getType(); - - /** - * Gets a primitive class that also represents this - * - * @return null if this is not a primitive - */ - @Nullable - default Class getPrimitiveType() { - return null; - } - - /** - * A friendly label that maybe used to describe the type - * - * @return label string - */ - String getLabel(); - - /** - * Create a builder that copies this instance. - * - * @return new builder - */ - default Builder builder() { - return ConverterFactory.newBuilder() - .type(getType()) - .primitiveType(getPrimitiveType()) - .label(getLabel()) - .comparator(this) - .valuesOf(this) - .valueOf(this) - .toString(this) - .serializer(this); - } - - final class Builder { - private Class _type; - private Class _primitiveType; - private String _label; - private Comparator _comparator; - private ValuesConverter _valuesConverter; - private ValueConverter _valueConverter; - private StringConverter _stringConverter; - private ISerializableImmutable _serializer; - - Builder() {} - - /** - * Class type this converter represents - * - * @param type class - * @return this - */ - public Builder type(Class type) { - this._type = type; - return this; - } - - /** - * Primitive class type of this converter. Only needed for Java primitives. - * - * @param primitiveType primitive class - * @return this - */ - public Builder primitiveType(Class primitiveType) { - this._primitiveType = primitiveType; - return this; - } - - /** - * A label used to identify this object - * - * @param label short name - * @return this - */ - public Builder label(String label) { - this._label = label; - return this; - } - - /** - * Comparator used to compare two values against each other - * - * @param comparator comparator - * @return this - */ - public Builder comparator(Comparator comparator) { - this._comparator = comparator; - return this; - } - - /** - * A function that collects all the possible values from a given string. If not provided, one - * will be automatically generated provided valueOf() is nonnull. - * - * @param function conversion function - * @return this - */ - public Builder valuesOf(ValuesConverter function) { - this._valuesConverter = function; - return this; - } - - /** - * A function that gets the most probable value of this object from a given string. If not - * provided, one will be automatically generated provided valuesOf() is nonnull. - * - * @param function conversion function - * @return this - */ - public Builder valueOf(ValueConverter function) { - this._valueConverter = function; - return this; - } - - /** - * A function used to translate an instance to a string. - * - * @param function to string function - * @return this - */ - public Builder toString(StringConverter function) { - this._stringConverter = function; - return this; - } - - public Builder serializer(ISerializableImmutable serializer) { - this._serializer = serializer; - return this; - } - - /** - * Build the converter - * - * @return new converter instance - */ - public IConverter build() { - if (_valueConverter == null && _valuesConverter == null) - throw new NullPointerException( - "Cannot build without a value and/or values converter provided"); - - if (_valuesConverter == null) - _valuesConverter = ((input, stream) -> Stream.of(_valueConverter.valueOf(input))); - - if (_valueConverter == null) - _valueConverter = - ((input, stream) -> _valuesConverter.valuesOf(input).findFirst().orElse(null)); - - return new BaseConverter<>( - _type, - _primitiveType, - _label, - _comparator, - _valuesConverter, - _valueConverter, - _stringConverter, - _serializer); - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/StringConverter.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/StringConverter.java deleted file mode 100644 index 4895ab1fe..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/StringConverter.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import com.matt.forgehax.util.command.v2.converter.exceptions.StringConversionException; -import javax.annotation.Nullable; - -public interface StringConverter { - /** - * Converts a value to a string - * - * @param value to convert to a string - * @return the value as a string - * @throws StringConversionException if there is any issue during the conversion - */ - String toString(E value) throws StringConversionException; - - /** - * Converts a value to a string. If it fails it uses the default string value provided - * - * @param value to convert to a string - * @param defaultTo string to default to - * @return defaultTo if StringConversionException is thrown - */ - default String toString(E value, @Nullable String defaultTo) { - try { - return toString(value); - } catch (StringConversionException e) { - return defaultTo; - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/ValueConverter.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/ValueConverter.java deleted file mode 100644 index 4217117d0..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/ValueConverter.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import com.matt.forgehax.util.command.v2.converter.exceptions.ValueParseException; -import java.util.stream.Stream; -import javax.annotation.Nullable; - -public interface ValueConverter { - - /** - * Find the value of a string with a given stream of data - * - * @param input string to parse - * @param stream stream of data to filter - * @return the most accurate match - * @throws ValueParseException - */ - E valueOf(String input, Stream stream) throws ValueParseException; - - /** - * Find the most probable value of the given input - * - * @param input string to parse - * @return null if no possible interpretation - * @throws ValueParseException if there was an issue parsing the input - */ - @Nullable - default E valueOf(String input) throws ValueParseException { - return valueOf(input, Stream.empty()); - } - - /** - * Same as other method, but allows a default value to be passed which will be used if - * ValueParseException is thrown - * - * @param input string to parse - * @param defaultTo value to default too - * @return default value if ValueParseException is thrown - */ - default E valueOf(String input, @Nullable E defaultTo) { - try { - return valueOf(input); - } catch (ValueParseException e) { - return defaultTo; - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/ValuesConverter.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/ValuesConverter.java deleted file mode 100644 index ff2c6f86e..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/ValuesConverter.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter; - -import com.matt.forgehax.util.command.v2.converter.exceptions.ValueParseException; -import java.util.stream.Stream; - -public interface ValuesConverter { - /** - * Get a list of possible values for the given text - * - * @param input string to parse - * @param stream stream of data to filter - * @return collection sorted from most likely to least likely - */ - Stream valuesOf(String input, Stream stream) throws ValueParseException; - - /** - * Get a list of possible values for the given text. - * - * @param input string to parse - * @return collection of valid data - * @throws ValueParseException if the parse fails - */ - default Stream valuesOf(String input) throws ValueParseException { - return valuesOf(input, Stream.empty()); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/exceptions/StringConversionException.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/exceptions/StringConversionException.java deleted file mode 100644 index 46c203205..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/exceptions/StringConversionException.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter.exceptions; - -public class StringConversionException extends RuntimeException { - public static void requireNonNull(Object o, String msg) throws StringConversionException { - if (o == null) throw new StringConversionException(new NullPointerException(msg)); - } - - public static void requireNonNull(Object o) throws StringConversionException { - requireNonNull(o, "null value"); - } - - public static void throwException(String message) throws StringConversionException { - throw new StringConversionException(new Exception(message)); - } - - public StringConversionException(Throwable t) { - super(t); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/converter/exceptions/ValueParseException.java b/src/main/java/com/matt/forgehax/util/command/v2/converter/exceptions/ValueParseException.java deleted file mode 100644 index 0dabb7700..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/converter/exceptions/ValueParseException.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.matt.forgehax.util.command.v2.converter.exceptions; - -public class ValueParseException extends RuntimeException { - public static void requireNonNull(Object o, String msg) throws ValueParseException { - if (o == null) throw new ValueParseException(new NullPointerException(msg)); - } - - public static void requireNonNull(Object o) throws ValueParseException { - requireNonNull(o, "null value"); - } - - public static void throwException(String message) throws ValueParseException { - throw new ValueParseException(new Exception(message)); - } - - public ValueParseException(Throwable t) { - super(t); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/exception/BaseCmdException.java b/src/main/java/com/matt/forgehax/util/command/v2/exception/BaseCmdException.java deleted file mode 100644 index 2c6fe8ab2..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/exception/BaseCmdException.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.matt.forgehax.util.command.v2.exception; - -import com.matt.forgehax.util.command.v2.ICmd; - -public class BaseCmdException extends RuntimeException { - private final ICmd command; - - public BaseCmdException(ICmd command, String message) { - super(message); - this.command = command; - } - - public BaseCmdException(ICmd command, Throwable wrapping) { - super(wrapping); - this.command = command; - } - - public ICmd getCommand() { - return command; - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdAmbiguousException.java b/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdAmbiguousException.java deleted file mode 100644 index 166f5fc77..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdAmbiguousException.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.matt.forgehax.util.command.v2.exception; - -import com.google.common.collect.ImmutableList; -import com.matt.forgehax.util.command.v2.ICmd; -import java.util.Collection; - -public class CmdAmbiguousException extends BaseCmdException { - private final String input; - private final Collection matching; - - public CmdAmbiguousException(ICmd command, String input, Collection matching) { - super(command, "ambiguous command"); - this.input = input; - this.matching = ImmutableList.copyOf(matching); - } - - public String getInput() { - return input; - } - - public Collection getMatching() { - return matching; - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdException.java b/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdException.java deleted file mode 100644 index 70e2b5c7d..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdException.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.matt.forgehax.util.command.v2.exception; - -/** Created on 1/30/2018 by fr1kin */ -public class CmdException extends Exception { - public CmdException(String msg) { - super(msg); - } - - public static class CreationFailure extends CmdException { - public CreationFailure(String msg) { - super(msg); - } - } - - public static class Unknown extends CmdException { - public Unknown(String msg) { - super(msg); - } - } - - public static class Ambiguous extends CmdException { - public Ambiguous(String msg) { - super(msg); - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdExceptions.java b/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdExceptions.java deleted file mode 100644 index 8b6f13172..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdExceptions.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.matt.forgehax.util.command.v2.exception; - -import com.google.common.base.Strings; -import com.matt.forgehax.util.command.v2.CmdHelper; - -/** Created on 2/3/2018 by fr1kin */ -public class CmdExceptions { - public static void checkIfNull(Object o, String msg) throws CmdRuntimeException.NullPointer { - if (o == null) throw new CmdRuntimeException.NullPointer(msg); - } - - public static void checkIfNull(Object o) throws CmdRuntimeException.NullPointer { - checkIfNull(o, String.valueOf(o) + " is null"); - } - - public static void checkIfNullOrEmpty(String o, String message) throws CmdRuntimeException { - if (Strings.isNullOrEmpty(o)) throw new CmdRuntimeException(message); - } - - public static void checkIfNameValid(String name, String message) throws CmdRuntimeException { - if (!CmdHelper.isNameValid(name)) throw new CmdRuntimeException(message); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdMissingArgumentException.java b/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdMissingArgumentException.java deleted file mode 100644 index bc3cbc090..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdMissingArgumentException.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.matt.forgehax.util.command.v2.exception; - -import com.matt.forgehax.util.command.v2.ICmd; -import com.matt.forgehax.util.command.v2.argument.IArg; - -public class CmdMissingArgumentException extends BaseCmdException { - private final IArg argument; - - public CmdMissingArgumentException(ICmd command, IArg argument) { - super(command, "missing argument"); - this.argument = argument; - } - - public IArg getExpectingArgument() { - return argument; - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdRuntimeException.java b/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdRuntimeException.java deleted file mode 100644 index 599c0649d..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdRuntimeException.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.matt.forgehax.util.command.v2.exception; - -import com.matt.forgehax.util.command.v2.argument.IArg; - -/** Created on 1/30/2018 by fr1kin */ -public class CmdRuntimeException extends RuntimeException { - public CmdRuntimeException() { - super(); - } - - public CmdRuntimeException(String msg) { - super(msg); - } - - public static class NullPointer extends CmdRuntimeException { - public NullPointer(String msg) { - super(msg); - } - } - - public static class ProcessingFailure extends CmdRuntimeException { - public ProcessingFailure(String msg) { - super(msg); - } - } - - public static class CreationFailure extends CmdRuntimeException { - public CreationFailure(String msg) { - super(msg); - } - } - - public static class Conflicting extends CmdRuntimeException { - public Conflicting(String msg) { - super(msg); - } - } - - public static class MissingArgument extends CmdRuntimeException { - private final IArg missingArgument; - - public MissingArgument(IArg missingArgument) { - super(); - this.missingArgument = missingArgument; - } - - public IArg getMissingArgument() { - return missingArgument; - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdUnknownException.java b/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdUnknownException.java deleted file mode 100644 index 0ab869b4d..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/exception/CmdUnknownException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.matt.forgehax.util.command.v2.exception; - -import com.matt.forgehax.util.command.v2.ICmd; - -public class CmdUnknownException extends BaseCmdException { - private final String input; - - public CmdUnknownException(ICmd command, String input) { - super(command, "unknown command"); - this.input = input; - } - - public String getInput() { - return input; - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/flag/CmdFlags.java b/src/main/java/com/matt/forgehax/util/command/v2/flag/CmdFlags.java deleted file mode 100644 index 6b2840a7e..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/flag/CmdFlags.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.matt.forgehax.util.command.v2.flag; - -import com.google.common.collect.Maps; -import java.util.EnumSet; -import java.util.Map; -import javax.annotation.Nullable; - -public class CmdFlags { - private static final Map>, EnumSet> REGISTRY = Maps.newConcurrentMap(); - - public static > void register(Class enumClass) { - if (!ICmdFlag.class.isAssignableFrom(enumClass)) - throw new IllegalArgumentException("Flag Enum must extend " + ICmdFlag.class.getSimpleName()); - REGISTRY.put(enumClass, EnumSet.allOf(enumClass)); - } - - @SuppressWarnings("unchecked") - @Nullable - public static > EnumSet get(Class enumClass) { - return (EnumSet) REGISTRY.get(enumClass); - } - - @SuppressWarnings("unchecked") - @Nullable - public static EnumSet get(final String enumClassName) { - return (EnumSet) - REGISTRY - .entrySet() - .stream() - .filter(e -> e.getKey().getName().equals(enumClassName)) - .findFirst() - .map(Map.Entry::getValue) - .orElse(null); - } - - @SuppressWarnings("unchecked") - @Nullable - public static Enum get( - final String enumClassName, final String enumValueName) { - EnumSet es = get(enumClassName); - return es == null - ? null - : es.stream().filter(v -> v.name().equals(enumValueName)).findFirst().orElse(null); - } - - @SuppressWarnings("unchecked") - @Nullable - public static Enum fromString(final String serializedEnumStr) { - String split[] = serializedEnumStr.split("::"); - if (split.length != 2) return null; - return get(split[0], split[1]); - } - - public static String toString(Enum flag) { - return flag.getDeclaringClass().getName() + "::" + flag.name(); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/flag/DefaultCmdFlags.java b/src/main/java/com/matt/forgehax/util/command/v2/flag/DefaultCmdFlags.java deleted file mode 100644 index 49598273d..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/flag/DefaultCmdFlags.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.matt.forgehax.util.command.v2.flag; - -/** Created on 12/26/2017 by fr1kin */ -public enum DefaultCmdFlags implements ICmdFlag { - HIDDEN, - ; - - static { - CmdFlags.register(DefaultCmdFlags.class); - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/flag/ICmdFlag.java b/src/main/java/com/matt/forgehax/util/command/v2/flag/ICmdFlag.java deleted file mode 100644 index ad008f031..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/flag/ICmdFlag.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.matt.forgehax.util.command.v2.flag; - -/** Created on 12/25/2017 by fr1kin */ -public interface ICmdFlag {} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/serializers/CmdChildrenSerializer.java b/src/main/java/com/matt/forgehax/util/command/v2/serializers/CmdChildrenSerializer.java deleted file mode 100644 index 172023ce2..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/serializers/CmdChildrenSerializer.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.matt.forgehax.util.command.v2.serializers; - -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.command.v2.ICmd; -import com.matt.forgehax.util.command.v2.IParentCmd; -import java.io.IOException; - -public class CmdChildrenSerializer implements ICmdSerializer { - private static final CmdChildrenSerializer INSTANCE = new CmdChildrenSerializer(); - - public static CmdChildrenSerializer getInstance() { - return INSTANCE; - } - - // - // - // - - @Override - public void serialize(IParentCmd instance, JsonWriter writer) throws IOException { - writer.beginObject(); // { - - for (ICmd cmd : instance.getChildren()) { - writer.name(cmd.getUniqueHeader()); - cmd.serialize(writer); - } - - writer.endObject(); // } - } - - @Override - public void deserialize(IParentCmd instance, JsonReader reader) throws IOException { - reader.beginObject(); // { - - while (reader.hasNext()) { - String name = reader.nextName(); // name is by default the absolute name - ICmd cmd = instance.findChild(name); - if (cmd != null) cmd.deserialize(reader); - else reader.skipValue(); // missing command, skip - } - - reader.endObject(); // } - } - - @Override - public String heading() { - return "children"; - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/serializers/CmdFlagSerializer.java b/src/main/java/com/matt/forgehax/util/command/v2/serializers/CmdFlagSerializer.java deleted file mode 100644 index a19e72806..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/serializers/CmdFlagSerializer.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.matt.forgehax.util.command.v2.serializers; - -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.util.command.v2.ICmd; -import com.matt.forgehax.util.command.v2.flag.CmdFlags; -import com.matt.forgehax.util.command.v2.flag.ICmdFlag; -import java.io.IOException; - -public class CmdFlagSerializer implements ICmdSerializer { - private static final CmdFlagSerializer INSTANCE = new CmdFlagSerializer(); - - public static CmdFlagSerializer getInstance() { - return INSTANCE; - } - - // - // - // - - @Override - public void serialize(ICmd instance, JsonWriter writer) throws IOException { - writer.beginArray(); // [ - - for (Enum val : instance.getFlags()) { - writer.value(CmdFlags.toString(val)); - } - - writer.endArray(); // ] - } - - @Override - public void deserialize(ICmd instance, JsonReader reader) throws IOException { - // remove previous flags - instance.clearFlags(); - - reader.beginArray(); // [ - - while (reader.hasNext()) { - String next = reader.nextName(); - Enum value = CmdFlags.fromString(next); - if (value != null) instance.addFlag(value); - } - - reader.endArray(); // ] - } - - @Override - public String heading() { - return "flags"; - } -} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/serializers/ICmdSerializer.java b/src/main/java/com/matt/forgehax/util/command/v2/serializers/ICmdSerializer.java deleted file mode 100644 index 987aad700..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/serializers/ICmdSerializer.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.matt.forgehax.util.command.v2.serializers; - -import com.matt.forgehax.util.command.v2.ICmd; -import com.matt.forgehax.util.serialization.ISerializableMutable; - -public interface ICmdSerializer extends ISerializableMutable {} diff --git a/src/main/java/com/matt/forgehax/util/command/v2/templates/ConverterBuilder.java b/src/main/java/com/matt/forgehax/util/command/v2/templates/ConverterBuilder.java deleted file mode 100644 index 2f63dfdaf..000000000 --- a/src/main/java/com/matt/forgehax/util/command/v2/templates/ConverterBuilder.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.matt.forgehax.util.command.v2.templates; - -import com.matt.forgehax.util.typeconverter.TypeConverter; -import com.matt.forgehax.util.typeconverter.TypeConverterRegistry; -import java.util.Objects; - -/** Created on 4/14/2018 by fr1kin */ -public interface ConverterBuilder { - /** - * Converter for changing objects to a string and an string to an object - * - * @param typeConverter converter instance - * @return this - */ - R converter(TypeConverter typeConverter); - - /** - * Alternative to using ::converter, will try and lookup the class in the type converter registry. - * If it fails to find anything, this.converter will be null and - * CmdRuntimeException.CreationFailure will be thrown when build() is called. - * - * @param clazz class of converter - * @return this - */ - default R converterOfType(Class clazz) { - TypeConverter tc = TypeConverterRegistry.get(clazz); - Objects.requireNonNull( - tc, "Failed to find type converter in registry for '" + clazz.getName() + "'"); - return converter(tc); - } -} diff --git a/src/main/java/com/matt/forgehax/util/common/Priority.java b/src/main/java/com/matt/forgehax/util/common/Priority.java index 13f3ccfb7..873c12783 100644 --- a/src/main/java/com/matt/forgehax/util/common/Priority.java +++ b/src/main/java/com/matt/forgehax/util/common/Priority.java @@ -3,8 +3,11 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ @Retention(RetentionPolicy.RUNTIME) public @interface Priority { + PriorityEnum value() default PriorityEnum.DEFAULT; } diff --git a/src/main/java/com/matt/forgehax/util/common/PriorityEnum.java b/src/main/java/com/matt/forgehax/util/common/PriorityEnum.java index 6b8aa433c..9743819fd 100644 --- a/src/main/java/com/matt/forgehax/util/common/PriorityEnum.java +++ b/src/main/java/com/matt/forgehax/util/common/PriorityEnum.java @@ -1,6 +1,8 @@ package com.matt.forgehax.util.common; -/** Created on 6/8/2017 by fr1kin */ +/** + * Created on 6/8/2017 by fr1kin + */ public enum PriorityEnum { HIGHEST, HIGH, diff --git a/src/main/java/com/matt/forgehax/util/console/ConsoleIO.java b/src/main/java/com/matt/forgehax/util/console/ConsoleIO.java index 73144d0d7..b3c0df757 100644 --- a/src/main/java/com/matt/forgehax/util/console/ConsoleIO.java +++ b/src/main/java/com/matt/forgehax/util/console/ConsoleIO.java @@ -7,10 +7,13 @@ import net.minecraft.util.text.Style; import net.minecraft.util.text.TextFormatting; -/** Created on 6/10/2017 by fr1kin */ +/** + * Created on 6/10/2017 by fr1kin + */ // TODO: fix memory leak public class ConsoleIO implements Globals { + public static final Style HEADING = new Style().setColor(TextFormatting.GRAY).setItalic(true); private static final ThreadLocal INDENTATION = new ThreadLocal<>(); @@ -31,8 +34,11 @@ public static void start() { public static void write(String msg, Style style) { String tab = Strings.repeat('>', Math.max(getOrCreate().get(), MIN_INDENT)) + " "; - if (style == null) Helper.printMessageNaked(tab, msg); // TODO: use a non-chat console - else Helper.printMessageNaked(tab, msg, style); // TODO: use a non-chat console + if (style == null) { + Helper.printMessageNaked(tab, msg); // TODO: use a non-chat console + } else { + Helper.printMessageNaked(tab, msg, style); // TODO: use a non-chat console + } } public static void write(String msg) { diff --git a/src/main/java/com/matt/forgehax/util/console/ConsoleWriter.java b/src/main/java/com/matt/forgehax/util/console/ConsoleWriter.java index 3eff83c91..243edfdff 100644 --- a/src/main/java/com/matt/forgehax/util/console/ConsoleWriter.java +++ b/src/main/java/com/matt/forgehax/util/console/ConsoleWriter.java @@ -1,15 +1,18 @@ package com.matt.forgehax.util.console; -/** Created on 6/10/2017 by fr1kin */ +/** + * Created on 6/10/2017 by fr1kin + */ public interface ConsoleWriter { + default void write(String msg) { ConsoleIO.write(msg); } - + default void incrementIndent() { ConsoleIO.incrementIndent(); } - + default void decrementIndent() { ConsoleIO.decrementIndent(); } diff --git a/src/main/java/com/matt/forgehax/util/draw/Fonts.java b/src/main/java/com/matt/forgehax/util/draw/Fonts.java deleted file mode 100644 index 1264cf150..000000000 --- a/src/main/java/com/matt/forgehax/util/draw/Fonts.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.matt.forgehax.util.draw; - -import java.awt.*; -import uk.co.hexeption.thx.ttf.MinecraftFontRenderer; - -/** Created on 9/2/2017 by fr1kin */ -public interface Fonts { - MinecraftFontRenderer ARIAL = - new MinecraftFontRenderer(new Font("Arial", Font.PLAIN, 18), true, true); - MinecraftFontRenderer CAMBRIA = - new MinecraftFontRenderer(new Font("Cambria", Font.PLAIN, 18), true, true); - MinecraftFontRenderer GEORGIA = - new MinecraftFontRenderer(new Font("Georgia", Font.PLAIN, 18), true, true); -} diff --git a/src/main/java/com/matt/forgehax/util/draw/RenderUtils.java b/src/main/java/com/matt/forgehax/util/draw/RenderUtils.java index 1a9efbec7..24fb22961 100644 --- a/src/main/java/com/matt/forgehax/util/draw/RenderUtils.java +++ b/src/main/java/com/matt/forgehax/util/draw/RenderUtils.java @@ -1,6 +1,6 @@ package com.matt.forgehax.util.draw; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getLocalPlayer; import com.matt.forgehax.Globals; import com.matt.forgehax.util.entity.EntityUtils; @@ -13,32 +13,35 @@ import org.lwjgl.opengl.GL11; public class RenderUtils implements Globals { + public static Vec3d getRenderPos() { return new Vec3d( - MC.player.lastTickPosX - + (MC.player.posX - MC.player.lastTickPosX) * MC.getRenderPartialTicks(), - MC.player.lastTickPosY - + (MC.player.posY - MC.player.lastTickPosY) * MC.getRenderPartialTicks(), - MC.player.lastTickPosZ - + (MC.player.posZ - MC.player.lastTickPosZ) * MC.getRenderPartialTicks()); + MC.player.lastTickPosX + + (MC.player.posX - MC.player.lastTickPosX) * MC.getRenderPartialTicks(), + MC.player.lastTickPosY + + (MC.player.posY - MC.player.lastTickPosY) * MC.getRenderPartialTicks(), + MC.player.lastTickPosZ + + (MC.player.posZ - MC.player.lastTickPosZ) * MC.getRenderPartialTicks()); } - + public static void drawLine( - Vec3d startPos, Vec3d endPos, int color, boolean smooth, float width) { + Vec3d startPos, Vec3d endPos, int color, boolean smooth, float width) { Tessellator tessellator = Tessellator.getInstance(); BufferBuilder BufferBuilder = tessellator.getBuffer(); - + Vec3d endVecPos = endPos.subtract(startPos); - + float r = (float) (color >> 16 & 255) / 255.0F; float g = (float) (color >> 8 & 255) / 255.0F; float b = (float) (color & 255) / 255.0F; float a = (float) (color >> 24 & 255) / 255.0F; - - if (smooth) GL11.glEnable(GL11.GL_LINE_SMOOTH); - + + if (smooth) { + GL11.glEnable(GL11.GL_LINE_SMOOTH); + } + GL11.glLineWidth(width); - + GlStateManager.pushMatrix(); GlStateManager.translate(startPos.x, startPos.y, startPos.z); GlStateManager.disableTexture2D(); @@ -46,14 +49,16 @@ public static void drawLine( GlStateManager.disableAlpha(); GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); GlStateManager.shadeModel(GL11.GL_SMOOTH); - + BufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR); BufferBuilder.pos(0, 0, 0).color(r, g, b, a).endVertex(); BufferBuilder.pos(endVecPos.x, endVecPos.y, endVecPos.z).color(r, g, b, a).endVertex(); tessellator.draw(); - - if (smooth) GL11.glDisable(GL11.GL_LINE_SMOOTH); - + + if (smooth) { + GL11.glDisable(GL11.GL_LINE_SMOOTH); + } + GlStateManager.shadeModel(GL11.GL_FLAT); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); @@ -62,26 +67,26 @@ public static void drawLine( GlStateManager.enableCull(); GlStateManager.popMatrix(); } - + // thanks again Gregor public static void drawBox( - Vec3d startPos, Vec3d endPos, int color, float width, boolean ignoreZ) { + Vec3d startPos, Vec3d endPos, int color, float width, boolean ignoreZ) { Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); - + Vec3d renderPos = EntityUtils.getInterpolatedPos(getLocalPlayer(), MC.getRenderPartialTicks()); - + Vec3d min = startPos.subtract(renderPos); Vec3d max = endPos.subtract(renderPos); - + double minX = min.x, minY = min.y, minZ = min.z; double maxX = max.x, maxY = max.y, maxZ = max.z; - + float r = (float) (color >> 16 & 255) / 255.0F; float g = (float) (color >> 8 & 255) / 255.0F; float b = (float) (color & 255) / 255.0F; float a = (float) (color >> 24 & 255) / 255.0F; - + GlStateManager.pushMatrix(); GlStateManager.disableTexture2D(); GlStateManager.enableBlend(); @@ -89,13 +94,15 @@ public static void drawBox( GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); GlStateManager.shadeModel(GL11.GL_SMOOTH); GlStateManager.glLineWidth(width); - - if (ignoreZ) GlStateManager.disableDepth(); - + + if (ignoreZ) { + GlStateManager.disableDepth(); + } + GlStateManager.color(r, g, b, a); - + // GlStateManager.translate(startPos.xCoord, startPos.yCoord, startPos.zCoord); - + buffer.begin(GL11.GL_LINE_STRIP, DefaultVertexFormats.POSITION); buffer.pos(minX, minY, minZ).endVertex(); buffer.pos(maxX, minY, minZ).endVertex(); @@ -120,7 +127,7 @@ public static void drawBox( buffer.pos(minX, minY, maxZ).endVertex(); buffer.pos(minX, maxY, maxZ).endVertex(); tessellator.draw(); - + GlStateManager.shadeModel(GL11.GL_FLAT); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); @@ -129,14 +136,14 @@ public static void drawBox( GlStateManager.enableCull(); GlStateManager.popMatrix(); } - + public static void drawBox( - BlockPos startPos, BlockPos endPos, int color, float width, boolean ignoreZ) { + BlockPos startPos, BlockPos endPos, int color, float width, boolean ignoreZ) { drawBox( - new Vec3d(startPos.getX(), startPos.getY(), startPos.getZ()), - new Vec3d(endPos.getX(), endPos.getY(), endPos.getZ()), - color, - width, - ignoreZ); + new Vec3d(startPos.getX(), startPos.getY(), startPos.getZ()), + new Vec3d(endPos.getX(), endPos.getY(), endPos.getZ()), + color, + width, + ignoreZ); } } diff --git a/src/main/java/com/matt/forgehax/util/draw/SurfaceBuilder.java b/src/main/java/com/matt/forgehax/util/draw/SurfaceBuilder.java index 7e353b929..6ba2bb8d0 100644 --- a/src/main/java/com/matt/forgehax/util/draw/SurfaceBuilder.java +++ b/src/main/java/com/matt/forgehax/util/draw/SurfaceBuilder.java @@ -2,323 +2,356 @@ import static com.matt.forgehax.Globals.MC; import static com.matt.forgehax.Helper.getLocalPlayer; -import static org.lwjgl.opengl.GL11.*; - -import com.matt.forgehax.util.Utils; +import static org.lwjgl.opengl.GL11.GL_LINES; +import static org.lwjgl.opengl.GL11.GL_LINE_LOOP; +import static org.lwjgl.opengl.GL11.GL_POLYGON; +import static org.lwjgl.opengl.GL11.GL_QUADS; +import static org.lwjgl.opengl.GL11.glBegin; +import static org.lwjgl.opengl.GL11.glColor4d; +import static org.lwjgl.opengl.GL11.glEnd; +import static org.lwjgl.opengl.GL11.glRotated; +import static org.lwjgl.opengl.GL11.glScaled; +import static org.lwjgl.opengl.GL11.glTranslated; +import static org.lwjgl.opengl.GL11.glVertex2d; +import static org.lwjgl.opengl.GL11.glVertex3d; + +import com.matt.forgehax.util.color.Color; +import com.matt.forgehax.util.draw.font.MinecraftFontRenderer; import java.util.Stack; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; -import uk.co.hexeption.thx.ttf.MinecraftFontRenderer; -/** Created on 9/2/2017 by fr1kin */ +/** + * Created on 9/2/2017 by fr1kin + */ public class SurfaceBuilder { + public static final int COLOR = 1; public static final int SCALE = 2; public static final int TRANSLATION = 4; public static final int ROTATION = 8; public static final int ALL = 15; - + private static final SurfaceBuilder INSTANCE = new SurfaceBuilder(); - + public static SurfaceBuilder getBuilder() { return INSTANCE; } - + // -------------------- - + private final Stack settings = new Stack<>(); private final RenderSettings DEFAULT_SETTINGS = new RenderSettings(); - + private RenderSettings current() { return !settings.isEmpty() ? settings.peek() : DEFAULT_SETTINGS; } - + public SurfaceBuilder begin(int mode) { glBegin(mode); return this; } - + public SurfaceBuilder beginLines() { return begin(GL_LINES); } - + public SurfaceBuilder beginLineLoop() { return begin(GL_LINE_LOOP); } - + public SurfaceBuilder beginQuads() { return begin(GL_QUADS); } - + public SurfaceBuilder beginPolygon() { return begin(GL_POLYGON); } - + public SurfaceBuilder end() { glEnd(); return this; } - + public SurfaceBuilder autoApply(boolean enabled) { current().setAutoApply(enabled); return this; } - + public SurfaceBuilder apply() { return apply(ALL); } - + public SurfaceBuilder apply(int flags) { RenderSettings current = current(); - if ((flags & COLOR) == COLOR) current.applyColor(); - if ((flags & SCALE) == SCALE) current.applyScale(); - if ((flags & TRANSLATION) == TRANSLATION) current.applyTranslation(); - if ((flags & ROTATION) == ROTATION) current.applyRotation(); + if ((flags & COLOR) == COLOR) { + current.applyColor(); + } + if ((flags & SCALE) == SCALE) { + current.applyScale(); + } + if ((flags & TRANSLATION) == TRANSLATION) { + current.applyTranslation(); + } + if ((flags & ROTATION) == ROTATION) { + current.applyRotation(); + } return this; } - + public SurfaceBuilder reset() { return reset(ALL); } - + public SurfaceBuilder reset(int flags) { RenderSettings current = current(); - if ((flags & COLOR) == COLOR) current.resetColor(); - if ((flags & SCALE) == SCALE) current.resetScale(); - if ((flags & TRANSLATION) == TRANSLATION) current.resetTranslation(); - if ((flags & ROTATION) == ROTATION) current.resetRotation(); + if ((flags & COLOR) == COLOR) { + current.resetColor(); + } + if ((flags & SCALE) == SCALE) { + current.resetScale(); + } + if ((flags & TRANSLATION) == TRANSLATION) { + current.resetTranslation(); + } + if ((flags & ROTATION) == ROTATION) { + current.resetRotation(); + } return this; } - + public SurfaceBuilder push() { GlStateManager.pushMatrix(); settings.push(new RenderSettings()); return this; } - + public SurfaceBuilder pop() { - if (!settings.isEmpty()) settings.pop(); + if (!settings.isEmpty()) { + settings.pop(); + } GlStateManager.popMatrix(); return this; } - + public SurfaceBuilder color(double r, double g, double b, double a) { current() - .setColor4d( - new double[] { - MathHelper.clamp(r, 0.D, 1.D), - MathHelper.clamp(g, 0.D, 1.D), - MathHelper.clamp(b, 0.D, 1.D), - MathHelper.clamp(a, 0.D, 1.D) - }); + .setColor4d( + new double[]{ + MathHelper.clamp(r, 0.D, 1.D), + MathHelper.clamp(g, 0.D, 1.D), + MathHelper.clamp(b, 0.D, 1.D), + MathHelper.clamp(a, 0.D, 1.D) + }); return this; } - + public SurfaceBuilder color(int buffer) { return color( - (buffer >> 16 & 255) / 255.D, - (buffer >> 8 & 255) / 255.D, - (buffer & 255) / 255.D, - (buffer >> 24 & 255) / 255.D); + (buffer >> 16 & 255) / 255.D, + (buffer >> 8 & 255) / 255.D, + (buffer & 255) / 255.D, + (buffer >> 24 & 255) / 255.D); } - + public SurfaceBuilder color(int r, int g, int b, int a) { return color(r / 255.D, g / 255.D, b / 255.D, a / 255.D); } - + public SurfaceBuilder scale(double x, double y, double z) { - current().setScale3d(new double[] {x, y, z}); + current().setScale3d(new double[]{x, y, z}); return this; } - + public SurfaceBuilder scale(double s) { return scale(s, s, s); } - + public SurfaceBuilder scale() { return scale(0.D); } - + public SurfaceBuilder translate(double x, double y, double z) { - current().setTranslate3d(new double[] {x, y, z}); + current().setTranslate3d(new double[]{x, y, z}); return this; } - + public SurfaceBuilder translate(double x, double y) { return translate(x, y, 0.D); } - + public SurfaceBuilder rotate(double angle, double x, double y, double z) { - current().setRotated4d(new double[] {angle, x, y, z}); + current().setRotated4d(new double[]{angle, x, y, z}); return this; } - + public SurfaceBuilder width(double width) { GlStateManager.glLineWidth((float) width); return this; } - + public SurfaceBuilder vertex(double x, double y, double z) { glVertex3d(x, y, z); return this; } - + public SurfaceBuilder vertex(double x, double y) { glVertex2d(x, y); return this; } - + public SurfaceBuilder line(double startX, double startY, double endX, double endY) { return vertex(startX, startY).vertex(endX, endY); } - + public SurfaceBuilder rectangle(double x, double y, double w, double h) { return vertex(x, y).vertex(x, y + h).vertex(x + w, y + h).vertex(x + w, y); } - + public SurfaceBuilder fontRenderer(MinecraftFontRenderer fontRenderer) { current().setFontRenderer(fontRenderer); return this; } - + private SurfaceBuilder text(String text, double x, double y, boolean shadow) { if (current().hasFontRenderer()) // use custom font renderer - current() - .getFontRenderer() - .drawString( - text, - x, - y + 1 /*TTF font renderer needs to be offset by 1*/, - Utils.toRGBA(current().getColor4d()), - shadow); - else { + { + current() + .getFontRenderer() + .drawString( + text, + x, + y + 1 /*TTF font renderer needs to be offset by 1*/, + Color.of(current().getColor4d()).toBuffer(), + shadow); + } else { // use default minecraft font GlStateManager.pushMatrix(); GlStateManager.translate(x, y, 0.D); - - MC.fontRenderer.drawString(text, 0, 0, Utils.toRGBA(current().getColor4d()), shadow); - + + MC.fontRenderer.drawString(text, 0, 0, Color.of(current().getColor4d()).toBuffer(), shadow); + GlStateManager.popMatrix(); } return this; } - + public SurfaceBuilder text(String text, double x, double y) { return text(text, x, y, false); } - + public SurfaceBuilder textWithShadow(String text, double x, double y) { return text(text, x, y, true); } - + public SurfaceBuilder task(Runnable task) { task.run(); return this; } - + public SurfaceBuilder item(ItemStack stack, double x, double y) { MC.getRenderItem().zLevel = 100.f; SurfaceHelper.renderItemAndEffectIntoGUI( - getLocalPlayer(), stack, x, y, current().hasScale() ? current().getScale3d()[0] : 16.D); + getLocalPlayer(), stack, x, y, current().hasScale() ? current().getScale3d()[0] : 16.D); MC.getRenderItem().zLevel = 0.f; return this; } - + public SurfaceBuilder itemOverlay(ItemStack stack, double x, double y) { SurfaceHelper.renderItemOverlayIntoGUI( - MC.fontRenderer, - stack, - x, - y, - null, - current().hasScale() ? current().getScale3d()[0] : 16.D); + MC.fontRenderer, + stack, + x, + y, + null, + current().hasScale() ? current().getScale3d()[0] : 16.D); return this; } - + public SurfaceBuilder head(ResourceLocation resource, double x, double y) { MC.renderEngine.bindTexture(resource); double scale = current().hasScale() ? current().getScale3d()[0] : 12.D; SurfaceHelper.drawScaledCustomSizeModalRect( - (x * (1 / scale)), (y * (1 / scale)), 8.0F, 8.0F, 8, 8, 12, 12, 64.0F, 64.0F); + (x * (1 / scale)), (y * (1 / scale)), 8.0F, 8.0F, 8, 8, 12, 12, 64.0F, 64.0F); SurfaceHelper.drawScaledCustomSizeModalRect( - (x * (1 / scale)), (y * (1 / scale)), 40.0F, 8.0F, 8, 8, 12, 12, 64.0F, 64.0F); + (x * (1 / scale)), (y * (1 / scale)), 40.0F, 8.0F, 8, 8, 12, 12, 64.0F, 64.0F); return this; } - + public int getFontWidth(String text) { return current().hasFontRenderer() - ? current().getFontRenderer().getStringWidth(text) - : MC.fontRenderer.getStringWidth(text); + ? current().getFontRenderer().getStringWidth(text) + : MC.fontRenderer.getStringWidth(text); } - + public int getFontHeight() { return current().hasFontRenderer() - ? current().getFontRenderer().getHeight() - : MC.fontRenderer.FONT_HEIGHT; + ? current().getFontRenderer().getHeight() + : MC.fontRenderer.FONT_HEIGHT; } - + public int getFontHeight(String text) { return getFontHeight(); } - + private double _getScaled(int index, double p) { return p * (1.D / current().getScale3d()[index]); } - + public double getScaledX(double x) { return _getScaled(0, x); } - + public double getScaledY(double y) { return _getScaled(1, y); } - + public double getScaledZ(double z) { return _getScaled(2, z); } - + public double getScaled(double p) { return getScaledX(p); } - + public double getItemSize() { return 16; } - + // -------------------- - + public static void disableTexture2D() { GlStateManager.disableTexture2D(); } - + public static void enableTexture2D() { GlStateManager.enableTexture2D(); } - + public static void enableBlend() { GlStateManager.enableBlend(); GlStateManager.tryBlendFuncSeparate( - GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, - GlStateManager.SourceFactor.ONE, - GlStateManager.DestFactor.ZERO); + GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); } - + public static void disableBlend() { GlStateManager.disableBlend(); } - + public static void enableFontRendering() { GlStateManager.disableDepth(); } - + public static void disableFontRendering() { GlStateManager.enableDepth(); } - + public static void enableItemRendering() { RenderHelper.enableGUIStandardItemLighting(); GlStateManager.disableLighting(); @@ -326,154 +359,171 @@ public static void enableItemRendering() { GlStateManager.enableColorMaterial(); GlStateManager.enableLighting(); } - + public static void disableItemRendering() { GlStateManager.disableLighting(); GlStateManager.enableDepth(); } - + public static void clearColor() { GlStateManager.color(1.f, 1.f, 1.f, 1.f); } - + private static class RenderSettings { - private static final double[] EMPTY_VECTOR3D = new double[] {0.D, 0.D, 0.D}; - private static final double[] EMPTY_VECTOR4D = new double[] {0.D, 0.D, 0.D, 0.D}; - + + private static final double[] EMPTY_VECTOR3D = new double[]{0.D, 0.D, 0.D}; + private static final double[] EMPTY_VECTOR4D = new double[]{0.D, 0.D, 0.D, 0.D}; + private double[] color4d = EMPTY_VECTOR4D; // 0-3 = rgba private double[] scale3d = EMPTY_VECTOR3D; // 0-2 = xyz private double[] translate3d = EMPTY_VECTOR3D; // 0-2 = xyz private double[] rotated4d = EMPTY_VECTOR4D; // 0 = angle, 1-3 = xyz - + private boolean autoApply = true; - + private MinecraftFontRenderer fontRenderer = null; - + public double[] getColor4d() { return color4d; } - + public void setColor4d(double[] color4d) { this.color4d = color4d; - if (autoApply) applyColor(); + if (autoApply) { + applyColor(); + } } - + public double[] getScale3d() { return scale3d; } - + public void setScale3d(double[] scale3d) { this.scale3d = scale3d; - if (autoApply) applyScale(); + if (autoApply) { + applyScale(); + } } - + public double[] getTranslate3d() { return translate3d; } - + public void setTranslate3d(double[] translate3d) { this.translate3d = translate3d; - if (autoApply) applyTranslation(); + if (autoApply) { + applyTranslation(); + } } - + public double[] getRotated4d() { return rotated4d; } - + public void setRotated4d(double[] rotated4d) { this.rotated4d = rotated4d; - if (autoApply) applyRotation(); + if (autoApply) { + applyRotation(); + } } - + public MinecraftFontRenderer getFontRenderer() { return fontRenderer; } - + public void setFontRenderer(MinecraftFontRenderer fontRenderer) { this.fontRenderer = fontRenderer; } - + public void setAutoApply(boolean autoApply) { this.autoApply = autoApply; } - + public boolean hasColor() { return color4d != EMPTY_VECTOR4D; } - + public boolean hasScale() { return scale3d != EMPTY_VECTOR3D; } - + public boolean hasTranslation() { return translate3d != EMPTY_VECTOR3D; } - + public boolean hasRotation() { return rotated4d != EMPTY_VECTOR4D; } - + public boolean hasFontRenderer() { return fontRenderer != null; } - + public void applyColor() { - if (hasColor()) glColor4d(color4d[0], color4d[1], color4d[2], color4d[3]); + if (hasColor()) { + glColor4d(color4d[0], color4d[1], color4d[2], color4d[3]); + } } - + public void applyScale() { - if (hasScale()) glScaled(scale3d[0], scale3d[1], scale3d[2]); + if (hasScale()) { + glScaled(scale3d[0], scale3d[1], scale3d[2]); + } } - + public void applyTranslation() { - if (hasTranslation()) glTranslated(translate3d[0], translate3d[1], translate3d[2]); + if (hasTranslation()) { + glTranslated(translate3d[0], translate3d[1], translate3d[2]); + } } - + public void applyRotation() { - if (hasRotation()) glRotated(rotated4d[0], rotated4d[1], rotated4d[2], rotated4d[3]); + if (hasRotation()) { + glRotated(rotated4d[0], rotated4d[1], rotated4d[2], rotated4d[3]); + } } - + public void clearColor() { color4d = EMPTY_VECTOR4D; } - + public void clearScale() { scale3d = EMPTY_VECTOR3D; } - + public void clearTranslation() { translate3d = EMPTY_VECTOR3D; } - + public void clearRotation() { rotated4d = EMPTY_VECTOR4D; } - + public void clearFontRenderer() { fontRenderer = null; } - + public void resetColor() { if (hasColor()) { clearColor(); glColor4d(1.D, 1.D, 1.D, 1.D); } } - + public void resetScale() { if (hasScale()) { clearScale(); glScaled(1.D, 1.D, 1.D); } } - + public void resetTranslation() { if (hasTranslation()) { clearTranslation(); glTranslated(0.D, 0.D, 0.D); } } - + public void resetRotation() { if (hasRotation()) { clearRotation(); diff --git a/src/main/java/com/matt/forgehax/util/draw/SurfaceHelper.java b/src/main/java/com/matt/forgehax/util/draw/SurfaceHelper.java index 87c1ad871..5580418fc 100644 --- a/src/main/java/com/matt/forgehax/util/draw/SurfaceHelper.java +++ b/src/main/java/com/matt/forgehax/util/draw/SurfaceHelper.java @@ -4,6 +4,7 @@ import com.matt.forgehax.Globals; import com.matt.forgehax.Helper; +import com.matt.forgehax.util.draw.font.MinecraftFontRenderer; import javax.annotation.Nullable; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; @@ -23,51 +24,59 @@ import net.minecraft.potion.PotionEffect; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; -import uk.co.hexeption.thx.ttf.MinecraftFontRenderer; -/** 2D rendering */ +/** + * 2D rendering + */ public class SurfaceHelper implements Globals { + public static void drawString( - @Nullable MinecraftFontRenderer fontRenderer, - String text, - double x, - double y, - int color, - boolean shadow) { + @Nullable MinecraftFontRenderer fontRenderer, + String text, + double x, + double y, + int color, + boolean shadow) { if (fontRenderer == null) { MC.fontRenderer.drawString(text, Math.round(x), Math.round(y), color, shadow); } else { fontRenderer.drawString(text, x, y, color, shadow); } } - + public static double getStringWidth(@Nullable MinecraftFontRenderer fontRenderer, String text) { - if (fontRenderer == null) return MC.fontRenderer.getStringWidth(text); - else return fontRenderer.getStringWidth(text); + if (fontRenderer == null) { + return MC.fontRenderer.getStringWidth(text); + } else { + return fontRenderer.getStringWidth(text); + } } - + public static double getStringHeight(@Nullable MinecraftFontRenderer fontRenderer) { - if (fontRenderer == null) return MC.fontRenderer.FONT_HEIGHT; - else return fontRenderer.getHeight(); + if (fontRenderer == null) { + return MC.fontRenderer.FONT_HEIGHT; + } else { + return fontRenderer.getHeight(); + } } - + public static void drawRect(int x, int y, int w, int h, int color) { GL11.glLineWidth(1.0f); Gui.drawRect(x, y, x + w, y + h, color); } - + public static void drawOutlinedRect(int x, int y, int w, int h, int color) { drawOutlinedRect(x, y, w, h, color, 1.f); } - + public static void drawOutlinedRectShaded( - int x, int y, int w, int h, int colorOutline, int shade, float width) { + int x, int y, int w, int h, int colorOutline, int shade, float width) { int shaded = (0x00FFFFFF & colorOutline) | ((shade & 255) << 24); // modify the alpha value // int shaded = Utils.toRGBA(255,255,255, 100); drawRect(x, y, w, h, shaded); drawOutlinedRect(x, y, w, h, colorOutline, width); } - + public static void drawOutlinedRect(int x, int y, int w, int h, int color, float width) { float r = (float) (color >> 16 & 255) / 255.0F; float g = (float) (color >> 8 & 255) / 255.0F; @@ -75,57 +84,57 @@ public static void drawOutlinedRect(int x, int y, int w, int h, int color, float float a = (float) (color >> 24 & 255) / 255.0F; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder BufferBuilder = tessellator.getBuffer(); - + GlStateManager.enableBlend(); GlStateManager.disableTexture2D(); GlStateManager.tryBlendFuncSeparate( - GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, - GlStateManager.SourceFactor.ONE, - GlStateManager.DestFactor.ZERO); + GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); GlStateManager.color(r, g, b, a); - + GL11.glLineWidth(width); - + BufferBuilder.begin(GL11.GL_LINE_LOOP, DefaultVertexFormats.POSITION); BufferBuilder.pos((double) x, (double) y, 0.0D).endVertex(); BufferBuilder.pos((double) x, (double) y + h, 0.0D).endVertex(); BufferBuilder.pos((double) x + w, (double) y + h, 0.0D).endVertex(); BufferBuilder.pos((double) x + w, (double) y, 0.0D).endVertex(); tessellator.draw(); - + GlStateManager.enableTexture2D(); GlStateManager.disableBlend(); } - + public static void drawTexturedRect( - int x, int y, int textureX, int textureY, int width, int height, int zLevel) { + int x, int y, int textureX, int textureY, int width, int height, int zLevel) { Tessellator tessellator = Tessellator.getInstance(); BufferBuilder BufferBuilder = tessellator.getBuffer(); BufferBuilder.begin(7, DefaultVertexFormats.POSITION_TEX); BufferBuilder.pos((double) (x + 0), (double) (y + height), (double) zLevel) - .tex( - (double) ((float) (textureX + 0) * 0.00390625F), - (double) ((float) (textureY + height) * 0.00390625F)) - .endVertex(); + .tex( + (double) ((float) (textureX + 0) * 0.00390625F), + (double) ((float) (textureY + height) * 0.00390625F)) + .endVertex(); BufferBuilder.pos((double) (x + width), (double) (y + height), (double) zLevel) - .tex( - (double) ((float) (textureX + width) * 0.00390625F), - (double) ((float) (textureY + height) * 0.00390625F)) - .endVertex(); + .tex( + (double) ((float) (textureX + width) * 0.00390625F), + (double) ((float) (textureY + height) * 0.00390625F)) + .endVertex(); BufferBuilder.pos((double) (x + width), (double) (y + 0), (double) zLevel) - .tex( - (double) ((float) (textureX + width) * 0.00390625F), - (double) ((float) (textureY + 0) * 0.00390625F)) - .endVertex(); + .tex( + (double) ((float) (textureX + width) * 0.00390625F), + (double) ((float) (textureY + 0) * 0.00390625F)) + .endVertex(); BufferBuilder.pos((double) (x + 0), (double) (y + 0), (double) zLevel) - .tex( - (double) ((float) (textureX + 0) * 0.00390625F), - (double) ((float) (textureY + 0) * 0.00390625F)) - .endVertex(); + .tex( + (double) ((float) (textureX + 0) * 0.00390625F), + (double) ((float) (textureY + 0) * 0.00390625F)) + .endVertex(); tessellator.draw(); } - + public static void drawLine(int x1, int y1, int x2, int y2, int color, float width) { float r = (float) (color >> 16 & 255) / 255.0F; float g = (float) (color >> 8 & 255) / 255.0F; @@ -133,84 +142,84 @@ public static void drawLine(int x1, int y1, int x2, int y2, int color, float wid float a = (float) (color >> 24 & 255) / 255.0F; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder BufferBuilder = tessellator.getBuffer(); - + GlStateManager.enableBlend(); GlStateManager.disableTexture2D(); GlStateManager.tryBlendFuncSeparate( - GlStateManager.SourceFactor.SRC_ALPHA, - GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, - GlStateManager.SourceFactor.ONE, - GlStateManager.DestFactor.ZERO); + GlStateManager.SourceFactor.SRC_ALPHA, + GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, + GlStateManager.SourceFactor.ONE, + GlStateManager.DestFactor.ZERO); GlStateManager.color(r, g, b, a); - + GL11.glLineWidth(width); - + BufferBuilder.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION); BufferBuilder.pos((double) x1, (double) y1, 0.0D).endVertex(); BufferBuilder.pos((double) x2, (double) y2, 0.0D).endVertex(); tessellator.draw(); - + GlStateManager.color(1f, 1f, 1f); GlStateManager.enableTexture2D(); GlStateManager.disableBlend(); } - + public static void drawText(String msg, int x, int y, int color) { MC.fontRenderer.drawString(msg, x, y, color); } - + public static void drawTextShadow(String msg, int x, int y, int color) { MC.fontRenderer.drawStringWithShadow(msg, x, y, color); } - + public static void drawTextShadowCentered(String msg, float x, float y, int color) { float offsetX = getTextWidth(msg) / 2f; float offsetY = getTextHeight() / 2f; MC.fontRenderer.drawStringWithShadow(msg, x - offsetX, y - offsetY, color); } - + public static void drawText(String msg, int x, int y, int color, double scale, boolean shadow) { GlStateManager.pushMatrix(); GlStateManager.disableDepth(); GlStateManager.scale(scale, scale, scale); MC.fontRenderer.drawString( - msg, (int) (x * (1 / scale)), (int) (y * (1 / scale)), color, shadow); + msg, (int) (x * (1 / scale)), (int) (y * (1 / scale)), color, shadow); GlStateManager.enableDepth(); GlStateManager.popMatrix(); } - + public static void drawText(String msg, int x, int y, int color, double scale) { drawText(msg, x, y, color, scale, false); } - + public static void drawTextShadow(String msg, int x, int y, int color, double scale) { drawText(msg, x, y, color, scale, true); } - + public static int getTextWidth(String text, double scale) { return (int) (MC.fontRenderer.getStringWidth(text) * scale); } - + public static int getTextWidth(String text) { return getTextWidth(text, 1.D); } - + public static int getTextHeight() { return MC.fontRenderer.FONT_HEIGHT; } - + public static int getTextHeight(double scale) { return (int) (MC.fontRenderer.FONT_HEIGHT * scale); } - + public static void drawItem(ItemStack item, int x, int y) { MC.getRenderItem().renderItemAndEffectIntoGUI(item, x, y); } - + public static void drawItemOverlay(ItemStack stack, int x, int y) { MC.getRenderItem().renderItemOverlayIntoGUI(MC.fontRenderer, stack, x, y, null); } - + public static void drawItem(ItemStack item, double x, double y) { GlStateManager.pushMatrix(); RenderHelper.enableGUIStandardItemLighting(); @@ -226,7 +235,7 @@ public static void drawItem(ItemStack item, double x, double y) { GlStateManager.enableDepth(); GlStateManager.color(1.f, 1.f, 1.f, 1.f); } - + public static void drawItemWithOverlay(ItemStack item, double x, double y, double scale) { GlStateManager.pushMatrix(); RenderHelper.enableGUIStandardItemLighting(); @@ -243,7 +252,7 @@ public static void drawItemWithOverlay(ItemStack item, double x, double y, doubl GlStateManager.enableDepth(); GlStateManager.color(1.f, 1.f, 1.f, 1.f); } - + public static void drawPotionEffect(PotionEffect potion, int x, int y) { int index = potion.getPotion().getStatusIconIndex(); GlStateManager.pushMatrix(); @@ -262,26 +271,26 @@ public static void drawPotionEffect(PotionEffect potion, int x, int y) { GlStateManager.color(1.f, 1.f, 1.f, 1.f); GlStateManager.popMatrix(); } - + public static void drawHead(ResourceLocation skinResource, double x, double y, float scale) { GlStateManager.pushMatrix(); MC.renderEngine.bindTexture(skinResource); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.F); GlStateManager.scale(scale, scale, scale); drawScaledCustomSizeModalRect( - (x * (1 / scale)), (y * (1 / scale)), 8.0F, 8.0F, 8, 8, 12, 12, 64.0F, 64.0F); + (x * (1 / scale)), (y * (1 / scale)), 8.0F, 8.0F, 8, 8, 12, 12, 64.0F, 64.0F); drawScaledCustomSizeModalRect( - (x * (1 / scale)), (y * (1 / scale)), 40.0F, 8.0F, 8, 8, 12, 12, 64.0F, 64.0F); + (x * (1 / scale)), (y * (1 / scale)), 40.0F, 8.0F, 8, 8, 12, 12, 64.0F, 64.0F); GlStateManager.popMatrix(); } - + protected static void renderItemAndEffectIntoGUI( - @Nullable EntityLivingBase living, final ItemStack stack, double x, double y, double scale) { + @Nullable EntityLivingBase living, final ItemStack stack, double x, double y, double scale) { if (!stack.isEmpty()) { MC.getRenderItem().zLevel += 50.f; try { renderItemModelIntoGUI( - stack, x, y, MC.getRenderItem().getItemModelWithOverrides(stack, null, living), scale); + stack, x, y, MC.getRenderItem().getItemModelWithOverrides(stack, null, living), scale); } catch (Throwable t) { Helper.handleThrowable(t); } finally { @@ -289,33 +298,36 @@ protected static void renderItemAndEffectIntoGUI( } } } - + private static void renderItemModelIntoGUI( - ItemStack stack, double x, double y, IBakedModel bakedmodel, double scale) { + ItemStack stack, double x, double y, IBakedModel bakedmodel, double scale) { GlStateManager.pushMatrix(); MC.getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); MC.getTextureManager() - .getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE) - .setBlurMipmap(false, false); + .getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE) + .setBlurMipmap(false, false); GlStateManager.enableRescaleNormal(); GlStateManager.enableAlpha(); GlStateManager.alphaFunc(516, 0.1F); GlStateManager.enableBlend(); GlStateManager.blendFunc( - GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); + GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); - + GlStateManager.translate(x, y, 100.0F + MC.getRenderItem().zLevel); GlStateManager.translate(8.0F, 8.0F, 0.0F); GlStateManager.scale(1.0F, -1.0F, 1.0F); GlStateManager.scale(scale, scale, scale); - - if (bakedmodel.isGui3d()) GlStateManager.enableLighting(); - else GlStateManager.disableLighting(); - + + if (bakedmodel.isGui3d()) { + GlStateManager.enableLighting(); + } else { + GlStateManager.disableLighting(); + } + bakedmodel = - net.minecraftforge.client.ForgeHooksClient.handleCameraTransforms( - bakedmodel, ItemCameraTransforms.TransformType.GUI, false); + net.minecraftforge.client.ForgeHooksClient.handleCameraTransforms( + bakedmodel, ItemCameraTransforms.TransformType.GUI, false); MC.getRenderItem().renderItem(stack, bakedmodel); GlStateManager.disableAlpha(); GlStateManager.disableRescaleNormal(); @@ -324,16 +336,16 @@ private static void renderItemModelIntoGUI( MC.getTextureManager().bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); MC.getTextureManager().getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).restoreLastBlurMipmap(); } - + protected static void renderItemOverlayIntoGUI( - FontRenderer fr, - ItemStack stack, - double xPosition, - double yPosition, - @Nullable String text, - double scale) { + FontRenderer fr, + ItemStack stack, + double xPosition, + double yPosition, + @Nullable String text, + double scale) { final double SCALE_RATIO = 1.23076923077D; - + if (!stack.isEmpty()) { if (stack.getCount() != 1 || text != null) { String s = text == null ? String.valueOf(stack.getCount()) : text; @@ -341,17 +353,17 @@ protected static void renderItemOverlayIntoGUI( GlStateManager.disableDepth(); GlStateManager.disableBlend(); fr.drawStringWithShadow( - s, - (float) (xPosition + 19 - 2 - fr.getStringWidth(s)), - (float) (yPosition + 6 + 3), - 16777215); + s, + (float) (xPosition + 19 - 2 - fr.getStringWidth(s)), + (float) (yPosition + 6 + 3), + 16777215); GlStateManager.enableLighting(); GlStateManager.enableDepth(); // Fixes opaque cooldown overlay a bit lower // TODO: check if enabled blending still screws things up down the line. GlStateManager.enableBlend(); } - + if (stack.getItem().showDurabilityBar(stack)) { GlStateManager.disableLighting(); GlStateManager.disableDepth(); @@ -364,29 +376,29 @@ protected static void renderItemOverlayIntoGUI( int j = rgbfordisplay; draw(xPosition + (scale / 8.D), yPosition + (scale / SCALE_RATIO), 13, 2, 0, 0, 0, 255); draw( - xPosition + (scale / 8.D), - yPosition + (scale / SCALE_RATIO), - i, - 1, - j >> 16 & 255, - j >> 8 & 255, - j & 255, - 255); + xPosition + (scale / 8.D), + yPosition + (scale / SCALE_RATIO), + i, + 1, + j >> 16 & 255, + j >> 8 & 255, + j & 255, + 255); GlStateManager.enableBlend(); GlStateManager.enableAlpha(); GlStateManager.enableTexture2D(); GlStateManager.enableLighting(); GlStateManager.enableDepth(); } - + EntityPlayerSP entityplayersp = Minecraft.getMinecraft().player; float f3 = - entityplayersp == null - ? 0.0F - : entityplayersp - .getCooldownTracker() - .getCooldown(stack.getItem(), Minecraft.getMinecraft().getRenderPartialTicks()); - + entityplayersp == null + ? 0.0F + : entityplayersp + .getCooldownTracker() + .getCooldown(stack.getItem(), Minecraft.getMinecraft().getRenderPartialTicks()); + if (f3 > 0.0F) { GlStateManager.disableLighting(); GlStateManager.disableDepth(); @@ -398,78 +410,78 @@ protected static void renderItemOverlayIntoGUI( } } } - + private static void draw( - double x, double y, double width, double height, int red, int green, int blue, int alpha) { + double x, double y, double width, double height, int red, int green, int blue, int alpha) { Tessellator tessellator = Tessellator.getInstance(); BufferBuilder renderer = tessellator.getBuffer(); renderer.begin(7, DefaultVertexFormats.POSITION_COLOR); renderer - .pos((double) (x + 0), (double) (y + 0), 0.0D) - .color(red, green, blue, alpha) - .endVertex(); + .pos((double) (x + 0), (double) (y + 0), 0.0D) + .color(red, green, blue, alpha) + .endVertex(); renderer - .pos((double) (x + 0), (double) (y + height), 0.0D) - .color(red, green, blue, alpha) - .endVertex(); + .pos((double) (x + 0), (double) (y + height), 0.0D) + .color(red, green, blue, alpha) + .endVertex(); renderer - .pos((double) (x + width), (double) (y + height), 0.0D) - .color(red, green, blue, alpha) - .endVertex(); + .pos((double) (x + width), (double) (y + height), 0.0D) + .color(red, green, blue, alpha) + .endVertex(); renderer - .pos((double) (x + width), (double) (y + 0), 0.0D) - .color(red, green, blue, alpha) - .endVertex(); + .pos((double) (x + width), (double) (y + 0), 0.0D) + .color(red, green, blue, alpha) + .endVertex(); Tessellator.getInstance().draw(); } - + protected static void drawScaledCustomSizeModalRect( - double x, - double y, - float u, - float v, - double uWidth, - double vHeight, - double width, - double height, - double tileWidth, - double tileHeight) { + double x, + double y, + float u, + float v, + double uWidth, + double vHeight, + double width, + double height, + double tileWidth, + double tileHeight) { double f = 1.0F / tileWidth; double f1 = 1.0F / tileHeight; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder bufferbuilder = tessellator.getBuffer(); bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX); bufferbuilder - .pos((double) x, (double) (y + height), 0.0D) - .tex((double) (u * f), (double) ((v + (float) vHeight) * f1)) - .endVertex(); + .pos((double) x, (double) (y + height), 0.0D) + .tex((double) (u * f), (double) ((v + (float) vHeight) * f1)) + .endVertex(); bufferbuilder - .pos((double) (x + width), (double) (y + height), 0.0D) - .tex((double) ((u + (float) uWidth) * f), (double) ((v + (float) vHeight) * f1)) - .endVertex(); + .pos((double) (x + width), (double) (y + height), 0.0D) + .tex((double) ((u + (float) uWidth) * f), (double) ((v + (float) vHeight) * f1)) + .endVertex(); bufferbuilder - .pos((double) (x + width), (double) y, 0.0D) - .tex((double) ((u + (float) uWidth) * f), (double) (v * f1)) - .endVertex(); + .pos((double) (x + width), (double) y, 0.0D) + .tex((double) ((u + (float) uWidth) * f), (double) (v * f1)) + .endVertex(); bufferbuilder - .pos((double) x, (double) y, 0.0D) - .tex((double) (u * f), (double) (v * f1)) - .endVertex(); + .pos((double) x, (double) y, 0.0D) + .tex((double) (u * f), (double) (v * f1)) + .endVertex(); tessellator.draw(); } - + public static int getHeadWidth(float scale) { return (int) (scale * 12); } - + public static int getHeadWidth() { return getHeadWidth(1.f); } - + public static int getHeadHeight(float scale) { return (int) (scale * 12); } - + public static int getHeadHeight() { return getHeadWidth(1.f); } diff --git a/src/main/java/uk/co/hexeption/thx/ttf/CFont.java b/src/main/java/com/matt/forgehax/util/draw/font/CFont.java similarity index 79% rename from src/main/java/uk/co/hexeption/thx/ttf/CFont.java rename to src/main/java/com/matt/forgehax/util/draw/font/CFont.java index f9066256d..50966a4a0 100644 --- a/src/main/java/uk/co/hexeption/thx/ttf/CFont.java +++ b/src/main/java/com/matt/forgehax/util/draw/font/CFont.java @@ -1,4 +1,4 @@ -package uk.co.hexeption.thx.ttf; +package com.matt.forgehax.util.draw.font; /* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE @@ -16,15 +16,22 @@ 0. You just DO WHAT THE FUCK YOU WANT TO. */ -/** Created by Hexeption on 18/12/2016. */ +/** + * Created by Hexeption on 18/12/2016. + */ -import java.awt.*; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import net.minecraft.client.renderer.texture.DynamicTexture; import org.lwjgl.opengl.GL11; public class CFont { + private float imgSize = 512; protected CharData[] charData = new CharData[256]; protected Font font; @@ -33,29 +40,29 @@ public class CFont { protected int fontHeight = -1; protected int charOffset = 0; protected DynamicTexture tex; - + public CFont(Font font, boolean antiAlias, boolean fractionalMetrics) { this.font = font; this.antiAlias = antiAlias; this.fractionalMetrics = fractionalMetrics; tex = setupTexture(font, antiAlias, fractionalMetrics, this.charData); } - + protected DynamicTexture setupTexture( - Font font, boolean antiAlias, boolean fractionalMetrics, CharData[] chars) { + Font font, boolean antiAlias, boolean fractionalMetrics, CharData[] chars) { BufferedImage img = generateFontImage(font, antiAlias, fractionalMetrics, chars); - + try { return new DynamicTexture(img); } catch (Exception e) { e.printStackTrace(); } - + return null; } - + protected BufferedImage generateFontImage( - Font font, boolean antiAlias, boolean fractionalMetrics, CharData[] chars) { + Font font, boolean antiAlias, boolean fractionalMetrics, CharData[] chars) { int imgSize = (int) this.imgSize; BufferedImage bufferedImage = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D) bufferedImage.getGraphics(); @@ -64,81 +71,81 @@ protected BufferedImage generateFontImage( g.fillRect(0, 0, imgSize, imgSize); g.setColor(Color.WHITE); g.setRenderingHint( - RenderingHints.KEY_FRACTIONALMETRICS, - fractionalMetrics - ? RenderingHints.VALUE_FRACTIONALMETRICS_ON - : RenderingHints.VALUE_FRACTIONALMETRICS_OFF); + RenderingHints.KEY_FRACTIONALMETRICS, + fractionalMetrics + ? RenderingHints.VALUE_FRACTIONALMETRICS_ON + : RenderingHints.VALUE_FRACTIONALMETRICS_OFF); g.setRenderingHint( - RenderingHints.KEY_TEXT_ANTIALIASING, - antiAlias - ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON - : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + RenderingHints.KEY_TEXT_ANTIALIASING, + antiAlias + ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON + : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); g.setRenderingHint( - RenderingHints.KEY_ANTIALIASING, - antiAlias ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); + RenderingHints.KEY_ANTIALIASING, + antiAlias ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); FontMetrics fontMetrics = g.getFontMetrics(); int charHeight = 0; int positionX = 0; int positionY = 1; - + for (int i = 0; i < chars.length; i++) { char ch = (char) i; CharData charData = new CharData(); Rectangle2D dimensions = fontMetrics.getStringBounds(String.valueOf(ch), g); charData.width = (dimensions.getBounds().width + 8); charData.height = dimensions.getBounds().height; - + if (positionX + charData.width >= imgSize) { positionX = 0; positionY += charHeight; charHeight = 0; } - + if (charData.height > charHeight) { charHeight = charData.height; } - + charData.storedX = positionX; charData.storedY = positionY; - + if (charData.height > this.fontHeight) { this.fontHeight = charData.height; } - + chars[i] = charData; g.drawString(String.valueOf(ch), positionX + 2, positionY + fontMetrics.getAscent()); positionX += charData.width; } - + return bufferedImage; } - + public void drawChar(CharData[] chars, char c, float x, float y) - throws ArrayIndexOutOfBoundsException { + throws ArrayIndexOutOfBoundsException { try { drawQuad( - x, - y, - chars[c].width, - chars[c].height, - chars[c].storedX, - chars[c].storedY, - chars[c].width, - chars[c].height); + x, + y, + chars[c].width, + chars[c].height, + chars[c].storedX, + chars[c].storedY, + chars[c].width, + chars[c].height); } catch (Exception e) { e.printStackTrace(); } } - + protected void drawQuad( - float x, - float y, - float width, - float height, - float srcX, - float srcY, - float srcWidth, - float srcHeight) { + float x, + float y, + float width, + float height, + float srcX, + float srcY, + float srcWidth, + float srcHeight) { float renderSRCX = srcX / imgSize; float renderSRCY = srcY / imgSize; float renderSRCWidth = srcWidth / imgSize; @@ -156,64 +163,66 @@ protected void drawQuad( GL11.glTexCoord2f(renderSRCX + renderSRCWidth, renderSRCY); GL11.glVertex2d(x + width, y); } - + public int getStringHeight(String text) { return getHeight(); } - + public int getHeight() { return (this.fontHeight - 8) / 2; } - + public int getStringWidth(String text) { int width = 0; - + for (char c : text.toCharArray()) { if ((c < this.charData.length) && (c >= 0)) { width += this.charData[c].width - 8 + this.charOffset; } } - + return width / 2; } - + public boolean isAntiAlias() { return this.antiAlias; } - + public void setAntiAlias(boolean antiAlias) { if (this.antiAlias != antiAlias) { this.antiAlias = antiAlias; tex = setupTexture(this.font, antiAlias, this.fractionalMetrics, this.charData); } } - + public boolean isFractionalMetrics() { return this.fractionalMetrics; } - + public void setFractionalMetrics(boolean fractionalMetrics) { if (this.fractionalMetrics != fractionalMetrics) { this.fractionalMetrics = fractionalMetrics; tex = setupTexture(this.font, this.antiAlias, fractionalMetrics, this.charData); } } - + public Font getFont() { return this.font; } - + public void setFont(Font font) { this.font = font; tex = setupTexture(font, this.antiAlias, this.fractionalMetrics, this.charData); } - + protected class CharData { + public int width; public int height; public int storedX; public int storedY; - - protected CharData() {} + + protected CharData() { + } } } diff --git a/src/main/java/com/matt/forgehax/util/draw/font/Fonts.java b/src/main/java/com/matt/forgehax/util/draw/font/Fonts.java new file mode 100644 index 000000000..ef84f238b --- /dev/null +++ b/src/main/java/com/matt/forgehax/util/draw/font/Fonts.java @@ -0,0 +1,16 @@ +package com.matt.forgehax.util.draw.font; + +import java.awt.Font; + +/** + * Created on 9/2/2017 by fr1kin + */ +public interface Fonts { + + MinecraftFontRenderer ARIAL = new MinecraftFontRenderer( + new Font("Arial", Font.PLAIN, 18), true, true); + MinecraftFontRenderer CAMBRIA = new MinecraftFontRenderer( + new Font("Cambria", Font.PLAIN, 18), true, true); + MinecraftFontRenderer GEORGIA = new MinecraftFontRenderer( + new Font("Georgia", Font.PLAIN, 18), true, true); +} diff --git a/src/main/java/uk/co/hexeption/thx/ttf/MinecraftFontRenderer.java b/src/main/java/com/matt/forgehax/util/draw/font/MinecraftFontRenderer.java similarity index 85% rename from src/main/java/uk/co/hexeption/thx/ttf/MinecraftFontRenderer.java rename to src/main/java/com/matt/forgehax/util/draw/font/MinecraftFontRenderer.java index 30614b094..125862b36 100644 --- a/src/main/java/uk/co/hexeption/thx/ttf/MinecraftFontRenderer.java +++ b/src/main/java/com/matt/forgehax/util/draw/font/MinecraftFontRenderer.java @@ -1,4 +1,4 @@ -package uk.co.hexeption.thx.ttf; +package com.matt.forgehax.util.draw.font; /* DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE @@ -16,9 +16,11 @@ 0. You just DO WHAT THE FUCK YOU WANT TO. */ -/** Created by Hexeption on 18/12/2016. */ +/** + * Created by Hexeption on 18/12/2016. + */ -import java.awt.*; +import java.awt.Font; import java.util.ArrayList; import java.util.List; import net.minecraft.client.renderer.GlStateManager; @@ -26,57 +28,58 @@ import org.lwjgl.opengl.GL11; public class MinecraftFontRenderer extends CFont { + protected CFont.CharData[] boldChars = new CFont.CharData[256]; protected CFont.CharData[] italicChars = new CFont.CharData[256]; protected CFont.CharData[] boldItalicChars = new CFont.CharData[256]; - + private final int[] colorCode = new int[32]; private final String colorcodeIdentifiers = "0123456789abcdefklmnor"; - + public MinecraftFontRenderer(Font font, boolean antiAlias, boolean fractionalMetrics) { super(font, antiAlias, fractionalMetrics); setupMinecraftColorcodes(); setupBoldItalicIDs(); } - + public float drawStringWithShadow(String text, double x, double y, int color) { float shadowWidth = drawString(text, x + 1.0D, y + 1.0D, color, true); return Math.max(shadowWidth, drawString(text, x, y, color, false)); } - + public float drawString(String text, float x, float y, int color) { return drawString(text, x, y, color, false); } - + public float drawCenteredString(String text, float x, float y, int color) { return drawString(text, x - getStringWidth(text) / 2, y, color); } - + public float drawCenteredStringWithShadow(String text, float x, float y, int color) { float shadowWidth = - drawString(text, x - getStringWidth(text) / 2 + 1.0D, y + 1.0D, color, true); + drawString(text, x - getStringWidth(text) / 2 + 1.0D, y + 1.0D, color, true); return drawString(text, x - getStringWidth(text) / 2, y, color); } - + public float drawString(String text, double x, double y, int color, boolean shadow) { x -= 1; - + if (text == null) { return 0.0F; } - + if (color == 553648127) { color = 16777215; } - + if ((color & 0xFC000000) == 0) { color |= -16777216; } - + if (shadow) { color = (color & 0xFCFCFC) >> 2 | color & 0xFF000000; } - + CFont.CharData[] currentData = this.charData; float alpha = (color >> 24 & 0xFF) / 255.0F; boolean randomCase = false; @@ -87,35 +90,35 @@ public float drawString(String text, double x, double y, int color, boolean shad boolean render = true; x *= 2.0D; y = (y - 3.0D) * 2.0D; - + if (render) { GL11.glPushMatrix(); GlStateManager.scale(0.5D, 0.5D, 0.5D); GlStateManager.enableBlend(); GlStateManager.blendFunc(770, 771); GlStateManager.color( - (color >> 16 & 0xFF) / 255.0F, - (color >> 8 & 0xFF) / 255.0F, - (color & 0xFF) / 255.0F, - alpha); + (color >> 16 & 0xFF) / 255.0F, + (color >> 8 & 0xFF) / 255.0F, + (color & 0xFF) / 255.0F, + alpha); int size = text.length(); GlStateManager.enableTexture2D(); GlStateManager.bindTexture(tex.getGlTextureId()); - + GL11.glBindTexture(GL11.GL_TEXTURE_2D, tex.getGlTextureId()); - + for (int i = 0; i < size; i++) { char character = text.charAt(i); - + if ((character == '\u00a7') && (i < size)) { int colorIndex = 21; - + try { colorIndex = "0123456789abcdefklmnor".indexOf(text.charAt(i + 1)); } catch (Exception e) { e.printStackTrace(); } - + if (colorIndex < 16) { bold = false; italic = false; @@ -126,26 +129,26 @@ public float drawString(String text, double x, double y, int color, boolean shad // GL11.glBindTexture(GL11.GL_TEXTURE_2D, // tex.getGlTextureId()); currentData = this.charData; - + if ((colorIndex < 0) || (colorIndex > 15)) { colorIndex = 15; } - + if (shadow) { colorIndex += 16; } - + int colorcode = this.colorCode[colorIndex]; GlStateManager.color( - (colorcode >> 16 & 0xFF) / 255.0F, - (colorcode >> 8 & 0xFF) / 255.0F, - (colorcode & 0xFF) / 255.0F, - alpha); + (colorcode >> 16 & 0xFF) / 255.0F, + (colorcode >> 8 & 0xFF) / 255.0F, + (colorcode & 0xFF) / 255.0F, + alpha); } else if (colorIndex == 16) { randomCase = true; } else if (colorIndex == 17) { bold = true; - + if (italic) { GlStateManager.bindTexture(texItalicBold.getGlTextureId()); // GL11.glBindTexture(GL11.GL_TEXTURE_2D, @@ -163,7 +166,7 @@ public float drawString(String text, double x, double y, int color, boolean shad underline = true; } else if (colorIndex == 20) { italic = true; - + if (bold) { GlStateManager.bindTexture(texItalicBold.getGlTextureId()); // GL11.glBindTexture(GL11.GL_TEXTURE_2D, @@ -182,75 +185,75 @@ public float drawString(String text, double x, double y, int color, boolean shad underline = false; strikethrough = false; GlStateManager.color( - (color >> 16 & 0xFF) / 255.0F, - (color >> 8 & 0xFF) / 255.0F, - (color & 0xFF) / 255.0F, - alpha); + (color >> 16 & 0xFF) / 255.0F, + (color >> 8 & 0xFF) / 255.0F, + (color & 0xFF) / 255.0F, + alpha); GlStateManager.bindTexture(tex.getGlTextureId()); // GL11.glBindTexture(GL11.GL_TEXTURE_2D, // tex.getGlTextureId()); currentData = this.charData; } - + i++; } else if ((character < currentData.length) && (character >= 0)) { GL11.glBegin(GL11.GL_TRIANGLES); drawChar(currentData, character, (float) x, (float) y); GL11.glEnd(); - + if (strikethrough) { drawLine( - x, - y + currentData[character].height / 2, - x + currentData[character].width - 8.0D, - y + currentData[character].height / 2, - 1.0F); + x, + y + currentData[character].height / 2, + x + currentData[character].width - 8.0D, + y + currentData[character].height / 2, + 1.0F); } - + if (underline) { drawLine( - x, - y + currentData[character].height - 2.0D, - x + currentData[character].width - 8.0D, - y + currentData[character].height - 2.0D, - 1.0F); + x, + y + currentData[character].height - 2.0D, + x + currentData[character].width - 8.0D, + y + currentData[character].height - 2.0D, + 1.0F); } - + x += currentData[character].width - 8 + this.charOffset; } } - + GL11.glHint(GL11.GL_POLYGON_SMOOTH_HINT, GL11.GL_DONT_CARE); GL11.glPopMatrix(); } - + return (float) x / 2.0F; } - + @Override public int getStringWidth(String text) { if (text == null) { return 0; } - + int width = 0; CFont.CharData[] currentData = this.charData; boolean bold = false; boolean italic = false; int size = text.length(); - + for (int i = 0; i < size; i++) { char character = text.charAt(i); - + if ((character == '\u00a7') && (i < size)) { int colorIndex = "0123456789abcdefklmnor".indexOf(character); - + if (colorIndex < 16) { bold = false; italic = false; } else if (colorIndex == 17) { bold = true; - + if (italic) { currentData = this.boldItalicChars; } else { @@ -258,7 +261,7 @@ public int getStringWidth(String text) { } } else if (colorIndex == 20) { italic = true; - + if (bold) { currentData = this.boldItalicChars; } else { @@ -269,47 +272,47 @@ public int getStringWidth(String text) { italic = false; currentData = this.charData; } - + i++; } else if ((character < currentData.length) && (character >= 0)) { width += currentData[character].width - 8 + this.charOffset; } } - + return width / 2; } - + public void setFont(Font font) { super.setFont(font); setupBoldItalicIDs(); } - + public void setAntiAlias(boolean antiAlias) { super.setAntiAlias(antiAlias); setupBoldItalicIDs(); } - + public void setFractionalMetrics(boolean fractionalMetrics) { super.setFractionalMetrics(fractionalMetrics); setupBoldItalicIDs(); } - + protected DynamicTexture texBold; protected DynamicTexture texItalic; protected DynamicTexture texItalicBold; - + private void setupBoldItalicIDs() { texBold = - setupTexture( - this.font.deriveFont(1), this.antiAlias, this.fractionalMetrics, this.boldChars); + setupTexture( + this.font.deriveFont(1), this.antiAlias, this.fractionalMetrics, this.boldChars); texItalic = - setupTexture( - this.font.deriveFont(2), this.antiAlias, this.fractionalMetrics, this.italicChars); + setupTexture( + this.font.deriveFont(2), this.antiAlias, this.fractionalMetrics, this.italicChars); texItalicBold = - setupTexture( - this.font.deriveFont(3), this.antiAlias, this.fractionalMetrics, this.boldItalicChars); + setupTexture( + this.font.deriveFont(3), this.antiAlias, this.fractionalMetrics, this.boldItalicChars); } - + private void drawLine(double x, double y, double x1, double y1, float width) { GL11.glDisable(GL11.GL_TEXTURE_2D); GL11.glLineWidth(width); @@ -319,24 +322,24 @@ private void drawLine(double x, double y, double x1, double y1, float width) { GL11.glEnd(); GL11.glEnable(GL11.GL_TEXTURE_2D); } - + public List wrapWords(String text, double width) { List finalWords = new ArrayList(); - + if (getStringWidth(text) > width) { String[] words = text.split(" "); String currentWord = ""; char lastColorCode = 65535; - + for (String word : words) { for (int i = 0; i < word.toCharArray().length; i++) { char c = word.toCharArray()[i]; - + if ((c == '\u00a7') && (i < word.toCharArray().length - 1)) { lastColorCode = word.toCharArray()[(i + 1)]; } } - + if (getStringWidth(currentWord + word + " ") < width) { currentWord = currentWord + word + " "; } else { @@ -344,8 +347,8 @@ public List wrapWords(String text, double width) { currentWord = "\u00a7" + lastColorCode + word + " "; } } - - if (currentWord.length() > 0) + + if (currentWord.length() > 0) { if (getStringWidth(currentWord) < width) { finalWords.add("\u00a7" + lastColorCode + currentWord + " "); currentWord = ""; @@ -354,26 +357,27 @@ public List wrapWords(String text, double width) { finalWords.add(s); } } + } } else { finalWords.add(text); } - + return finalWords; } - + public List formatString(String string, double width) { List finalWords = new ArrayList(); String currentWord = ""; char lastColorCode = 65535; char[] chars = string.toCharArray(); - + for (int i = 0; i < chars.length; i++) { char c = chars[i]; - + if ((c == '\u00a7') && (i < chars.length - 1)) { lastColorCode = chars[(i + 1)]; } - + if (getStringWidth(currentWord + c) < width) { currentWord = currentWord + c; } else { @@ -381,31 +385,31 @@ public List formatString(String string, double width) { currentWord = "\u00a7" + lastColorCode + String.valueOf(c); } } - + if (currentWord.length() > 0) { finalWords.add(currentWord); } - + return finalWords; } - + private void setupMinecraftColorcodes() { for (int index = 0; index < 32; index++) { int noClue = (index >> 3 & 0x1) * 85; int red = (index >> 2 & 0x1) * 170 + noClue; int green = (index >> 1 & 0x1) * 170 + noClue; int blue = (index >> 0 & 0x1) * 170 + noClue; - + if (index == 6) { red += 85; } - + if (index >= 16) { red /= 4; green /= 4; blue /= 4; } - + this.colorCode[index] = ((red & 0xFF) << 16 | (green & 0xFF) << 8 | blue & 0xFF); } } diff --git a/src/main/java/com/matt/forgehax/util/entity/EnchantmentUtils.java b/src/main/java/com/matt/forgehax/util/entity/EnchantmentUtils.java index 1124fc816..d911c36ea 100644 --- a/src/main/java/com/matt/forgehax/util/entity/EnchantmentUtils.java +++ b/src/main/java/com/matt/forgehax/util/entity/EnchantmentUtils.java @@ -10,36 +10,48 @@ import net.minecraft.nbt.NBTTagList; public class EnchantmentUtils { + public static List getEnchantments(NBTTagList tags) { - if (tags == null) return null; + if (tags == null) { + return null; + } List list = Lists.newArrayList(); - for (int i = 0; i < tags.tagCount(); i++) + for (int i = 0; i < tags.tagCount(); i++) { list.add( - new EntityEnchantment( - tags.getCompoundTagAt(i).getShort("id"), tags.getCompoundTagAt(i).getShort("lvl"))); + new EntityEnchantment( + tags.getCompoundTagAt(i).getShort("id"), tags.getCompoundTagAt(i).getShort("lvl"))); + } return list; } public static List getEnchantmentsSorted(NBTTagList tags) { List list = getEnchantments(tags); - if (list != null) Collections.sort(list, new EnchantSort()); + if (list != null) { + Collections.sort(list, new EnchantSort()); + } return list; } // IV.sort(III) public static class EnchantSort implements Comparator { + @Override public int compare(EntityEnchantment o1, EntityEnchantment o2) { int deltaEch1 = o1.getEnchantment().getMaxLevel() - o1.getEnchantment().getMinLevel(); int deltaEch2 = o2.getEnchantment().getMaxLevel() - o2.getEnchantment().getMinLevel(); - if (deltaEch1 == deltaEch2) return 0; - else if (deltaEch1 < deltaEch2) return 1; - else return -1; + if (deltaEch1 == deltaEch2) { + return 0; + } else if (deltaEch1 < deltaEch2) { + return 1; + } else { + return -1; + } } } public static class EntityEnchantment { + private static final Map SHORT_ENCHANT_NAMES = Maps.newHashMap(); static { @@ -95,9 +107,14 @@ public int getLevel() { public String getShortName() { int id = Enchantment.getEnchantmentID(enchantment); if (SHORT_ENCHANT_NAMES.containsKey(id)) { - if (enchantment.getMaxLevel() <= 1) return SHORT_ENCHANT_NAMES.get(id); - else return SHORT_ENCHANT_NAMES.get(id) + this.level; - } else return toString(); + if (enchantment.getMaxLevel() <= 1) { + return SHORT_ENCHANT_NAMES.get(id); + } else { + return SHORT_ENCHANT_NAMES.get(id) + this.level; + } + } else { + return toString(); + } } public String toString() { diff --git a/src/main/java/com/matt/forgehax/util/entity/EntityUtils.java b/src/main/java/com/matt/forgehax/util/entity/EntityUtils.java index 8a7d98a8f..f9c1999fd 100644 --- a/src/main/java/com/matt/forgehax/util/entity/EntityUtils.java +++ b/src/main/java/com/matt/forgehax/util/entity/EntityUtils.java @@ -6,7 +6,7 @@ import com.matt.forgehax.Globals; import com.matt.forgehax.asm.reflection.FastReflection; -import com.matt.forgehax.util.Utils; +import com.matt.forgehax.util.color.Colors; import com.matt.forgehax.util.entity.mobtypes.MobType; import com.matt.forgehax.util.entity.mobtypes.MobTypeEnum; import com.matt.forgehax.util.entity.mobtypes.MobTypeRegistry; @@ -23,25 +23,38 @@ import net.minecraft.entity.passive.EntityVillager; import net.minecraft.entity.passive.EntityWolf; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.util.math.*; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; public class EntityUtils implements Globals { + public static MobTypeEnum getRelationship(Entity entity) { - if (entity instanceof AbstractClientPlayer) return MobTypeEnum.PLAYER; - else { + if (entity instanceof AbstractClientPlayer) { + return MobTypeEnum.PLAYER; + } else { // check special cases first - for (MobType type : MobTypeRegistry.getSortedSpecialMobTypes()) - if (type.isMobType(entity)) return type.getMobType(entity); + for (MobType type : MobTypeRegistry.getSortedSpecialMobTypes()) { + if (type.isMobType(entity)) { + return type.getMobType(entity); + } + } // this code will continue if no special was found - if (MobTypeRegistry.HOSTILE.isMobType(entity)) return MobTypeEnum.HOSTILE; - else if (MobTypeRegistry.FRIENDLY.isMobType(entity)) return MobTypeEnum.FRIENDLY; - else return MobTypeEnum.HOSTILE; // default to hostile + if (MobTypeRegistry.HOSTILE.isMobType(entity)) { + return MobTypeEnum.HOSTILE; + } else if (MobTypeRegistry.FRIENDLY.isMobType(entity)) { + return MobTypeEnum.FRIENDLY; + } else { + return MobTypeEnum.HOSTILE; // default to hostile + } } } - + public static boolean isBatsDisabled = false; - + /** * Checks if the mob could be possibly hostile towards us (we can't detect their attack target * easily) Current entities: PigZombie: Aggressive if arms are raised, when arms are put down a @@ -65,178 +78,217 @@ public static boolean isMobAggressive(Entity entity) { } return false; } - - /** Check if the mob is an instance of EntityLivingBase */ + + /** + * Check if the mob is an instance of EntityLivingBase + */ public static boolean isLiving(Entity entity) { return entity instanceof EntityLivingBase; } - - /** If the entity is a player */ + + /** + * If the entity is a player + */ public static boolean isPlayer(Entity entity) { return entity instanceof EntityPlayer; } - + public static boolean isLocalPlayer(Entity entity) { return Objects.equals(getLocalPlayer(), entity); } - + public static boolean isFakeLocalPlayer(Entity entity) { return entity != null && entity.getEntityId() == -100; } - + public static boolean isValidEntity(Entity entity) { Entity riding = getLocalPlayer().getRidingEntity(); return entity.ticksExisted > 1 - && !isFakeLocalPlayer(entity) - && (riding == null || !riding.equals(entity)); + && !isFakeLocalPlayer(entity) + && (riding == null || !riding.equals(entity)); } - + public static boolean isAlive(Entity entity) { return isLiving(entity) && !entity.isDead && ((EntityLivingBase) (entity)).getHealth() > 0; } - - /** If the mob by default wont attack the player, but will if the player attacks it */ + + /** + * If the mob by default wont attack the player, but will if the player attacks it + */ public static boolean isNeutralMob(Entity entity) { return entity instanceof EntityPigZombie - || entity instanceof EntityWolf - || entity instanceof EntityEnderman; + || entity instanceof EntityWolf + || entity instanceof EntityEnderman; } - - /** If the mob is friendly (not aggressive) */ + + /** + * If the mob is friendly (not aggressive) + */ public static boolean isFriendlyMob(Entity entity) { return (entity.isCreatureType(EnumCreatureType.CREATURE, false) - && !EntityUtils.isNeutralMob(entity)) - || (entity.isCreatureType(EnumCreatureType.AMBIENT, false) && !isBatsDisabled) - || entity instanceof EntityVillager - || entity instanceof EntityIronGolem - || (isNeutralMob(entity) && !EntityUtils.isMobAggressive(entity)); + && !EntityUtils.isNeutralMob(entity)) + || (entity.isCreatureType(EnumCreatureType.AMBIENT, false) && !isBatsDisabled) + || entity instanceof EntityVillager + || entity instanceof EntityIronGolem + || (isNeutralMob(entity) && !EntityUtils.isMobAggressive(entity)); } - - /** If the mob is hostile */ + + /** + * If the mob is hostile + */ public static boolean isHostileMob(Entity entity) { return (entity.isCreatureType(EnumCreatureType.MONSTER, false) - && !EntityUtils.isNeutralMob(entity)) - || EntityUtils.isMobAggressive(entity); + && !EntityUtils.isNeutralMob(entity)) + || EntityUtils.isMobAggressive(entity); } - - /** Find the entities interpolated amount */ + + /** + * Find the entities interpolated amount + */ public static Vec3d getInterpolatedAmount(Entity entity, double x, double y, double z) { return new Vec3d( - (entity.posX - entity.lastTickPosX) * x, - (entity.posY - entity.lastTickPosY) * y, - (entity.posZ - entity.lastTickPosZ) * z); + (entity.posX - entity.lastTickPosX) * x, + (entity.posY - entity.lastTickPosY) * y, + (entity.posZ - entity.lastTickPosZ) * z); } - + public static Vec3d getInterpolatedAmount(Entity entity, Vec3d vec) { return getInterpolatedAmount(entity, vec.x, vec.y, vec.z); } - + public static Vec3d getInterpolatedAmount(Entity entity, double ticks) { return getInterpolatedAmount(entity, ticks, ticks, ticks); } - - /** Find the entities interpolated position */ + + /** + * Find the entities interpolated position + */ public static Vec3d getInterpolatedPos(Entity entity, double ticks) { return new Vec3d(entity.lastTickPosX, entity.lastTickPosY, entity.lastTickPosZ) - .add(getInterpolatedAmount(entity, ticks)); + .add(getInterpolatedAmount(entity, ticks)); } - - /** Find the entities interpolated eye position */ + + /** + * Find the entities interpolated eye position + */ public static Vec3d getInterpolatedEyePos(Entity entity, double ticks) { return getInterpolatedPos(entity, ticks).addVector(0, entity.getEyeHeight(), 0); } - - /** Get entities eye position */ + + /** + * Get entities eye position + */ public static Vec3d getEyePos(Entity entity) { return new Vec3d(entity.posX, entity.posY + entity.getEyeHeight(), entity.posZ); } - - /** Find the center of the entities hit box */ + + /** + * Find the center of the entities hit box + */ public static Vec3d getOBBCenter(Entity entity) { AxisAlignedBB obb = entity.getEntityBoundingBox(); return new Vec3d( - (obb.maxX + obb.minX) / 2.D, (obb.maxY + obb.minY) / 2.D, (obb.maxZ + obb.minZ) / 2.D); + (obb.maxX + obb.minX) / 2.D, (obb.maxY + obb.minY) / 2.D, (obb.maxZ + obb.minZ) / 2.D); } - - /** Create a trace */ + + /** + * Create a trace + */ public static RayTraceResult traceEntity( - World world, Vec3d start, Vec3d end, List filter) { + World world, Vec3d start, Vec3d end, List filter) { RayTraceResult result = null; double hitDistance = -1; - + for (Entity ent : world.loadedEntityList) { - - if (filter.contains(ent)) continue; - + + if (filter.contains(ent)) { + continue; + } + double distance = start.distanceTo(ent.getPositionVector()); RayTraceResult trace = ent.getEntityBoundingBox().calculateIntercept(start, end); - + if (trace != null && (hitDistance == -1 || distance < hitDistance)) { hitDistance = distance; result = trace; result.entityHit = ent; } } - + return result; } - - /** Find the entities draw color */ + + /** + * Find the entities draw color + */ public static int getDrawColor(EntityLivingBase living) { if (isPlayer(living)) { - if (PlayerUtils.isFriend((EntityPlayer) living)) return Utils.Colors.GREEN; - else return Utils.Colors.RED; + if (PlayerUtils.isFriend((EntityPlayer) living)) { + return Colors.GREEN.toBuffer(); + } else { + return Colors.RED.toBuffer(); + } } else if (isHostileMob(living)) { - return Utils.Colors.ORANGE; + return Colors.ORANGE.toBuffer(); } else if (isFriendlyMob(living)) { - return Utils.Colors.GREEN; + return Colors.GREEN.toBuffer(); } else { - return Utils.Colors.WHITE; + return Colors.WHITE.toBuffer(); } } - + public static boolean isDrivenByPlayer(Entity entityIn) { return getLocalPlayer() != null && entityIn != null && entityIn == getRidingEntity(); } - + public static boolean isAboveWater(Entity entity) { return isAboveWater(entity, false); } - + public static boolean isAboveWater(Entity entity, boolean packet) { - if (entity == null) return false; - + if (entity == null) { + return false; + } + double y = - entity.posY - - (packet - ? 0.03 - : (EntityUtils.isPlayer(entity) - ? 0.2 - : 0.5)); // increasing this seems to flag more in NCP but needs to be increased + entity.posY + - (packet + ? 0.03 + : (EntityUtils.isPlayer(entity) + ? 0.2 + : 0.5)); // increasing this seems to flag more in NCP but needs to be increased // so the player lands on solid water - - for (int x = MathHelper.floor(entity.posX); x < MathHelper.ceil(entity.posX); x++) + + for (int x = MathHelper.floor(entity.posX); x < MathHelper.ceil(entity.posX); x++) { for (int z = MathHelper.floor(entity.posZ); z < MathHelper.ceil(entity.posZ); z++) { BlockPos pos = new BlockPos(x, MathHelper.floor(y), z); - - if (getWorld().getBlockState(pos).getBlock() instanceof BlockLiquid) return true; + + if (getWorld().getBlockState(pos).getBlock() instanceof BlockLiquid) { + return true; + } } - + } + return false; } - + public static boolean isInWater(Entity entity) { - if (entity == null) return false; - + if (entity == null) { + return false; + } + double y = entity.posY + 0.01; - - for (int x = MathHelper.floor(entity.posX); x < MathHelper.ceil(entity.posX); x++) + + for (int x = MathHelper.floor(entity.posX); x < MathHelper.ceil(entity.posX); x++) { for (int z = MathHelper.floor(entity.posZ); z < MathHelper.ceil(entity.posZ); z++) { BlockPos pos = new BlockPos(x, (int) y, z); - - if (getWorld().getBlockState(pos).getBlock() instanceof BlockLiquid) return true; + + if (getWorld().getBlockState(pos).getBlock() instanceof BlockLiquid) { + return true; + } } - + } + return false; } } diff --git a/src/main/java/com/matt/forgehax/util/entity/LocalPlayerInventory.java b/src/main/java/com/matt/forgehax/util/entity/LocalPlayerInventory.java index 9973ad37c..be8534ee0 100644 --- a/src/main/java/com/matt/forgehax/util/entity/LocalPlayerInventory.java +++ b/src/main/java/com/matt/forgehax/util/entity/LocalPlayerInventory.java @@ -25,104 +25,105 @@ import net.minecraft.network.play.client.CPacketHeldItemChange; public class LocalPlayerInventory { + public static InventoryPlayer getInventory() { return getLocalPlayer().inventory; } - + public static Container getContainer() { return getLocalPlayer().inventoryContainer; } - + public static Container getOpenContainer() { return getLocalPlayer().openContainer; } - + public static int getHotbarSize() { return InventoryPlayer.getHotbarSize(); } - + public static List getMainInventory() { AtomicInteger next = new AtomicInteger(0); return getInventory() - .mainInventory - .stream() - .map(item -> new InvItem.Base(item, next.getAndIncrement())) - .collect(Collectors.toList()); + .mainInventory + .stream() + .map(item -> new InvItem.Base(item, next.getAndIncrement())) + .collect(Collectors.toList()); } - + public static List getSlotInventory() { return getContainer() - .inventorySlots - .stream() - .map(SlotWrapper::new) - .collect(Collectors.toList()); + .inventorySlots + .stream() + .map(SlotWrapper::new) + .collect(Collectors.toList()); } - + public static List getMainInventory(int start, int end) { return getMainInventory().subList(start, end); } - + public static List getSlotInventory(int start, int end) { return getSlotInventory().subList(start, end); } - + public static List getStorageInventory() { return getMainInventory(9, 27); } - + public static List getSlotStorageInventory() { return getSlotInventory(9, 36); } - + public static List getHotbarInventory() { return getMainInventory(0, getHotbarSize()); } - + public static InvItem getMouseHeld() { return newInvItem(getInventory().getItemStack(), -999); } - + public static InvItem getSelected() { return getMainInventory().get(getInventory().currentItem); } - + public static ResetFunction setSelected(int index, boolean reset, Predicate condition) { return HotbarSelectionService.getInstance().setSelected(index, reset, condition); } - + public static ResetFunction setSelected(InvItem inv, boolean reset, Predicate condition) { return setSelected(inv.getIndex(), reset, condition); } - + public static ResetFunction setSelected(int index, Predicate condition) { Objects.requireNonNull(condition); return setSelected(index, true, condition); } - + public static ResetFunction setSelected(InvItem inv, Predicate condition) { return setSelected(inv.getIndex(), condition); } - + public static ResetFunction setSelected(int index) { return setSelected(index, Predicates.alwaysTrue()); } - + public static ResetFunction setSelected(InvItem invItem) { return setSelected(invItem.getIndex()); } - + public static ResetFunction forceSelected(int index) { return setSelected(index, false, null); } - + public static ResetFunction forceSelected(InvItem inv) { return forceSelected(inv.getIndex()); } - + public static void resetSelected() { HotbarSelectionService.getInstance().resetSelected(); } - + public static void syncSelected() { int selected = getSelected().getIndex(); if (selected != PlayerControllerMP_currentPlayerItem.get(getPlayerController())) { @@ -130,77 +131,80 @@ public static void syncSelected() { getNetworkManager().sendPacket(new CPacketHeldItemChange(selected)); } } - + public static InvItem getOffhand() { return newInvItem(getLocalPlayer().getHeldItemOffhand(), 36); } - + public static int getHotbarDistance(InvItem item) { int max = LocalPlayerInventory.getHotbarSize() - 1; return item.getIndex() > max ? 0 : max - Math.abs(getSelected().getIndex() - item.getIndex()); } - + public static void sendWindowClick( - int slotIdIn, int usedButtonIn, ClickType modeIn, ItemStack clickedItemIn) { + int slotIdIn, int usedButtonIn, ClickType modeIn, ItemStack clickedItemIn) { getNetworkManager() - .sendPacket( - new CPacketClickWindow( - 0, - slotIdIn, - usedButtonIn, - modeIn, - clickedItemIn, - getOpenContainer().getNextTransactionID(getInventory()))); + .sendPacket( + new CPacketClickWindow( + 0, + slotIdIn, + usedButtonIn, + modeIn, + clickedItemIn, + getOpenContainer().getNextTransactionID(getInventory()))); } - + public static ItemStack sendWindowClick(InvItem item, int usedButtonIn, ClickType modeIn) { - if (item.getIndex() == -1) throw new IllegalArgumentException(); + if (item.getIndex() == -1) { + throw new IllegalArgumentException(); + } ItemStack ret; sendWindowClick( - item.getSlotNumber(), - usedButtonIn, - modeIn, - ret = - getOpenContainer() - .slotClick(item.getSlotNumber(), usedButtonIn, modeIn, getLocalPlayer())); + item.getSlotNumber(), + usedButtonIn, + modeIn, + ret = + getOpenContainer() + .slotClick(item.getSlotNumber(), usedButtonIn, modeIn, getLocalPlayer())); return ret; } - + public static InvItem newInvItem(ItemStack itemStack, int index) { return new InvItem.Base(itemStack, index); } - + public static InvItem newInvItem(Slot slot) { return new SlotWrapper(slot); } - + public abstract static class InvItem implements Comparable { + public static final InvItem EMPTY = - new InvItem() { - @Override - public ItemStack getItemStack() { - return ItemStack.EMPTY; - } - - @Override - public Item getItem() { - return Items.AIR; - } - - @Override - public int getIndex() { - return -1; - } - }; - + new InvItem() { + @Override + public ItemStack getItemStack() { + return ItemStack.EMPTY; + } + + @Override + public Item getItem() { + return Items.AIR; + } + + @Override + public int getIndex() { + return -1; + } + }; + public abstract ItemStack getItemStack(); - + public Item getItem() { return getItemStack().getItem(); } - + public abstract int getIndex(); - + public int getSlotNumber() { switch (getIndex()) { case 36: @@ -214,116 +218,118 @@ public int getSlotNumber() { return 9 + 36 - ((row * 9) + (9 - idx)); } } - + public boolean isNull() { return getItemStack().isEmpty(); } - + public boolean nonNull() { return !isNull(); } - + public boolean isEmpty() { return getItemStack().isEmpty(); } - + public boolean nonEmpty() { return !isEmpty(); } - + public boolean isDamageable() { return getItemStack().isItemStackDamageable(); } - + public boolean isItemDamageable() { return getItem().isDamageable(); } - + public boolean isStackable() { return getItemStack().isStackable(); } - + public int getDamage() { return isDamageable() ? getItemStack().getItemDamage() : 0; } - + public int getDurability() { return isDamageable() ? (getItemStack().getMaxDamage() - getItemStack().getItemDamage()) : 0; } - + public int getStackCount() { return getItemStack().getCount(); } - + public int getMaxStackCount() { return getItemStack().getMaxStackSize(); } - + public boolean isStackMaxed() { return getStackCount() >= getMaxStackCount(); } - + public boolean isItemsEqual(InvItem other) { return getItemStack().isItemEqualIgnoreDurability(other.getItemStack()); } - + @Override public boolean equals(Object obj) { return this == obj - || (obj instanceof InvItem - && getIndex() == ((InvItem) obj).getIndex() - && getItemStack().equals(((InvItem) obj).getItemStack())); + || (obj instanceof InvItem + && getIndex() == ((InvItem) obj).getIndex() + && getItemStack().equals(((InvItem) obj).getItemStack())); } - + @Override public int hashCode() { return Objects.hash(getItemStack(), getIndex()); } - + @Override public int compareTo(InvItem o) { return Integer.compare(getIndex(), o.getIndex()); } - + protected static class Base extends InvItem { + private final ItemStack itemStack; private final int index; - + protected Base(ItemStack itemStack, int index) { this.itemStack = itemStack; this.index = index; } - + @Override public ItemStack getItemStack() { return itemStack; } - + @Override public int getIndex() { return index; } } - + protected static class SlotWrapper extends InvItem { + private final Slot slot; - + protected SlotWrapper(Slot slot) { this.slot = slot; } - + @Override public ItemStack getItemStack() { return slot.getStack(); } - + @Override public int getIndex() { int row = (getSlotNumber() / 9) - 1; int idx = getSlotNumber() % 9; return 36 - ((row * 9) + (9 - idx)); // inverse of what is done for ::getIndex() } - + @Override public int getSlotNumber() { return slot.slotNumber; diff --git a/src/main/java/com/matt/forgehax/util/entity/LocalPlayerUtils.java b/src/main/java/com/matt/forgehax/util/entity/LocalPlayerUtils.java index 7e0dedf2c..18ef2c5c9 100644 --- a/src/main/java/com/matt/forgehax/util/entity/LocalPlayerUtils.java +++ b/src/main/java/com/matt/forgehax/util/entity/LocalPlayerUtils.java @@ -1,6 +1,8 @@ package com.matt.forgehax.util.entity; -import static com.matt.forgehax.Helper.*; +import static com.matt.forgehax.Helper.getLocalPlayer; +import static com.matt.forgehax.Helper.getPlayerController; +import static com.matt.forgehax.Helper.getWorld; import com.google.common.base.Predicates; import com.matt.forgehax.Globals; @@ -21,85 +23,94 @@ import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; -/** Class for dealing with the local player only */ +/** + * Class for dealing with the local player only + */ public class LocalPlayerUtils implements Globals { - /** Gets the players current view angles */ + + /** + * Gets the players current view angles + */ public static Angle getViewAngles() { return PositionRotationManager.getState().getRenderClientViewAngles(); } - + public static Angle getServerViewAngles() { return PositionRotationManager.getState().getRenderServerViewAngles(); } - + public static Vec3d getVelocity() { return new Vec3d(getLocalPlayer().motionX, getLocalPlayer().motionY, getLocalPlayer().motionZ); } - + public static boolean isSneaking() { return getLocalPlayer().isSneaking(); } - + public static boolean setSneaking(boolean sneak) { boolean old = isSneaking(); getLocalPlayer().setSneaking(sneak); - if (getLocalPlayer().movementInput != null) getLocalPlayer().movementInput.sneak = sneak; + if (getLocalPlayer().movementInput != null) { + getLocalPlayer().movementInput.sneak = sneak; + } return old; } - + public static void setSneakingSuppression(boolean suppress) { SneakService.getInstance().setSuppressing(suppress); } - + public static Vec3d getEyePos() { return EntityUtils.getEyePos(getLocalPlayer()); } - + public static Vec3d getDirectionVector() { return getViewAngles().getDirectionVector().normalize(); } - + public static Vec3d getServerDirectionVector() { return getServerViewAngles().getDirectionVector().normalize(); } - + public static RayTraceResult getViewTrace() { return MC.objectMouseOver; } - + public static RayTraceResult getMouseOverBlockTrace() { return Optional.ofNullable(MC.objectMouseOver) - .filter(tr -> tr.getBlockPos() != null) // no its not intelliJ - .filter( - tr -> - Type.BLOCK.equals(tr.typeOfHit) - || !Material.AIR.equals( - getWorld().getBlockState(tr.getBlockPos()).getMaterial())) - .orElse(null); + .filter(tr -> tr.getBlockPos() != null) // no its not intelliJ + .filter( + tr -> + Type.BLOCK.equals(tr.typeOfHit) + || !Material.AIR.equals( + getWorld().getBlockState(tr.getBlockPos()).getMaterial())) + .orElse(null); } - + public static RayTraceResult getViewTrace( - Entity entity, Vec3d direction, float partialTicks, double reach, double reachAttack) { - if (entity == null) return null; - + Entity entity, Vec3d direction, float partialTicks, double reach, double reachAttack) { + if (entity == null) { + return null; + } + Vec3d eyes = entity.getPositionEyes(partialTicks); RayTraceResult trace = entity.rayTrace(reach, partialTicks); - + Vec3d dir = direction.scale(reach); Vec3d lookDir = eyes.add(dir); - + double hitDistance = trace == null ? reachAttack : trace.hitVec.distanceTo(eyes); Entity hitEntity = null; Vec3d hitEntityVec = null; - + for (Entity ent : - getWorld() - .getEntitiesInAABBexcluding( - entity, - entity.getEntityBoundingBox().expand(dir.x, dir.y, dir.y).grow(1.D), - Predicates.and( - EntitySelectors.NOT_SPECTATING, - ent -> ent != null && ent.canBeCollidedWith()))) { + getWorld() + .getEntitiesInAABBexcluding( + entity, + entity.getEntityBoundingBox().expand(dir.x, dir.y, dir.y).grow(1.D), + Predicates.and( + EntitySelectors.NOT_SPECTATING, + ent -> ent != null && ent.canBeCollidedWith()))) { AxisAlignedBB bb = ent.getEntityBoundingBox().grow(ent.getCollisionBorderSize()); RayTraceResult tr = bb.calculateIntercept(eyes, lookDir); if (bb.contains(eyes)) { @@ -112,7 +123,7 @@ public static RayTraceResult getViewTrace( double dist = eyes.distanceTo(tr.hitVec); if (dist < hitDistance || hitDistance == 0.D) { if (entity.getLowestRidingEntity() == ent.getLowestRidingEntity() - && !ent.canRiderInteract()) { + && !ent.canRiderInteract()) { if (hitDistance == 0.D) { hitEntity = ent; hitEntityVec = tr.hitVec; @@ -125,43 +136,47 @@ public static RayTraceResult getViewTrace( } } } - - if (hitEntity != null && reach > 3.D && eyes.distanceTo(hitEntityVec) > 3.D) + + if (hitEntity != null && reach > 3.D && eyes.distanceTo(hitEntityVec) > 3.D) { return new RayTraceResult(Type.MISS, hitEntityVec, EnumFacing.UP, new BlockPos(hitEntityVec)); - else if (hitEntity != null && trace == null && hitDistance < reachAttack) + } else if (hitEntity != null && trace == null && hitDistance < reachAttack) { return new RayTraceResult(hitEntity, hitEntityVec); - else return trace; + } else { + return trace; + } } - + public static boolean isInReach(Vec3d start, Vec3d end) { return start.squareDistanceTo(end) - < getPlayerController().getBlockReachDistance() - * getPlayerController().getBlockReachDistance(); + < getPlayerController().getBlockReachDistance() + * getPlayerController().getBlockReachDistance(); } - + private static final Switch FLY_SWITCH = new Switch("PlayerFlying") { @Override protected void onEnabled() { MC.addScheduledTask(() -> { - if(getLocalPlayer() == null || getLocalPlayer().capabilities == null) + if (getLocalPlayer() == null || getLocalPlayer().capabilities == null) { return; - + } + getLocalPlayer().capabilities.allowFlying = true; getLocalPlayer().capabilities.isFlying = true; }); } - + @Override protected void onDisabled() { MC.addScheduledTask(() -> { EntityPlayer player = getLocalPlayer(); - - if (player == null || player.capabilities == null) + + if (player == null || player.capabilities == null) { return; - + } + PlayerCapabilities gmCaps = new PlayerCapabilities(); MC.playerController.getCurrentGameType().configurePlayerCapabilities(gmCaps); - + PlayerCapabilities capabilities = player.capabilities; capabilities.allowFlying = gmCaps.allowFlying; capabilities.isFlying = gmCaps.allowFlying && capabilities.isFlying; @@ -169,7 +184,7 @@ protected void onDisabled() { }); } }; - + public static Switch getFlySwitch() { return FLY_SWITCH; } diff --git a/src/main/java/com/matt/forgehax/util/entity/PlayerInfo.java b/src/main/java/com/matt/forgehax/util/entity/PlayerInfo.java index b00afd533..1dfa4cc50 100644 --- a/src/main/java/com/matt/forgehax/util/entity/PlayerInfo.java +++ b/src/main/java/com/matt/forgehax/util/entity/PlayerInfo.java @@ -12,23 +12,37 @@ import java.io.DataOutputStream; import java.io.IOException; import java.net.URL; -import java.util.*; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Scanner; +import java.util.UUID; import javax.net.ssl.HttpsURLConnection; import net.minecraft.client.entity.EntityPlayerSP; -/** Created on 7/22/2017 by fr1kin */ +/** + * Created on 7/22/2017 by fr1kin + */ public class PlayerInfo implements Globals, GsonConstant { - /** The online UUID for this player */ + + /** + * The online UUID for this player + */ private final UUID id; - + private final UUID offlineId; - - /** If this player data is only for offline mode */ + + /** + * If this player data is only for offline mode + */ private final boolean isOfflinePlayer; - - /** List of names */ + + /** + * List of names + */ private final List names; - + public PlayerInfo(UUID id) throws IOException { Objects.requireNonNull(id); this.id = id; @@ -36,42 +50,42 @@ public PlayerInfo(UUID id) throws IOException { this.offlineId = EntityPlayerSP.getOfflineUUID(getName()); this.isOfflinePlayer = false; } - + public PlayerInfo(String name) throws IOException, NullPointerException { Objects.requireNonNull(name); JsonArray ar = new JsonArray(); ar.add(name); - + JsonArray array = - getResources(new URL("https://api.mojang.com/profiles/minecraft"), "POST", ar) - .getAsJsonArray(); + getResources(new URL("https://api.mojang.com/profiles/minecraft"), "POST", ar) + .getAsJsonArray(); JsonObject node = array.get(0).getAsJsonObject(); - + UUID uuid = PlayerInfoHelper.getIdFromString(node.get("id").getAsString()); Objects.requireNonNull(uuid); - + this.id = uuid; this.names = ImmutableList.copyOf(lookupNames(uuid)); this.offlineId = EntityPlayerSP.getOfflineUUID(name); this.isOfflinePlayer = false; } - + public PlayerInfo(String name, boolean dummy) { this.id = EntityPlayerSP.getOfflineUUID(name); this.names = Collections.singletonList(new Name(name)); this.offlineId = this.id; this.isOfflinePlayer = true; } - + private static List lookupNames(UUID id) throws IOException { JsonArray array = - getResources( - new URL( - "https://api.mojang.com/user/profiles/" - + PlayerInfoHelper.getIdNoHyphens(id) - + "/names"), - "GET") - .getAsJsonArray(); + getResources( + new URL( + "https://api.mojang.com/user/profiles/" + + PlayerInfoHelper.getIdNoHyphens(id) + + "/names"), + "GET") + .getAsJsonArray(); List temp = Lists.newArrayList(); for (JsonElement e : array) { JsonObject node = e.getAsJsonObject(); @@ -82,48 +96,43 @@ private static List lookupNames(UUID id) throws IOException { Collections.sort(temp); return temp; } - + /** * Unique ID that will identify this player - * - * @return */ public UUID getId() { return id; } - + public UUID getOfflineId() { return offlineId; } - + /** * If this player is not verified on Mojang's auth server - * - * @return */ public boolean isOfflinePlayer() { return isOfflinePlayer; } - + /** * This players current name - * - * @return */ public String getName() { - if (!names.isEmpty()) return names.get(0).getName(); - else return null; + if (!names.isEmpty()) { + return names.get(0).getName(); + } else { + return null; + } } - + /** * This players name history - * - * @return */ public List getNameHistory() { return names; } - + public String getNameHistoryAsString() { StringBuilder builder = new StringBuilder(); if (!names.isEmpty()) { @@ -132,37 +141,39 @@ public String getNameHistoryAsString() { while (it.hasNext()) { Name next = it.next(); builder.append(next.getName()); - if (it.hasNext()) builder.append(", "); + if (it.hasNext()) { + builder.append(", "); + } } } return builder.toString(); } - + public boolean isLocalPlayer() { return String.CASE_INSENSITIVE_ORDER.compare(getName(), getLocalPlayer().getName()) == 0; } - + public boolean matches(UUID otherId) { return otherId != null && (otherId.equals(getOfflineId()) || otherId.equals(getId())); } - + @Override public boolean equals(Object obj) { return obj instanceof PlayerInfo && id.equals(((PlayerInfo) obj).id); } - + @Override public int hashCode() { return id.hashCode(); } - + @Override public String toString() { return id.toString(); } - + private static JsonElement getResources(URL url, String request, JsonElement element) - throws IOException { + throws IOException { JsonElement data; HttpsURLConnection connection = null; try { @@ -170,13 +181,13 @@ private static JsonElement getResources(URL url, String request, JsonElement ele connection.setDoOutput(true); connection.setRequestMethod(request); connection.setRequestProperty("Content-Type", "application/json"); - + if (element != null) { DataOutputStream output = new DataOutputStream(connection.getOutputStream()); output.writeBytes(GSON.toJson(element)); output.close(); } - + Scanner scanner = new Scanner(connection.getInputStream()); StringBuilder builder = new StringBuilder(); while (scanner.hasNextLine()) { @@ -184,52 +195,55 @@ private static JsonElement getResources(URL url, String request, JsonElement ele builder.append('\n'); } scanner.close(); - + String json = builder.toString(); data = PARSER.parse(json); } finally { - if (connection != null) connection.disconnect(); + if (connection != null) { + connection.disconnect(); + } } return data; } - + private static JsonElement getResources(URL url, String request) throws IOException { return getResources(url, request, null); } - + public static class Name implements Comparable { + private final String name; private final long changedAt; - + public Name(String name, long changedAt) { this.name = name; this.changedAt = changedAt; } - + public Name(String name) { this(name, 0); } - + public String getName() { return name; } - + public long getTimeChanged() { return changedAt; } - + @Override public int compareTo(Name o) { return Long.compare(o.changedAt, changedAt); // longest to shortest } - + @Override public boolean equals(Object obj) { return obj instanceof Name - && name.equalsIgnoreCase(((Name) obj).getName()) - && changedAt == ((Name) obj).changedAt; + && name.equalsIgnoreCase(((Name) obj).getName()) + && changedAt == ((Name) obj).changedAt; } - + @Override public int hashCode() { return Objects.hash(name, changedAt); diff --git a/src/main/java/com/matt/forgehax/util/entity/PlayerInfoHelper.java b/src/main/java/com/matt/forgehax/util/entity/PlayerInfoHelper.java index f0eb55e18..d5948fcb0 100644 --- a/src/main/java/com/matt/forgehax/util/entity/PlayerInfoHelper.java +++ b/src/main/java/com/matt/forgehax/util/entity/PlayerInfoHelper.java @@ -1,24 +1,34 @@ package com.matt.forgehax.util.entity; import com.google.common.collect.Maps; -import com.google.common.util.concurrent.*; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; import com.matt.forgehax.Globals; import com.matt.forgehax.util.Immutables; import java.io.IOException; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import javax.annotation.Nullable; import joptsimple.internal.Strings; -/** Created on 7/22/2017 by fr1kin */ +/** + * Created on 7/22/2017 by fr1kin + */ public class PlayerInfoHelper implements Globals { + private static final int THREAD_COUNT = 1; public static final int MAX_NAME_LENGTH = 16; private static final ListeningExecutorService EXECUTOR_SERVICE = - MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(Math.max(THREAD_COUNT, 1))); + MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(Math.max(THREAD_COUNT, 1))); private static final Map NAME_TO_INFO = Maps.newConcurrentMap(); private static final Map UUID_TO_INFO = Maps.newConcurrentMap(); @@ -26,20 +36,23 @@ public class PlayerInfoHelper implements Globals { static { // shut threads down Runtime.getRuntime() - .addShutdownHook( - new Thread( - () -> { - EXECUTOR_SERVICE.shutdown(); - while (!EXECUTOR_SERVICE.isShutdown()) - try { - EXECUTOR_SERVICE.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); - } catch (InterruptedException e) { - } - })); + .addShutdownHook( + new Thread( + () -> { + EXECUTOR_SERVICE.shutdown(); + while (!EXECUTOR_SERVICE.isShutdown()) { + try { + EXECUTOR_SERVICE.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + } + } + })); } private static PlayerInfo register(String name) throws IOException { - if (Strings.isNullOrEmpty(name) || name.length() > MAX_NAME_LENGTH) return null; + if (Strings.isNullOrEmpty(name) || name.length() > MAX_NAME_LENGTH) { + return null; + } PlayerInfo info = new PlayerInfo(name); NAME_TO_INFO.put(info.getName().toLowerCase(), info); UUID_TO_INFO.put(info.getId(), info); @@ -54,7 +67,9 @@ private static PlayerInfo register(UUID uuid) throws IOException { } private static PlayerInfo offlineUser(String name) { - if (name.length() > MAX_NAME_LENGTH) return null; + if (name.length() > MAX_NAME_LENGTH) { + return null; + } return new PlayerInfo(name, true); } @@ -72,40 +87,44 @@ public static List getPlayers() { public static List getOnlinePlayers() { return MC.getConnection() == null - ? Collections.emptyList() - : MC.getConnection() - .getPlayerInfoMap() - .stream() - .map( - info -> { - PlayerInfo pl = get(info.getGameProfile().getName()); - return pl == null ? offlineUser(info.getGameProfile().getName()) : pl; - }) - .collect(Collectors.toList()); + ? Collections.emptyList() + : MC.getConnection() + .getPlayerInfoMap() + .stream() + .map( + info -> { + PlayerInfo pl = get(info.getGameProfile().getName()); + return pl == null ? offlineUser(info.getGameProfile().getName()) : pl; + }) + .collect(Collectors.toList()); } public static PlayerInfo lookup(String name) throws IOException { PlayerInfo info = get(name); - if (info == null) return register(name); - else return info; + if (info == null) { + return register(name); + } else { + return info; + } } public static PlayerInfo lookup(UUID uuid) throws IOException { PlayerInfo info = get(uuid); - if (info == null) return register(uuid); - else return info; + if (info == null) { + return register(uuid); + } else { + return info; + } } /** * Will either use already cached player info or start a new service to lookup the player info * - * @param name - * @param callback * @return true if the player info is being looked up on a separate thread */ @SuppressWarnings("Duplicates") public static boolean registerWithCallback( - final String name, final FutureCallback callback) { + final String name, final FutureCallback callback) { PlayerInfo info = get(name); if (info == null) { Futures.addCallback(EXECUTOR_SERVICE.submit(() -> PlayerInfoHelper.register(name)), callback); @@ -118,7 +137,7 @@ public static boolean registerWithCallback( @SuppressWarnings("Duplicates") public static boolean registerWithCallback( - final UUID uuid, final FutureCallback callback) { + final UUID uuid, final FutureCallback callback) { PlayerInfo info = get(uuid); if (info == null) { Futures.addCallback(EXECUTOR_SERVICE.submit(() -> PlayerInfoHelper.register(uuid)), callback); @@ -130,38 +149,40 @@ public static boolean registerWithCallback( } public static boolean registerWithCallback( - final UUID uuid, final String name, final FutureCallback callback) { + final UUID uuid, final String name, final FutureCallback callback) { return registerWithCallback( - uuid, - new FutureCallback() { - @Override - public void onSuccess(@Nullable PlayerInfo result) { - callback.onSuccess( - result); // uuid successfully found player data, call original onSuccess - } - - @Override - public void onFailure(Throwable t) { - registerWithCallback(name, callback); // try name instead - } - }); + uuid, + new FutureCallback() { + @Override + public void onSuccess(@Nullable PlayerInfo result) { + callback.onSuccess( + result); // uuid successfully found player data, call original onSuccess + } + + @Override + public void onFailure(Throwable t) { + registerWithCallback(name, callback); // try name instead + } + }); } public static boolean generateOfflineWithCallback( - final String name, final FutureCallback callback) { + final String name, final FutureCallback callback) { ListenableFuture future = - Futures.immediateFuture(PlayerInfoHelper.offlineUser(name)); + Futures.immediateFuture(PlayerInfoHelper.offlineUser(name)); Futures.addCallback(future, callback); return false; } public static UUID getIdFromString(String uuid) { - if (uuid.contains("-")) return UUID.fromString(uuid); - else + if (uuid.contains("-")) { + return UUID.fromString(uuid); + } else { return UUID.fromString( - uuid.replaceFirst( - "(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", - "$1-$2-$3-$4-$5")); + uuid.replaceFirst( + "(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", + "$1-$2-$3-$4-$5")); + } } public static String getIdNoHyphens(UUID uuid) { diff --git a/src/main/java/com/matt/forgehax/util/entity/PlayerUtils.java b/src/main/java/com/matt/forgehax/util/entity/PlayerUtils.java index e684941cc..6ae6f9149 100644 --- a/src/main/java/com/matt/forgehax/util/entity/PlayerUtils.java +++ b/src/main/java/com/matt/forgehax/util/entity/PlayerUtils.java @@ -7,7 +7,10 @@ import net.minecraft.entity.player.EntityPlayer; public class PlayerUtils implements Globals { - /** Use EntityUtils::isLocalPlayer */ + + /** + * Use EntityUtils::isLocalPlayer + */ @Deprecated public static boolean isLocalPlayer(Entity player) { EntityPlayer localPlayer = getLocalPlayer(); diff --git a/src/main/java/com/matt/forgehax/util/entity/mobtypes/EndermanMob.java b/src/main/java/com/matt/forgehax/util/entity/mobtypes/EndermanMob.java index 0066549ad..ef20694da 100644 --- a/src/main/java/com/matt/forgehax/util/entity/mobtypes/EndermanMob.java +++ b/src/main/java/com/matt/forgehax/util/entity/mobtypes/EndermanMob.java @@ -4,8 +4,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.monster.EntityEnderman; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class EndermanMob extends MobType { + @Override protected PriorityEnum getPriority() { return PriorityEnum.LOW; diff --git a/src/main/java/com/matt/forgehax/util/entity/mobtypes/FriendlyMob.java b/src/main/java/com/matt/forgehax/util/entity/mobtypes/FriendlyMob.java index ff2209ed4..a08f2fdfc 100644 --- a/src/main/java/com/matt/forgehax/util/entity/mobtypes/FriendlyMob.java +++ b/src/main/java/com/matt/forgehax/util/entity/mobtypes/FriendlyMob.java @@ -5,17 +5,20 @@ import net.minecraft.entity.monster.EntityGolem; import net.minecraft.entity.passive.EntityVillager; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class FriendlyMob extends MobType { + @Override public boolean isMobType(Entity entity) { return entity.isCreatureType(EnumCreatureType.CREATURE, false) - || entity.isCreatureType(EnumCreatureType.AMBIENT, false) - || entity.isCreatureType(EnumCreatureType.WATER_CREATURE, false) - || entity instanceof EntityVillager - || entity instanceof EntityGolem; + || entity.isCreatureType(EnumCreatureType.AMBIENT, false) + || entity.isCreatureType(EnumCreatureType.WATER_CREATURE, false) + || entity instanceof EntityVillager + || entity instanceof EntityGolem; } - + @Override protected MobTypeEnum getMobTypeUnchecked(Entity entity) { return MobTypeEnum.FRIENDLY; diff --git a/src/main/java/com/matt/forgehax/util/entity/mobtypes/HostileMob.java b/src/main/java/com/matt/forgehax/util/entity/mobtypes/HostileMob.java index 08b1b0757..9aa10926c 100644 --- a/src/main/java/com/matt/forgehax/util/entity/mobtypes/HostileMob.java +++ b/src/main/java/com/matt/forgehax/util/entity/mobtypes/HostileMob.java @@ -3,8 +3,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EnumCreatureType; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class HostileMob extends MobType { + @Override public boolean isMobType(Entity entity) { return entity.isCreatureType(EnumCreatureType.MONSTER, false); diff --git a/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobType.java b/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobType.java index b1757c0d5..3c1d30718 100644 --- a/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobType.java +++ b/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobType.java @@ -3,20 +3,23 @@ import com.matt.forgehax.util.common.PriorityEnum; import net.minecraft.entity.Entity; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public abstract class MobType implements Comparable { + protected PriorityEnum getPriority() { return PriorityEnum.LOWEST; } - + public boolean isNeutralMob(Entity entity) { return false; } - + public abstract boolean isMobType(Entity entity); - + protected abstract MobTypeEnum getMobTypeUnchecked(Entity entity); - + public MobTypeEnum getMobType(Entity entity) { try { return getMobTypeUnchecked(entity); @@ -24,7 +27,7 @@ public MobTypeEnum getMobType(Entity entity) { return MobTypeEnum.HOSTILE; } } - + @Override public int compareTo(MobType o) { return getPriority().compareTo(o.getPriority()); diff --git a/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobTypeEnum.java b/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobTypeEnum.java index 2869dff13..3f844a4ec 100644 --- a/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobTypeEnum.java +++ b/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobTypeEnum.java @@ -1,23 +1,35 @@ package com.matt.forgehax.util.entity.mobtypes; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public enum MobTypeEnum { - /** Is a player */ + /** + * Is a player + */ PLAYER, - - /** Mob will attack the player */ + + /** + * Mob will attack the player + */ HOSTILE, - - /** Mob does not attack by default, but will under certain circumstances */ + + /** + * Mob does not attack by default, but will under certain circumstances + */ NEUTRAL, - - /** Mob is friendly and will not harm the player */ + + /** + * Mob is friendly and will not harm the player + */ FRIENDLY, - - /** Unknown */ + + /** + * Unknown + */ INVALID, ; - + public boolean isValid() { return ordinal() > 0; } diff --git a/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobTypeRegistry.java b/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobTypeRegistry.java index c92e94be1..59eacf269 100644 --- a/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobTypeRegistry.java +++ b/src/main/java/com/matt/forgehax/util/entity/mobtypes/MobTypeRegistry.java @@ -5,8 +5,11 @@ import java.util.Collections; import java.util.List; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class MobTypeRegistry { + public static final MobType HOSTILE = new HostileMob(); public static final MobType FRIENDLY = new FriendlyMob(); diff --git a/src/main/java/com/matt/forgehax/util/entity/mobtypes/PigZombieMob.java b/src/main/java/com/matt/forgehax/util/entity/mobtypes/PigZombieMob.java index e08a80e36..d70235293 100644 --- a/src/main/java/com/matt/forgehax/util/entity/mobtypes/PigZombieMob.java +++ b/src/main/java/com/matt/forgehax/util/entity/mobtypes/PigZombieMob.java @@ -4,8 +4,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.monster.EntityPigZombie; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class PigZombieMob extends MobType { + @Override protected PriorityEnum getPriority() { return PriorityEnum.LOW; diff --git a/src/main/java/com/matt/forgehax/util/entity/mobtypes/WolfMob.java b/src/main/java/com/matt/forgehax/util/entity/mobtypes/WolfMob.java index cf5462caf..f3933ae32 100644 --- a/src/main/java/com/matt/forgehax/util/entity/mobtypes/WolfMob.java +++ b/src/main/java/com/matt/forgehax/util/entity/mobtypes/WolfMob.java @@ -4,8 +4,11 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.passive.EntityWolf; -/** Created on 6/27/2017 by fr1kin */ +/** + * Created on 6/27/2017 by fr1kin + */ public class WolfMob extends MobType { + @Override protected PriorityEnum getPriority() { return PriorityEnum.LOW; diff --git a/src/main/java/com/matt/forgehax/util/entry/ClassEntry.java b/src/main/java/com/matt/forgehax/util/entry/ClassEntry.java index d7d3cb7ed..da72c43b1 100644 --- a/src/main/java/com/matt/forgehax/util/entry/ClassEntry.java +++ b/src/main/java/com/matt/forgehax/util/entry/ClassEntry.java @@ -8,64 +8,68 @@ import javax.annotation.Nullable; import net.minecraft.launchwrapper.Launch; -/** Created on 10/13/2017 by fr1kin */ +/** + * Created on 10/13/2017 by fr1kin + */ public class ClassEntry implements ISerializableJson { + private final String clazzName; private Class clazz; - + public ClassEntry(String clazzName) { this.clazzName = clazzName; getClassInstance(); // initial attempt } - + public ClassEntry(Class clazz) { Objects.requireNonNull(clazz); this.clazzName = clazz.getCanonicalName(); this.clazz = clazz; } - + public String getClassName() { return clazzName; } - + @Nullable public Class getClassInstance() { - if (clazz == null) + if (clazz == null) { try { clazz = Class.forName(clazzName, true, Launch.classLoader); } catch (Throwable t) { } + } return clazz; } - + @Override public void serialize(JsonWriter writer) throws IOException { writer.beginObject(); writer.endObject(); } - + @Override public void deserialize(JsonReader reader) throws IOException { reader.beginObject(); reader.endObject(); } - + @Override public boolean equals(Object obj) { return obj == this - || (obj instanceof ClassEntry && clazzName.equals(((ClassEntry) obj).clazzName)) - || (obj instanceof String && clazzName.equals(obj)) - || (getClassInstance() != null - && obj != null - && obj instanceof Class - && getClassInstance().equals(obj)); + || (obj instanceof ClassEntry && clazzName.equals(((ClassEntry) obj).clazzName)) + || (obj instanceof String && clazzName.equals(obj)) + || (getClassInstance() != null + && obj != null + && obj instanceof Class + && getClassInstance().equals(obj)); } - + @Override public int hashCode() { return clazzName.toLowerCase().hashCode(); } - + @Override public String toString() { return clazzName; diff --git a/src/main/java/com/matt/forgehax/util/entry/CustomMessageEntry.java b/src/main/java/com/matt/forgehax/util/entry/CustomMessageEntry.java index 8a9c797c2..2a96a3764 100644 --- a/src/main/java/com/matt/forgehax/util/entry/CustomMessageEntry.java +++ b/src/main/java/com/matt/forgehax/util/entry/CustomMessageEntry.java @@ -10,8 +10,11 @@ import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; -/** Created on 7/21/2017 by fr1kin */ +/** + * Created on 7/21/2017 by fr1kin + */ public class CustomMessageEntry implements ISerializableJson { + private final UUID player; private final List messages = Lists.newCopyOnWriteArrayList(); @@ -26,8 +29,6 @@ public CustomMessageEntry(String uuid) { /** * The player this join message is for - * - * @return */ public UUID getPlayer() { return player; @@ -38,7 +39,11 @@ public List getMessages() { } public MessageEntry getEntry(UUID owner) { - for (MessageEntry entry : messages) if (entry.getOwner().equals(owner)) return entry; + for (MessageEntry entry : messages) { + if (entry.getOwner().equals(owner)) { + return entry; + } + } return null; } @@ -68,7 +73,9 @@ public int getSize() { } public void setSize(int size) { - while (messages.size() > size) messages.remove(getRandom()); + while (messages.size() > size) { + messages.remove(getRandom()); + } } @Override @@ -116,9 +123,9 @@ public void deserialize(JsonReader reader) throws IOException { @Override public boolean equals(Object obj) { return obj == this - || (obj instanceof CustomMessageEntry - && player.equals(((CustomMessageEntry) obj).getPlayer())) - || (obj instanceof UUID && player.equals(obj)); + || (obj instanceof CustomMessageEntry + && player.equals(((CustomMessageEntry) obj).getPlayer())) + || (obj instanceof UUID && player.equals(obj)); } @Override @@ -132,6 +139,7 @@ public String toString() { } public static class MessageEntry implements ISerializableJson { + private final UUID owner; private String message; @@ -179,7 +187,7 @@ public void deserialize(JsonReader reader) throws IOException { @Override public boolean equals(Object obj) { return (obj instanceof MessageEntry && owner.equals(((MessageEntry) obj).owner)) - || (obj instanceof UUID && owner.equals(obj)); + || (obj instanceof UUID && owner.equals(obj)); } @Override diff --git a/src/main/java/com/matt/forgehax/util/entry/FacingEntry.java b/src/main/java/com/matt/forgehax/util/entry/FacingEntry.java index 33fd9b4a6..f24f6ae05 100644 --- a/src/main/java/com/matt/forgehax/util/entry/FacingEntry.java +++ b/src/main/java/com/matt/forgehax/util/entry/FacingEntry.java @@ -8,40 +8,41 @@ import net.minecraft.util.EnumFacing; public class FacingEntry implements ISerializableJson { + private final EnumFacing facing; - + public FacingEntry(EnumFacing facing) { Objects.requireNonNull(facing); this.facing = facing; } - + public FacingEntry(String str) { this(EnumFacing.byName(str)); } - + public EnumFacing getFacing() { return facing; } - + @Override public void serialize(JsonWriter writer) throws IOException { writer.beginArray(); writer.endArray(); } - + @Override public void deserialize(JsonReader reader) throws IOException { reader.beginArray(); reader.endArray(); } - + @Override public boolean equals(Object obj) { return this == obj - || (obj instanceof FacingEntry && facing.equals(((FacingEntry) obj).getFacing())) - || (obj instanceof EnumFacing && facing.equals(obj)); + || (obj instanceof FacingEntry && facing.equals(((FacingEntry) obj).getFacing())) + || (obj instanceof EnumFacing && facing.equals(obj)); } - + @Override public String toString() { return getFacing().getName2(); diff --git a/src/main/java/com/matt/forgehax/util/filter/FilterElement.java b/src/main/java/com/matt/forgehax/util/filter/FilterElement.java deleted file mode 100644 index 261477852..000000000 --- a/src/main/java/com/matt/forgehax/util/filter/FilterElement.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.matt.forgehax.util.filter; - -import com.matt.forgehax.util.serialization.ISerializableJson; - -/** Created on 8/23/2017 by fr1kin */ -public abstract class FilterElement implements ISerializableJson { - public abstract String name(); - - public abstract boolean matches(Object o); - - @Override - public abstract boolean equals(Object obj); - - @Override - public abstract String toString(); -} diff --git a/src/main/java/com/matt/forgehax/util/filter/FilterEntry.java b/src/main/java/com/matt/forgehax/util/filter/FilterEntry.java deleted file mode 100644 index 515d48bee..000000000 --- a/src/main/java/com/matt/forgehax/util/filter/FilterEntry.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.matt.forgehax.util.filter; - -import com.google.common.collect.Lists; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import com.matt.forgehax.Helper; -import com.matt.forgehax.util.Utils; -import com.matt.forgehax.util.serialization.ISerializableJson; -import java.io.IOException; -import java.util.List; -import joptsimple.internal.Strings; - -/** Created on 8/23/2017 by fr1kin */ -public class FilterEntry implements ISerializableJson { - private final String name; - private final List filtered = Lists.newArrayList(); - - private String tag = Strings.EMPTY; - private int color = Utils.Colors.WHITE; - - public FilterEntry(String name) { - this.name = name; - } - - public boolean add(E element) { - return element != null && !contains(element) && filtered.add(element); - } - - public boolean remove(E element) { - return element != null && filtered.remove(element); - } - - @SuppressWarnings("unchecked") - public E get(String name) { - for (E e : filtered) if (e.equals(name)) return e; - return null; - } - - public boolean contains(String name) { - return get(name) != null; - } - - public boolean contains(FilterElement element) { - return filtered.contains(element); - } - - public boolean isFiltered(Object o) { - for (FilterElement e : filtered) if (e.equals(o)) return true; - return false; - } - - public String getName() { - return name; - } - - public String getTag() { - return tag; - } - - public void setTag(String tag) { - this.tag = tag; - } - - public int getColor() { - return color; - } - - public int[] getColor4() { - return Utils.toRGBAArray(color); - } - - public void setColor(int color) { - this.color = color; - } - - @Override - public void serialize(JsonWriter writer) throws IOException { - writer.beginObject(); - - writer.name("tag"); - writer.value(tag); - - writer.name("color"); - writer.value(color); - - writer.name("filtered"); - writer.beginObject(); - for (FilterElement e : filtered) { - writer.value(e.name()); - e.serialize(writer); - } - writer.endObject(); - - writer.endObject(); - } - - @Override - public void deserialize(JsonReader reader) throws IOException { - reader.beginObject(); - - while (reader.hasNext()) { - switch (reader.nextName()) { - case "tag": - setTag(reader.nextString()); - break; - case "color": - setColor(reader.nextInt()); - break; - case "filtered": - reader.beginObject(); - // TODO: factory - while (reader.hasNext()) { - try { - E instance = FilterFactory.newInstanceByName(reader.nextName()); - add(instance); - } catch (Throwable t) { - Helper.handleThrowable(t); - } - } - reader.endObject(); - break; - } - } - - reader.endObject(); - } - - @Override - public String toString() { - return super.toString(); - } -} diff --git a/src/main/java/com/matt/forgehax/util/filter/FilterFactory.java b/src/main/java/com/matt/forgehax/util/filter/FilterFactory.java deleted file mode 100644 index 1a6458f47..000000000 --- a/src/main/java/com/matt/forgehax/util/filter/FilterFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.matt.forgehax.util.filter; - -import com.google.common.collect.Maps; -import java.util.Map; - -/** Created on 8/23/2017 by fr1kin */ -public class FilterFactory { - private static final Map> FILTERS = - Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); - - public static void register(String name, Class clazz) { - FILTERS.put(name, clazz); - } - - public static void unregister(String name) { - FILTERS.remove(name); - } - - public static Class get(String name) { - return FILTERS.get(name); - } - - @SuppressWarnings("unchecked") - public static T newInstanceByName(String name) throws Throwable { - Class clazz = get(name); - return clazz != null ? (T) clazz.newInstance() : null; - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/GuiHelper.java b/src/main/java/com/matt/forgehax/util/gui/GuiHelper.java deleted file mode 100644 index 7c617c166..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/GuiHelper.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.matt.forgehax.util.gui; - -import java.util.Optional; - -/** Created on 9/14/2017 by fr1kin */ -public class GuiHelper { - public static boolean isInArea( - double x, double y, double topX, double topY, double bottomX, double bottomY) { - return x > topX && x < bottomX && y > topY && y < bottomY; - } - - public static boolean isInRectangle( - double x, double y, double topX, double topY, double width, double height) { - return isInArea(x, y, topX, topY, topX + width, topY + height); - } - - public static Optional getTopGuiAt(IGuiParent parent, final double x, final double y) { - return parent - .getChildren() - .stream() - .filter(IGuiBase::isVisible) - .filter( - gui -> - isInRectangle( - x, y, gui.getRealX(), gui.getRealY(), gui.getWidth(), gui.getHeight())) - .findFirst(); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/IGuiBase.java b/src/main/java/com/matt/forgehax/util/gui/IGuiBase.java deleted file mode 100644 index 29161a0db..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/IGuiBase.java +++ /dev/null @@ -1,244 +0,0 @@ -package com.matt.forgehax.util.gui; - -import com.matt.forgehax.util.Utils; -import com.matt.forgehax.util.gui.callbacks.IGuiCallbackBase; -import com.matt.forgehax.util.gui.events.GuiKeyEvent; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; -import com.matt.forgehax.util.gui.events.GuiUpdateEvent; -import javax.annotation.Nullable; -import uk.co.hexeption.thx.ttf.MinecraftFontRenderer; - -/** Created on 9/9/2017 by fr1kin */ -public interface IGuiBase { - /** - * Initialize GUI. Called when created or when the UI is rescaled. - * - * @param screenWidth scaled width - * @param screenHeight scaled height - */ - void init(double screenWidth, double screenHeight); - - /** - * The X coordinate of this element. If the element has a parent, then this will be relative to - * that parent (i.e if a Panel is at (5, 5) and the pos of this element is (1, 1), the REAL - * position is (6, 6) and the relative position is (1,1). - * - * @return relative X coordinate - */ - double getX(); - - /** - * The Y coordinate of this element. If the element has a parent, then this will be relative to - * that parent (i.e if a Panel is at (5, 5) and the pos of this element is (1, 1), the REAL - * position is (6, 6) and the relative position is (1,1). - * - * @return relative Y coordinate - */ - double getY(); - - /** - * Sets the relative X coordinate - * - * @param x relative X coordinate - */ - void setX(double x); - - /** - * Sets the relative Y coordinate - * - * @param y relative Y coordinate - */ - void setY(double y); - - /** - * Sets both the X and Y coordinates at the same time. By default, calls setX(D) and setY(D). - * - * @param x relative X coordinate - * @param y relative Y coordinate - */ - default void setPos(double x, double y) { - setX(x); - setY(y); - } - - /** - * Get the real X coordinate - * - * @return X coordinate relative to the screen - */ - default double getRealX() { - return getParent() == null ? getX() : getParent().getRealX() + getX(); - } - - /** - * Get the real Y coordinate - * - * @return Y coordinate relative to the screen - */ - default double getRealY() { - return getParent() == null ? getY() : getParent().getRealY() + getY(); - } - - /** - * Width of the element - * - * @return width - */ - double getWidth(); - - /** - * Height of the element - * - * @return height - */ - double getHeight(); - - /** - * Set the width of the element - * - * @param w width - */ - void setWidth(double w); - - /** - * Set the height of the element - * - * @param h height - */ - void setHeight(double h); - - /** - * Set the width and height at the same time By default, calls setWidth(D) and setHeight(D) - * - * @param w width - * @param h height - */ - default void setSize(double w, double h) { - setWidth(w); - setHeight(h); - } - - /** - * Check if the element is visible. If not visible, element will not update or draw. - * - * @return if the element will draw - */ - boolean isVisible(); - - /** - * Enable/disable element rendering and updating - * - * @param visible true to enable, false to disable - */ - void setVisible(boolean visible); - - boolean isLocked(); - - void setLocked(boolean locked); - - /** - * This elements parent - * - * @return null if no parent exists - */ - @Nullable - IGuiParent getParent(); - - /** - * Set this elements parent. If it already has a parent, then the child will leave that parent and - * join the provided one. - * - * @param parent null to remove its parent - */ - void setParent(@Nullable IGuiParent parent); - - /** - * If the mouse is hovering over this element - * - * @return true if mouse is hovering over - */ - boolean isHovered(); - - /** - * Time that the mouse has been hovering over the element. - * - * @return time in render ticks - */ - int getHoveredTime(); - - /** - * If this element has focus - * - * @return true if has focus - */ - boolean isInFocus(); - - /** - * Will give this element top focus NOTE: Two of the same elements are not allowed sequentially, - * but are however allowed if split up. If this method is called and the element is already at the - * top of the stack, nothing will be added. - */ - boolean requestFocus(); - - /** - * Time this element has had top focus - * - * @return time in render ticks - */ - int getFocusTime(); - - @Nullable - MinecraftFontRenderer getFontRenderer(); - - void setFontRenderer(MinecraftFontRenderer fontRenderer); - - int getFontColor(); - - void setFontColor(int buffer); - - default void setFontColor(int r, int g, int b, int a) { - setFontColor(Utils.toRGBA(r, g, b, a)); - } - - void onUpdateSize(); - - /** - * Called when a mouse event is invoked - * - * @param event event data - */ - void onMouseEvent(GuiMouseEvent event); - - /** - * Called when a keyboard event is invoked - * - * @param event event data - */ - void onKeyEvent(GuiKeyEvent event); - - /** - * Called before rendering - * - * @param event event data - */ - void onUpdate(GuiUpdateEvent event); - - void onRender(GuiRenderEvent event); - - void onRenderPreBackground(GuiRenderEvent event); - - void onRenderPostBackground(GuiRenderEvent event); - - void addCallback(Class clazz, T callback); - - void removeCallback(Class clazz, T callback); - - void onVisibleChange(); - - void onFocusChanged(); - - void onMouseHoverStateChange(); - - void onClicked(GuiMouseEvent event); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/IGuiButton.java b/src/main/java/com/matt/forgehax/util/gui/IGuiButton.java deleted file mode 100644 index 638f01fa5..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/IGuiButton.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.matt.forgehax.util.gui; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiButton { - int getBackgroundColor(); - - void setBackgroundColor(int color); - - boolean isPressed(); - - void setPressed(boolean pressed); - - String getText(); - - void setText(String text); - - String getHoverText(); - - void setHoverText(String text); - - void onPressed(); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/IGuiCheckbox.java b/src/main/java/com/matt/forgehax/util/gui/IGuiCheckbox.java deleted file mode 100644 index 85e437482..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/IGuiCheckbox.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.matt.forgehax.util.gui; - -/** Created on 9/9/2017 by fr1kin */ -public interface IGuiCheckbox extends IGuiBase { - String getText(); - - void setText(String text); - - String getHoverText(); - - void setHoverText(String text); - - boolean isChecked(); - - void setChecked(boolean checked); - - void onCheckChanged(); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/IGuiLabel.java b/src/main/java/com/matt/forgehax/util/gui/IGuiLabel.java deleted file mode 100644 index d320ae748..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/IGuiLabel.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.matt.forgehax.util.gui; - -/** Created on 9/10/2017 by fr1kin */ -public interface IGuiLabel extends IGuiBase { - String getText(); - - void setText(String text); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/IGuiPanel.java b/src/main/java/com/matt/forgehax/util/gui/IGuiPanel.java deleted file mode 100644 index bd7e1bd61..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/IGuiPanel.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.matt.forgehax.util.gui; - -/** Created on 9/9/2017 by fr1kin */ -public interface IGuiPanel extends IGuiParent { - int getBackgroundColor(); - - void setBackgroundColor(int color); - - boolean isCollapsed(); - - void setCollapsed(boolean collapsed); - - int getMaxRows(); - - void setMaxRows(int rows); - - int getMaxColumns(); - - void setMaxColumns(int columns); - - boolean isVerticalScrolling(); - - void setVerticalScrolling(boolean scrolling); - - boolean isHorizontalScrolling(); - - void setHorizontalScrolling(boolean scrolling); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/IGuiParent.java b/src/main/java/com/matt/forgehax/util/gui/IGuiParent.java deleted file mode 100644 index feaf4e012..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/IGuiParent.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.matt.forgehax.util.gui; - -import com.matt.forgehax.util.gui.events.GuiRenderEvent; -import java.util.List; -import javax.annotation.Nullable; - -/** Created on 9/9/2017 by fr1kin */ -public interface IGuiParent extends IGuiBase { - void addChild(IGuiBase element); - - void removeChild(IGuiBase element); - - void removeAllChildren(); - - List getChildren(); - - int getChildrenCount(); - - boolean focus(IGuiBase element); - - @Nullable - IGuiBase getChildInFocus(); - - void onRenderChildren(GuiRenderEvent event); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/IGuiWindow.java b/src/main/java/com/matt/forgehax/util/gui/IGuiWindow.java deleted file mode 100644 index ae583dd50..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/IGuiWindow.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.matt.forgehax.util.gui; - -/** Created on 9/15/2017 by fr1kin */ -public interface IGuiWindow extends IGuiParent { - int getBackgroundColor(); - - void setBackgroundColor(int color); - - boolean isCloseable(); - - void setCloseable(boolean closeable); - - boolean isCollapsible(); - - void setCollapsible(boolean collapsible); - - boolean isCollapsed(); - - void setCollapsed(boolean collapsed); - - boolean isDraggable(); - - void setDraggable(boolean draggable); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/CallbackList.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/CallbackList.java deleted file mode 100644 index c0efbc35a..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/CallbackList.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; -import java.util.List; -import java.util.Objects; - -/** Created on 9/16/2017 by fr1kin */ -public class CallbackList { - private final Multimap, IGuiCallbackBase> callbacks = - Multimaps.newListMultimap(Maps.newHashMap(), Lists::newArrayList); - - public boolean add(Class clazz, T callback) { - Objects.requireNonNull(callback); - return callbacks.put(clazz, callback); - } - - public boolean remove(Class clazz, T callback) { - Objects.requireNonNull(callback); - return callbacks.remove(clazz, callback); - } - - public List get(Class clazz) { - return (List) callbacks.get(clazz); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/GuiCallbacks.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/GuiCallbacks.java deleted file mode 100644 index 7c3cf0328..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/GuiCallbacks.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -import com.matt.forgehax.util.gui.IGuiBase; - -/** Created on 9/16/2017 by fr1kin */ -public class GuiCallbacks { - /* - Wrapper because I don't want to write a addCallbackblahblah for each type - */ - - public static void addButtonClickedCallback(IGuiBase base, IGuiCallbackButtonPressed callback) { - base.addCallback(IGuiCallbackButtonPressed.class, callback); - } - - public static void addCheckboxStateChangedCallback( - IGuiBase base, IGuiCallbackCheckboxStateChanged callback) { - base.addCallback(IGuiCallbackCheckboxStateChanged.class, callback); - } - - public static void addChildEventCallback(IGuiBase base, IGuiCallbackChildEvent callback) { - base.addCallback(IGuiCallbackChildEvent.class, callback); - } - - public static void addClickedCallback(IGuiBase base, IGuiCallbackClicked callback) { - base.addCallback(IGuiCallbackClicked.class, callback); - } - - public static void addFocusChangedCallback(IGuiBase base, IGuiCallbackFocus callback) { - base.addCallback(IGuiCallbackFocus.class, callback); - } - - public static void addMouseHoverStateCallback( - IGuiBase base, IGuiCallbackMouseHoverState callback) { - base.addCallback(IGuiCallbackMouseHoverState.class, callback); - } - - public static void addVisibilityChangedCallback(IGuiBase base, IGuiCallbackVisibility callback) { - base.addCallback(IGuiCallbackVisibility.class, callback); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackBase.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackBase.java deleted file mode 100644 index 708ceedad..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackBase.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiCallbackBase {} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackButtonPressed.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackButtonPressed.java deleted file mode 100644 index b5a34d7b9..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackButtonPressed.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiCallbackButtonPressed extends IGuiCallbackBase { - void onPressed(); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackCheckboxStateChanged.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackCheckboxStateChanged.java deleted file mode 100644 index 08b71701d..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackCheckboxStateChanged.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiCallbackCheckboxStateChanged extends IGuiCallbackBase { - void onCheckChanged(); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackChildEvent.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackChildEvent.java deleted file mode 100644 index 9fcb8abb2..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackChildEvent.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -import com.matt.forgehax.util.gui.IGuiBase; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiCallbackChildEvent extends IGuiCallbackBase { - void onChildAdded(IGuiBase child); - - void onChildRemoved(IGuiBase child); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackClicked.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackClicked.java deleted file mode 100644 index d82f59e51..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackClicked.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -import com.matt.forgehax.util.gui.events.GuiMouseEvent; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiCallbackClicked extends IGuiCallbackBase { - void onClicked(GuiMouseEvent event); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackFocus.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackFocus.java deleted file mode 100644 index 802f3e309..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackFocus.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiCallbackFocus extends IGuiCallbackBase { - void onFocusChanged(); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackMouseHoverState.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackMouseHoverState.java deleted file mode 100644 index cfe383933..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackMouseHoverState.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiCallbackMouseHoverState extends IGuiCallbackBase { - void onMouseHoverStateChange(); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackVisibility.java b/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackVisibility.java deleted file mode 100644 index d8bf10145..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/callbacks/IGuiCallbackVisibility.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.matt.forgehax.util.gui.callbacks; - -/** Created on 9/16/2017 by fr1kin */ -public interface IGuiCallbackVisibility extends IGuiCallbackBase { - void onVisibilityChanged(); -} diff --git a/src/main/java/com/matt/forgehax/util/gui/events/GuiKeyEvent.java b/src/main/java/com/matt/forgehax/util/gui/events/GuiKeyEvent.java deleted file mode 100644 index 3c1f34e5c..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/events/GuiKeyEvent.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.matt.forgehax.util.gui.events; - -/** Created on 9/10/2017 by fr1kin */ -public class GuiKeyEvent { - public enum Type { - PRESSED, - DOWN, - RELEASED, - ; - } - - private final Type type; - - private final int keyCode; - private final int ticks; - - private final long timePreviouslyPressed; - private final long timePressed; - - public GuiKeyEvent( - Type type, int keyCode, int ticks, long timePreviouslyPressed, long timePressed) { - this.type = type; - this.keyCode = keyCode; - this.ticks = ticks; - this.timePreviouslyPressed = timePreviouslyPressed; - this.timePressed = timePressed; - } - - /** - * Key event type - * - * @return type of key event - */ - public Type getType() { - return type; - } - - /** - * Key code for event - * - * @return key code - */ - public int getKeyCode() { - return keyCode; - } - - /** - * Number of ticks that the key has been held down for - * - * @return ticks key down - */ - public int getTicksDown() { - return ticks; - } - - /** - * Time of the previous key press - * - * @return - */ - public long getTimePreviouslyPressed() { - return timePreviouslyPressed; - } - - public long getTimePressed() { - return timePressed; - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/events/GuiMouseEvent.java b/src/main/java/com/matt/forgehax/util/gui/events/GuiMouseEvent.java deleted file mode 100644 index b8ab38440..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/events/GuiMouseEvent.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.matt.forgehax.util.gui.events; - -import com.matt.forgehax.util.gui.GuiHelper; -import com.matt.forgehax.util.gui.IGuiBase; - -/** Created on 9/10/2017 by fr1kin */ -public class GuiMouseEvent { - public static final int LEFT_MOUSE = 0; - public static final int RIGHT_MOUSE = 1; - public static final int MIDDLE_MOUSE = 2; - - public enum Type { - PRESSED, - DOWN, - RELEASED, - } - - private final Type type; - - private final int mouseCode; - - private final int mouseX; - private final int mouseY; - - private final long timePreviouslyPressed; - private final long timePressed; - - private final double delta; - - public GuiMouseEvent( - Type type, - int mouseCode, - int mouseX, - int mouseY, - double delta, - long timePreviouslyPressed, - long timePressed) { - this.type = type; - this.mouseCode = mouseCode; - this.mouseX = mouseX; - this.mouseY = mouseY; - this.delta = delta; - this.timePressed = timePressed; - this.timePreviouslyPressed = timePreviouslyPressed; - } - - public Type getType() { - return type; - } - - public int getMouseCode() { - return mouseCode; - } - - public int getMouseX() { - return mouseX; - } - - public int getMouseY() { - return mouseY; - } - - public long getTimePreviouslyPressed() { - return timePreviouslyPressed; - } - - public long getTimePressed() { - return timePressed; - } - - public double getDelta() { - return delta; - } - - public boolean isWheelMoved() { - return delta != 0; - } - - public boolean isMouseWithin(IGuiBase base) { - double rx = base.getRealX(); - double ry = base.getRealY(); - return GuiHelper.isInArea( - getMouseX(), getMouseY(), rx, ry, rx + base.getWidth(), ry + base.getHeight()); - } - - public boolean isLeftMouse() { - return mouseCode == LEFT_MOUSE; - } - - public boolean isRightMouse() { - return mouseCode == RIGHT_MOUSE; - } - - public boolean isMiddleMouse() { - return mouseCode == MIDDLE_MOUSE; - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/events/GuiRenderEvent.java b/src/main/java/com/matt/forgehax/util/gui/events/GuiRenderEvent.java deleted file mode 100644 index 964eb84c6..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/events/GuiRenderEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.matt.forgehax.util.gui.events; - -import com.matt.forgehax.util.draw.SurfaceBuilder; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; - -/** Created on 9/10/2017 by fr1kin */ -public class GuiRenderEvent { - private final SurfaceBuilder surfaceBuilder = new SurfaceBuilder(); - - private final Tessellator tessellator; - private final BufferBuilder builder; - - private final float partialTicks; - - private final int mouseX; - private final int mouseY; - - public GuiRenderEvent(Tessellator tessellator, float partialTicks, int mouseX, int mouseY) { - this.tessellator = tessellator; - this.builder = tessellator.getBuffer(); - this.partialTicks = partialTicks; - this.mouseX = mouseX; - this.mouseY = mouseY; - } - - public SurfaceBuilder getSurfaceBuilder() { - return surfaceBuilder; - } - - public Tessellator getTessellator() { - return tessellator; - } - - public BufferBuilder getBuilder() { - return builder; - } - - public float getPartialTicks() { - return partialTicks; - } - - public int getMouseX() { - return mouseX; - } - - public int getMouseY() { - return mouseY; - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/events/GuiUpdateEvent.java b/src/main/java/com/matt/forgehax/util/gui/events/GuiUpdateEvent.java deleted file mode 100644 index 2ad57b699..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/events/GuiUpdateEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.matt.forgehax.util.gui.events; - -/** Created on 9/10/2017 by fr1kin */ -public class GuiUpdateEvent { - private final int mouseX; - private final int mouseY; - - public GuiUpdateEvent(int mouseX, int mouseY) { - this.mouseX = mouseX; - this.mouseY = mouseY; - } - - public int getMouseX() { - return mouseX; - } - - public int getMouseY() { - return mouseY; - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mc/GuiParentScreen.java b/src/main/java/com/matt/forgehax/util/gui/mc/GuiParentScreen.java deleted file mode 100644 index bf02bf987..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mc/GuiParentScreen.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.matt.forgehax.util.gui.mc; - -import com.matt.forgehax.Globals; -import com.matt.forgehax.util.gui.mcgui.MParent; - -/** Created on 9/15/2017 by fr1kin */ -public class GuiParentScreen extends MParent implements Globals { - @Override - public void init(double screenWidth, double screenHeight) { - setSize(screenWidth, screenHeight); - super.init(screenWidth, screenHeight); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mc/MinecraftGuiProxy.java b/src/main/java/com/matt/forgehax/util/gui/mc/MinecraftGuiProxy.java deleted file mode 100644 index 7248eb374..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mc/MinecraftGuiProxy.java +++ /dev/null @@ -1,217 +0,0 @@ -package com.matt.forgehax.util.gui.mc; - -import com.google.common.collect.Maps; -import com.matt.forgehax.Globals; -import com.matt.forgehax.util.draw.SurfaceBuilder; -import com.matt.forgehax.util.gui.IGuiBase; -import com.matt.forgehax.util.gui.events.GuiKeyEvent; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; -import com.matt.forgehax.util.gui.events.GuiUpdateEvent; -import java.io.IOException; -import java.util.Map; -import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.gui.ScaledResolution; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.Tessellator; -import org.lwjgl.input.Keyboard; -import org.lwjgl.input.Mouse; - -/** Created on 9/12/2017 by fr1kin */ -public class MinecraftGuiProxy extends GuiScreen implements Globals { - private final IGuiBase element; - - private final Map inputs = Maps.newHashMap(); - - public MinecraftGuiProxy(IGuiBase element) { - this.element = element; - this.allowUserInput = true; - } - - @Override - public void initGui() { - inputs.clear(); - - ScaledResolution resolution = new ScaledResolution(MC); - element.init(resolution.getScaledWidth_double(), resolution.getScaledHeight_double()); - } - - @Override - public void handleKeyboardInput() throws IOException { - int keyCode = Keyboard.getEventKey(); - if (keyCode == Keyboard.KEY_NONE || keyCode >= Keyboard.KEYBOARD_SIZE) - return; // unknown key or key index greater than what lwjgl supports - - if (keyCode == Keyboard.KEY_ESCAPE) { - MC.displayGuiScreen(null); - return; - } - - InputEntry entry = - inputs.computeIfAbsent(keyCode, i -> new InputEntry(InputEntry.KEYBOARD, keyCode)); - - boolean down = Keyboard.getEventKeyState(); - long currentTimeMS = System.currentTimeMillis(); - - GuiKeyEvent.Type type; - if (entry.getTicks() < 0) { // initially pressed - if (!down) - return; // stop executing if key hasnt been initially pressed AND the key is being released - // (double release event) - type = GuiKeyEvent.Type.PRESSED; - entry.setTimePressed(currentTimeMS); // update last click time - } else { - type = down ? GuiKeyEvent.Type.DOWN : GuiKeyEvent.Type.RELEASED; - } - - // update ticks - entry.incrementTicks(); - - element.onKeyEvent( - new GuiKeyEvent( - type, - keyCode, - entry.getTicks(), - entry.getTime(), - currentTimeMS - entry.getTimePressed())); - - if (type == GuiKeyEvent.Type.RELEASED) { - entry.setTime(entry.getTimePressed()); - entry.setTimePressed(-1); - entry.resetTicks(); // reset ticks after event - } - - super.handleKeyboardInput(); - } - - @Override - public void handleMouseInput() throws IOException { - int mouseCode = Mouse.getEventButton(); - if (mouseCode < 0 || mouseCode >= Mouse.getButtonCount()) - return; // only allow number of buttons supported by mouse (for mouse event, 0 is not an - // unknown button) - - InputEntry entry = - inputs.computeIfAbsent( - Keyboard.KEYBOARD_SIZE + 1 + mouseCode, - i -> new InputEntry(InputEntry.MOUSE, mouseCode)); - - boolean down = Mouse.getEventButtonState(); - long currentTimeMS = System.currentTimeMillis(); - - GuiMouseEvent.Type type; - if (entry.getTicks() < 0) { // initially pressed - if (!down) - return; // stop executing if key hasnt been initially pressed AND the key is being released - // (double release event) - type = GuiMouseEvent.Type.PRESSED; - entry.setTimePressed(currentTimeMS); // update last click time - } else { - type = down ? GuiMouseEvent.Type.DOWN : GuiMouseEvent.Type.RELEASED; - } - - // update ticks - entry.incrementTicks(); - - int[] mpos = getMousePos(); - element.onMouseEvent( - new GuiMouseEvent( - type, - mouseCode, - mpos[0], - mpos[1], - Mouse.getEventDWheel(), - entry.getTime(), - currentTimeMS - entry.getTimePressed())); - - if (type == GuiMouseEvent.Type.RELEASED) { - entry.setTime(entry.getTimePressed()); - entry.setTimePressed(-1); - entry.resetTicks(); // reset ticks after event - } - - super.handleMouseInput(); - } - - @Override - public void updateScreen() { - int[] mpos = getMousePos(); - element.onUpdate(new GuiUpdateEvent(mpos[0], mpos[1])); - } - - @Override - public void drawScreen(int mouseX, int mouseY, float partialTicks) { - GlStateManager.pushMatrix(); - SurfaceBuilder.enableBlend(); - SurfaceBuilder.disableTexture2D(); - - element.onRender(new GuiRenderEvent(Tessellator.getInstance(), partialTicks, mouseX, mouseY)); - - SurfaceBuilder.disableBlend(); - SurfaceBuilder.enableTexture2D(); - GlStateManager.popMatrix(); - } - - private static int[] getMousePos() { - ScaledResolution resolution = new ScaledResolution(MC); - int width = resolution.getScaledWidth(); - int height = resolution.getScaledHeight(); - int mouseX = Mouse.getX() * width / MC.displayWidth; - int mouseY = height - Mouse.getY() * height / MC.displayHeight - 1; - return new int[] {mouseX, mouseY}; - } - - private static class InputEntry { - private static final int KEYBOARD = 0; - private static final int MOUSE = 1; - - private final int type; - private final int code; - - private int ticks = -1; - private long time = -1; - - private long timePressed = -1; - - public InputEntry(int type, int code) { - this.type = type; - this.code = code; - } - - public int getTicks() { - return ticks; - } - - public void incrementTicks() { - ++ticks; - } - - public void resetTicks() { - ticks = -1; - } - - public long getTime() { - return time; - } - - public void setTime(long time) { - this.time = time; - } - - public long getTimePressed() { - return timePressed; - } - - public void setTimePressed(long timePressed) { - this.timePressed = timePressed; - } - - @Override - public boolean equals(Object obj) { - return this == obj - || (obj instanceof InputEntry - && type == ((InputEntry) obj).type - && code == ((InputEntry) obj).code); - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mcgui/ImmutableGuiBase.java b/src/main/java/com/matt/forgehax/util/gui/mcgui/ImmutableGuiBase.java deleted file mode 100644 index e23020163..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mcgui/ImmutableGuiBase.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.matt.forgehax.util.gui.mcgui; - -import com.matt.forgehax.util.gui.IGuiBase; -import com.matt.forgehax.util.gui.IGuiParent; -import com.matt.forgehax.util.gui.callbacks.IGuiCallbackBase; -import com.matt.forgehax.util.gui.events.GuiKeyEvent; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; -import com.matt.forgehax.util.gui.events.GuiUpdateEvent; -import javax.annotation.Nullable; -import uk.co.hexeption.thx.ttf.MinecraftFontRenderer; - -/** Created on 9/17/2017 by fr1kin */ -public class ImmutableGuiBase implements IGuiBase { - @Override - public void init(double screenWidth, double screenHeight) {} - - @Override - public double getX() { - return 0; - } - - @Override - public double getY() { - return 0; - } - - @Override - public void setX(double x) {} - - @Override - public void setY(double y) {} - - @Override - public double getWidth() { - return 0; - } - - @Override - public double getHeight() { - return 0; - } - - @Override - public void setWidth(double w) {} - - @Override - public void setHeight(double h) {} - - @Override - public boolean isVisible() { - return false; - } - - @Override - public void setVisible(boolean visible) {} - - @Override - public boolean isLocked() { - return true; - } - - @Override - public void setLocked(boolean locked) {} - - @Nullable - @Override - public IGuiParent getParent() { - return null; - } - - @Override - public void setParent(@Nullable IGuiParent parent) {} - - @Override - public boolean isHovered() { - return false; - } - - @Override - public int getHoveredTime() { - return 0; - } - - @Override - public boolean isInFocus() { - return false; - } - - @Override - public boolean requestFocus() { - return false; - } - - @Override - public int getFocusTime() { - return 0; - } - - @Nullable - @Override - public MinecraftFontRenderer getFontRenderer() { - return null; - } - - @Override - public void setFontRenderer(MinecraftFontRenderer fontRenderer) {} - - @Override - public int getFontColor() { - return 0; - } - - @Override - public void setFontColor(int buffer) {} - - @Override - public void onUpdateSize() {} - - @Override - public void onMouseEvent(GuiMouseEvent event) {} - - @Override - public void onKeyEvent(GuiKeyEvent event) {} - - @Override - public void onUpdate(GuiUpdateEvent event) {} - - @Override - public void onRender(GuiRenderEvent event) {} - - @Override - public void onRenderPreBackground(GuiRenderEvent event) {} - - @Override - public void onRenderPostBackground(GuiRenderEvent event) {} - - @Override - public void addCallback(Class clazz, T callback) {} - - @Override - public void removeCallback(Class clazz, T callback) {} - - @Override - public void onVisibleChange() {} - - @Override - public void onFocusChanged() {} - - @Override - public void onMouseHoverStateChange() {} - - @Override - public void onClicked(GuiMouseEvent event) {} -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mcgui/MBase.java b/src/main/java/com/matt/forgehax/util/gui/mcgui/MBase.java deleted file mode 100644 index d5da7afe4..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mcgui/MBase.java +++ /dev/null @@ -1,274 +0,0 @@ -package com.matt.forgehax.util.gui.mcgui; - -import com.matt.forgehax.util.Utils; -import com.matt.forgehax.util.gui.GuiHelper; -import com.matt.forgehax.util.gui.IGuiBase; -import com.matt.forgehax.util.gui.IGuiParent; -import com.matt.forgehax.util.gui.callbacks.*; -import com.matt.forgehax.util.gui.events.GuiKeyEvent; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; -import com.matt.forgehax.util.gui.events.GuiUpdateEvent; -import javax.annotation.Nullable; -import uk.co.hexeption.thx.ttf.MinecraftFontRenderer; - -/** Created on 9/9/2017 by fr1kin */ -public class MBase implements IGuiBase { - protected final CallbackList callbacks = new CallbackList(); - - private double x = 0; - private double y = 0; - - private double width = 0; - private double height = 0; - - private boolean visible = true; - private boolean locked = false; - - private IGuiParent parent = null; - - private boolean hovered = false; - private int hoveredTime = 0; - - private int focusTime = 0; - - private MinecraftFontRenderer fontRenderer = null; - private Integer fontColor = null; - - @Override - public void init(double screenWidth, double screenHeight) { - focusTime = 0; - hoveredTime = 0; - hovered = false; - onUpdateSize(); - } - - @Override - public double getX() { - return x; - } - - @Override - public double getY() { - return y; - } - - @Override - public void setX(double x) { - this.x = x; - } - - @Override - public void setY(double y) { - this.y = y; - } - - @Override - public double getWidth() { - return width; - } - - @Override - public double getHeight() { - return height; - } - - @Override - public void setWidth(double w) { - this.width = w; - } - - @Override - public void setHeight(double h) { - this.height = h; - } - - @Override - public boolean isVisible() { - return visible; - } - - @Override - public void setVisible(boolean visible) { - if (visible != this.visible) { - this.visible = visible; - onVisibleChange(); - } - } - - @Override - public boolean isLocked() { - return locked; - } - - @Override - public void setLocked(boolean locked) { - this.locked = locked; - } - - @Override - public IGuiParent getParent() { - return parent; - } - - @Override - public void setParent(IGuiParent parent) { - if (this.parent == parent) return; // no need to continue - if (parent == null && this.parent != null) { // remove parent and don't add another - IGuiParent oldParent = this.parent; - this.parent = null; - oldParent.removeChild(this); - } else { - if (this.parent != null) { // remove from old parent - IGuiParent oldParent = this.parent; - this.parent = null; - oldParent.removeChild(this); - } - this.parent = parent; - this.parent.addChild(this); - } - onUpdateSize(); - } - - @Override - public boolean isHovered() { - return hovered; - } - - @Override - public int getHoveredTime() { - return hoveredTime; - } - - @Override - public boolean isInFocus() { - return getParent() == null || getParent().isInFocus() && getParent().getChildInFocus() == this; - } - - @Override - public boolean requestFocus() { - return getParent() != null && getParent().focus(this); - } - - @Override - public int getFocusTime() { - return focusTime; - } - - @Nullable - @Override - public MinecraftFontRenderer getFontRenderer() { - return fontRenderer != null - ? fontRenderer - : (getParent() != null ? getParent().getFontRenderer() : null); - } - - @Override - public void setFontRenderer(MinecraftFontRenderer fontRenderer) { - this.fontRenderer = fontRenderer; - onUpdateSize(); - } - - @Override - public int getFontColor() { - return fontColor != null - ? fontColor - : (getParent() != null ? getParent().getFontColor() : Utils.Colors.WHITE); - } - - @Override - public void setFontColor(int buffer) { - this.fontColor = buffer; - } - - @Override - public void onUpdateSize() {} - - @Override - public void onMouseEvent(GuiMouseEvent event) { - switch (event.getType()) { - case PRESSED: - { - if (event.isMouseWithin(this)) onClicked(event); - break; - } - } - } - - @Override - public void onKeyEvent(GuiKeyEvent event) {} - - @Override - public void onUpdate(GuiUpdateEvent event) { - // check if mouse is hovered over - double rx = getRealX(); - double ry = getRealY(); - boolean previous = this.hovered; - if (GuiHelper.isInArea( - event.getMouseX(), event.getMouseY(), rx, ry, rx + getWidth(), ry + getHeight())) { - this.hovered = true; - this.hoveredTime++; - if (!previous) onMouseHoverStateChange(); - } else { - this.hovered = false; - this.hoveredTime = 0; - if (previous) onMouseHoverStateChange(); - } - - // update focus time - if (isInFocus()) this.focusTime++; - else this.focusTime = 0; - } - - @Override - public void onRender(GuiRenderEvent event) { - onRenderPreBackground(event); - - onRenderPostBackground(event); - } - - @Override - public void onRenderPreBackground(GuiRenderEvent event) {} - - @Override - public void onRenderPostBackground(GuiRenderEvent event) {} - - @Override - public void addCallback(Class clazz, T callback) { - callbacks.add(clazz, callback); - } - - @Override - public void removeCallback(Class clazz, T callback) { - callbacks.remove(clazz, callback); - } - - @Override - public void onVisibleChange() { - if (!isVisible()) { - focusTime = 0; - hoveredTime = 0; - hovered = false; - } - callbacks - .get(IGuiCallbackVisibility.class) - .forEach(IGuiCallbackVisibility::onVisibilityChanged); - } - - @Override - public void onFocusChanged() { - callbacks.get(IGuiCallbackFocus.class).forEach(IGuiCallbackFocus::onFocusChanged); - } - - @Override - public void onMouseHoverStateChange() { - callbacks - .get(IGuiCallbackMouseHoverState.class) - .forEach(IGuiCallbackMouseHoverState::onMouseHoverStateChange); - } - - @Override - public void onClicked(final GuiMouseEvent event) { - callbacks.get(IGuiCallbackClicked.class).forEach(listener -> listener.onClicked(event)); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mcgui/MButton.java b/src/main/java/com/matt/forgehax/util/gui/mcgui/MButton.java deleted file mode 100644 index c1ac7cb30..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mcgui/MButton.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.matt.forgehax.util.gui.mcgui; - -import com.matt.forgehax.util.Utils; -import com.matt.forgehax.util.draw.SurfaceBuilder; -import com.matt.forgehax.util.draw.SurfaceHelper; -import com.matt.forgehax.util.gui.IGuiButton; -import com.matt.forgehax.util.gui.callbacks.IGuiCallbackButtonPressed; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; - -/** Created on 9/16/2017 by fr1kin */ -public class MButton extends MBase implements IGuiButton { - private boolean pressed = true; - - private String text = ""; - private String hoverText = ""; - - private int backgroundColor = Utils.Colors.WHITE; - - @Override - public int getBackgroundColor() { - return backgroundColor; - } - - @Override - public void setBackgroundColor(int color) { - this.backgroundColor = color; - } - - @Override - public boolean isPressed() { - return pressed; - } - - @Override - public void setPressed(boolean pressed) { - if (pressed != this.pressed) { - this.pressed = pressed; - onPressed(); - } - } - - @Override - public String getText() { - return text; - } - - @Override - public void setText(String text) { - this.text = text; - onUpdateSize(); - } - - @Override - public String getHoverText() { - return hoverText; - } - - @Override - public void setHoverText(String text) { - this.hoverText = text; - } - - @Override - public void onPressed() { - callbacks.get(IGuiCallbackButtonPressed.class).forEach(IGuiCallbackButtonPressed::onPressed); - } - - @Override - public void onClicked(GuiMouseEvent event) { - if (event.isLeftMouse()) setPressed(!isPressed()); - super.onClicked(event); - } - - @Override - public void onRenderPreBackground(GuiRenderEvent event) { - event - .getSurfaceBuilder() - .task(SurfaceBuilder::clearColor) - .task(SurfaceBuilder::disableTexture2D) - .task(SurfaceBuilder::enableBlend) - .push() - .translate(getX(), getY()) - .color(isPressed() ? Utils.Colors.GREEN : getBackgroundColor()) - .beginQuads() - .rectangle(0, 0, getWidth(), getHeight()) - .end() - .color(Utils.toRGBA(0, 0, 0, 255)) - .beginLineLoop() - .rectangle(0, 0, getWidth(), getHeight()) - .end() - .pop() - .task(SurfaceBuilder::disableFontRendering) - .task(SurfaceBuilder::disableBlend); - - // GL11.glScissor((int)getX(), (int)getY(), (int)getWidth(), (int)getHeight()); - // GL11.glEnable(GL11.GL_SCISSOR_TEST); - - double strWidth = SurfaceHelper.getStringWidth(getFontRenderer(), getText()); - double strHeight = SurfaceHelper.getStringHeight(getFontRenderer()); - - event - .getSurfaceBuilder() - .push() - .task(SurfaceBuilder::enableTexture2D) - .task(SurfaceBuilder::enableFontRendering) - .task(SurfaceBuilder::enableBlend) - .fontRenderer(getFontRenderer()) - .color(getFontColor()) - .text( - getText(), - getX() + (getWidth() / 2) - (strWidth / 2), - getY() + (getHeight() / 2) - (strHeight / 2)) - .task(SurfaceBuilder::disableFontRendering) - .task(SurfaceBuilder::disableBlend) - .pop(); - - // GL11.glDisable(GL11.GL_SCISSOR_TEST); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mcgui/MCheckbox.java b/src/main/java/com/matt/forgehax/util/gui/mcgui/MCheckbox.java deleted file mode 100644 index de3cfff5f..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mcgui/MCheckbox.java +++ /dev/null @@ -1,162 +0,0 @@ -package com.matt.forgehax.util.gui.mcgui; - -import com.matt.forgehax.util.Utils; -import com.matt.forgehax.util.draw.SurfaceBuilder; -import com.matt.forgehax.util.draw.SurfaceHelper; -import com.matt.forgehax.util.gui.IGuiCheckbox; -import com.matt.forgehax.util.gui.callbacks.IGuiCallbackCheckboxStateChanged; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; - -/** Created on 9/9/2017 by fr1kin */ -public class MCheckbox extends MBase implements IGuiCheckbox { - public static final int CHECKBOX_SIZE = 10; - public static final int BUFFER_SIZE = 2; - - private String text = ""; - private String hoverText = ""; - - private boolean checked = false; - - @Override - public String getText() { - return text; - } - - @Override - public void setText(String text) { - this.text = text; - onUpdateSize(); - } - - @Override - public String getHoverText() { - return hoverText; - } - - @Override - public void setHoverText(String text) { - this.hoverText = text; - } - - @Override - public boolean isChecked() { - return checked; - } - - @Override - public void setChecked(boolean checked) { - if (checked != this.checked) { - this.checked = checked; - onCheckChanged(); - } - } - - @Override - public void onCheckChanged() { - callbacks - .get(IGuiCallbackCheckboxStateChanged.class) - .forEach(IGuiCallbackCheckboxStateChanged::onCheckChanged); - } - - @Override - public void onUpdateSize() { - super.onUpdateSize(); - setWidth( - SurfaceHelper.getStringWidth(getFontRenderer(), getText()) + BUFFER_SIZE + CHECKBOX_SIZE); - setHeight(Math.max(CHECKBOX_SIZE, SurfaceHelper.getStringHeight(getFontRenderer()))); - } - - @Override - public void onClicked(GuiMouseEvent event) { - if (event.isLeftMouse()) setChecked(!isChecked()); - super.onClicked(event); - } - - @Override - public void onRenderPreBackground(GuiRenderEvent event) { - double fontHeight = SurfaceHelper.getStringHeight(getFontRenderer()); - - // draw check mark box - event - .getSurfaceBuilder() - .push() - .task(SurfaceBuilder::clearColor) - .task(SurfaceBuilder::disableTexture2D) - .task(SurfaceBuilder::enableBlend) - .translate(getX(), getY()) - .color(Utils.Colors.BLACK) - .beginQuads() - .rectangle(0, 0, CHECKBOX_SIZE, CHECKBOX_SIZE) - .end() - .color(Utils.Colors.WHITE) - .beginQuads() - .rectangle(1, 1, CHECKBOX_SIZE - 2, CHECKBOX_SIZE - 2) - .end() - .task(SurfaceBuilder::enableTexture2D) - .task(SurfaceBuilder::disableBlend) - .pop(); - - if (isChecked()) { - event - .getSurfaceBuilder() - .push() - .task(SurfaceBuilder::clearColor) - .task(SurfaceBuilder::disableTexture2D) - .task(SurfaceBuilder::enableBlend) - .translate(getX(), getY()) - .color(Utils.Colors.GREEN) - .beginQuads() - .rectangle(2, 2, CHECKBOX_SIZE - 4, CHECKBOX_SIZE - 4) - .end() - .task(SurfaceBuilder::enableTexture2D) - .task(SurfaceBuilder::disableBlend) - .pop(); - } - - event - .getSurfaceBuilder() - .push() - .task(SurfaceBuilder::enableTexture2D) - .task(SurfaceBuilder::enableFontRendering) - .task(SurfaceBuilder::enableBlend) - .fontRenderer(getFontRenderer()) - .color(getFontColor()) - .text( - getText(), - getX() + CHECKBOX_SIZE + BUFFER_SIZE, - getY() - (fontHeight / 2) + (CHECKBOX_SIZE / 2)) - .task(SurfaceBuilder::disableFontRendering) - .task(SurfaceBuilder::disableBlend) - .pop(); - - if (isHovered() && getHoveredTime() > 10) { - double rx = getParent() == null ? 0.D : getParent().getRealX(); - double ry = getParent() == null ? 0.D : getParent().getRealY(); - - event - .getSurfaceBuilder() - .push() - .translate(-rx + event.getMouseX() + 10, -ry + event.getMouseY() - fontHeight) - .task(SurfaceBuilder::clearColor) - .task(SurfaceBuilder::disableTexture2D) - .task(SurfaceBuilder::enableBlend) - .color(Utils.Colors.BLACK) - .beginQuads() - .rectangle( - -2, - -2, - SurfaceHelper.getStringWidth(getFontRenderer(), getHoverText()) + 4, - fontHeight + 4) - .end() - .task(SurfaceBuilder::enableTexture2D) - .task(SurfaceBuilder::enableFontRendering) - .fontRenderer(getFontRenderer()) - .color(getFontColor()) - .text(getHoverText(), 0, 0) - .task(SurfaceBuilder::disableFontRendering) - .task(SurfaceBuilder::disableBlend) - .pop(); - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mcgui/MLabel.java b/src/main/java/com/matt/forgehax/util/gui/mcgui/MLabel.java deleted file mode 100644 index 3afe907b1..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mcgui/MLabel.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.matt.forgehax.util.gui.mcgui; - -import com.matt.forgehax.util.draw.SurfaceBuilder; -import com.matt.forgehax.util.draw.SurfaceHelper; -import com.matt.forgehax.util.gui.IGuiLabel; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; - -/** Created on 9/10/2017 by fr1kin */ -public class MLabel extends MBase implements IGuiLabel { - private String text = ""; - - @Override - public String getText() { - return text; - } - - @Override - public void setText(String text) { - this.text = text; - onUpdateSize(); - } - - @Override - public void onUpdateSize() { - setWidth(SurfaceHelper.getStringWidth(getFontRenderer(), getText())); - setHeight(SurfaceHelper.getStringHeight(getFontRenderer())); - } - - @Override - public void onRenderPreBackground(GuiRenderEvent event) { - if (isHovered()) { - event - .getSurfaceBuilder() - .push() - .task(SurfaceBuilder::clearColor) - .task(SurfaceBuilder::disableTexture2D) - .task(SurfaceBuilder::enableBlend) - .color(255, 0, 0, 150) - .beginQuads() - .rectangle(getX(), getY(), getWidth(), getHeight()) - .end() - .task(SurfaceBuilder::enableTexture2D) - .task(SurfaceBuilder::disableBlend) - .pop(); - } - - event - .getSurfaceBuilder() - .push() - .task(SurfaceBuilder::enableTexture2D) - .task(SurfaceBuilder::enableFontRendering) - .task(SurfaceBuilder::enableBlend) - .fontRenderer(getFontRenderer()) - .color(getFontColor()) - .text(getText(), getX(), getY()) - .task(SurfaceBuilder::disableFontRendering) - .task(SurfaceBuilder::disableBlend) - .pop(); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mcgui/MPanel.java b/src/main/java/com/matt/forgehax/util/gui/mcgui/MPanel.java deleted file mode 100644 index eaa494c60..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mcgui/MPanel.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.matt.forgehax.util.gui.mcgui; - -import com.matt.forgehax.util.Utils; -import com.matt.forgehax.util.draw.SurfaceBuilder; -import com.matt.forgehax.util.gui.IGuiPanel; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; - -/** Created on 9/9/2017 by fr1kin */ -public class MPanel extends MParent implements IGuiPanel { - private boolean collapsed = false; - - private int maxRows = Integer.MAX_VALUE; - private int maxColumns = 1; - - private boolean verticalScrolling = false; - private boolean horizontalScrolling = false; - - private int backgroundColor = Utils.Colors.WHITE; - - @Override - public int getBackgroundColor() { - return backgroundColor; - } - - @Override - public void setBackgroundColor(int color) { - this.backgroundColor = color; - } - - @Override - public boolean isCollapsed() { - return collapsed; - } - - @Override - public void setCollapsed(boolean collapsed) { - this.collapsed = true; - } - - @Override - public int getMaxRows() { - return maxRows; - } - - @Override - public void setMaxRows(int rows) { - this.maxRows = Math.max(1, rows); - } - - @Override - public int getMaxColumns() { - return maxColumns; - } - - @Override - public void setMaxColumns(int columns) { - this.maxColumns = Math.max(1, columns); - } - - @Override - public boolean isVerticalScrolling() { - return verticalScrolling; - } - - @Override - public void setVerticalScrolling(boolean scrolling) { - this.verticalScrolling = scrolling; - } - - @Override - public boolean isHorizontalScrolling() { - return horizontalScrolling; - } - - @Override - public void setHorizontalScrolling(boolean scrolling) { - this.horizontalScrolling = scrolling; - } - - @Override - public void onClicked(GuiMouseEvent event) { - requestFocus(); // request focus on click - - super.onClicked(event); - } - - @Override - public void onRenderPreBackground(GuiRenderEvent event) { - super.onRenderPreBackground(event); - - event - .getSurfaceBuilder() - .task(SurfaceBuilder::clearColor) - .task(SurfaceBuilder::disableTexture2D) - .task(SurfaceBuilder::enableBlend) - .push() - .color(getBackgroundColor()) - .beginQuads() - .rectangle(getX(), getY(), getWidth(), getHeight()) - .end() - .color(0, 0, 0, 255) - .beginLineLoop() - .rectangle(getX(), getY(), getWidth(), getHeight()) - .end() - .pop() - .task(SurfaceBuilder::disableFontRendering) - .task(SurfaceBuilder::disableBlend); - - /* - .line(getX(), getY(), getX(), getY() + getHeight()) - .line(getX(), getY() + getHeight(), getX() + getWidth(), getY() + getHeight()) - .line(getX() + getWidth(), getY() + getHeight(), getX() + getWidth(), getY()) - .line(getX() + getWidth(), getY(), getX(), getY()) - */ - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mcgui/MParent.java b/src/main/java/com/matt/forgehax/util/gui/mcgui/MParent.java deleted file mode 100644 index 1b1333ac0..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mcgui/MParent.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.matt.forgehax.util.gui.mcgui; - -import com.google.common.collect.Lists; -import com.matt.forgehax.util.gui.GuiHelper; -import com.matt.forgehax.util.gui.IGuiBase; -import com.matt.forgehax.util.gui.IGuiParent; -import com.matt.forgehax.util.gui.callbacks.IGuiCallbackChildEvent; -import com.matt.forgehax.util.gui.events.GuiKeyEvent; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; -import com.matt.forgehax.util.gui.events.GuiUpdateEvent; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import javax.annotation.Nullable; -import net.minecraft.client.renderer.GlStateManager; - -/** Created on 9/15/2017 by fr1kin */ -public class MParent extends MBase implements IGuiParent { - protected final List children = Lists.newCopyOnWriteArrayList(); - - @Override - public void addChild(IGuiBase element) { - if (!children.contains(element) && children.add(element)) { - element.setParent(this); - focus(element); // to invoke focus callbacks and add to head - callbacks - .get(IGuiCallbackChildEvent.class) - .forEach(listener -> listener.onChildAdded(element)); - } - } - - @Override - public void removeChild(IGuiBase element) { - if (children.remove(element)) { - element.setParent(null); - callbacks - .get(IGuiCallbackChildEvent.class) - .forEach(listener -> listener.onChildRemoved(element)); - } - } - - @Override - public void removeAllChildren() { - children.forEach(this::removeChild); - } - - @Override - public List getChildren() { - return Collections.unmodifiableList(children); - } - - @Override - public int getChildrenCount() { - return children.size(); - } - - @Override - public boolean focus(IGuiBase element) { - if (this == element.getParent() && element != getChildInFocus()) { - Optional previous = - Optional.ofNullable(getChildInFocus()).filter(gui -> element != gui); - - children.remove(element); // remove from list - children.add(0, element); // readd at head of the stack - - previous.ifPresent(IGuiBase::onFocusChanged); - - element.onFocusChanged(); - - return true; - } else return false; - } - - @Nullable - @Override - public IGuiBase getChildInFocus() { - return children.isEmpty() ? null : children.get(0); - } - - @Override - public void onRenderChildren(GuiRenderEvent event) { - for (int i = children.size() - 1; - i >= 0; - --i) { // since rendering last = top, we must iterate the list backwards for rendering - IGuiBase gui = children.get(i); - if (gui.isVisible()) { - GlStateManager.pushMatrix(); - GlStateManager.translate(getX(), getY(), 0.D); - - gui.onRender(event); - - GlStateManager.popMatrix(); - } - } - } - - @Override - public void init(double screenWidth, double screenHeight) { - super.init(screenWidth, screenHeight); - - for (IGuiBase gui : children) - if (gui.isVisible()) { - gui.init(screenWidth, screenHeight); - } - } - - @Override - public void onUpdateSize() { - super.onUpdateSize(); - for (IGuiBase gui : children) - if (gui.isVisible()) { - gui.onUpdateSize(); - } - } - - @Override - public void onMouseEvent(GuiMouseEvent event) { - Optional gui = GuiHelper.getTopGuiAt(this, event.getMouseX(), event.getMouseY()); - if (gui.isPresent()) gui.get().onMouseEvent(event); - else super.onMouseEvent(event); - } - - @Override - public void onKeyEvent(GuiKeyEvent event) { - super.onKeyEvent(event); - - // TODO: there will always be a child on top, need a find a way to give focus only to 1 at a - // time - Optional.ofNullable(getChildInFocus()) - .filter(IGuiBase::isVisible) - .ifPresent(gui -> gui.onKeyEvent(event)); - } - - @Override - public void onUpdate(GuiUpdateEvent event) { - super.onUpdate(event); - - // update children if visible - for (IGuiBase gui : children) if (gui.isVisible()) gui.onUpdate(event); - } - - @Override - public void onRender(GuiRenderEvent event) { - // don't call super - - onRenderPreBackground(event); - - onRenderChildren(event); - - onRenderPostBackground(event); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/mcgui/MWindow.java b/src/main/java/com/matt/forgehax/util/gui/mcgui/MWindow.java deleted file mode 100644 index f67a502b3..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/mcgui/MWindow.java +++ /dev/null @@ -1,251 +0,0 @@ -package com.matt.forgehax.util.gui.mcgui; - -import com.matt.forgehax.util.Utils; -import com.matt.forgehax.util.draw.SurfaceBuilder; -import com.matt.forgehax.util.gui.GuiHelper; -import com.matt.forgehax.util.gui.IGuiWindow; -import com.matt.forgehax.util.gui.callbacks.GuiCallbacks; -import com.matt.forgehax.util.gui.events.GuiMouseEvent; -import com.matt.forgehax.util.gui.events.GuiRenderEvent; - -/** Created on 9/15/2017 by fr1kin */ -public class MWindow extends MParent implements IGuiWindow { - public static final double BAR_HEIGHT = 20; - public static final double BUTTON_SIZE = 7; - public static final double BUFFER = 2; - - private final MButton closeButton = new MButton(); - private final MButton collapseButton = new MButton(); - - private boolean closeable = true; - private boolean collapsible = true; - private boolean draggable = true; - - private boolean dragging = false; - - private double dragX = 0.D; - private double dragY = 0.D; - - private int backgroundColor = Utils.Colors.WHITE; - - public MWindow() { - closeButton.setText("X"); - closeButton.setFontColor(Utils.Colors.BLACK); - closeButton.setParent(this); - closeButton.setSize(BUTTON_SIZE, BUTTON_SIZE); - closeButton.setVisible(isCloseable()); - - collapseButton.setText("-"); - collapseButton.setFontColor(Utils.Colors.BLACK); - collapseButton.setParent(this); - collapseButton.setSize(BUTTON_SIZE, BUTTON_SIZE); - collapseButton.setVisible(isCollapsible()); - GuiCallbacks.addButtonClickedCallback( - collapseButton, - () -> { - collapseButton.setText(isCollapsed() ? "+" : "-"); - children - .stream() - .filter(gui -> gui != closeButton && gui != collapseButton) - .forEach(gui -> gui.setVisible(collapseButton.isPressed())); - }); - - repositionButtons(); - } - - private void repositionButtons() { - if (isCloseable()) { - closeButton.setX(getWidth() - closeButton.getWidth() - BUFFER); - closeButton.setY(BAR_HEIGHT / 2 - closeButton.getHeight() / 2); - } - - if (isCollapsible()) { - collapseButton.setX( - (isCloseable() ? closeButton.getX() : getWidth()) - collapseButton.getWidth() - BUFFER); - collapseButton.setY(BAR_HEIGHT / 2 - collapseButton.getHeight() / 2); - } - } - - @Override - public int getBackgroundColor() { - return backgroundColor; - } - - @Override - public void setBackgroundColor(int color) { - this.backgroundColor = color; - } - - @Override - public boolean isCloseable() { - return closeable; - } - - @Override - public void setCloseable(boolean closeable) { - if (closeable != this.closeable) { - this.closeable = closeable; - repositionButtons(); - } - } - - @Override - public boolean isCollapsible() { - return collapsible; - } - - @Override - public void setCollapsible(boolean collapsible) { - if (collapsible != this.collapsible) { - this.collapsible = collapsible; - repositionButtons(); - } - } - - @Override - public boolean isCollapsed() { - return !collapseButton.isPressed(); - } - - @Override - public void setCollapsed(boolean collapsed) { - collapseButton.setPressed(collapsed); - } - - @Override - public boolean isDraggable() { - return draggable; - } - - @Override - public void setDraggable(boolean draggable) { - this.draggable = draggable; - } - - @Override - public void onClicked(GuiMouseEvent event) { - requestFocus(); - super.onClicked(event); - } - - @Override - public double getHeight() { - return isCollapsed() ? BAR_HEIGHT : super.getHeight(); - } - - @Override - public void setHeight(double h) { - super.setHeight(Math.max(h, BAR_HEIGHT)); - } - - @Override - public boolean isVisible() { - return closeButton.isPressed(); - } - - @Override - public void setVisible(boolean visible) { - if (visible != closeButton.isPressed()) { - closeButton.setPressed(visible); - onVisibleChange(); - } - } - - @Override - public void onFocusChanged() { - if (!isInFocus()) { - // focus lost - dragging = false; - } - super.onFocusChanged(); - } - - @Override - public void onUpdateSize() { - repositionButtons(); - - super.onUpdateSize(); - } - - @Override - public void onMouseEvent(GuiMouseEvent event) { - super.onMouseEvent(event); - - if (event.isLeftMouse() - && GuiHelper.isInRectangle( - event.getMouseX(), event.getMouseY(), getRealX(), getRealY(), getWidth(), BAR_HEIGHT)) { - switch (event.getType()) { - case PRESSED: - dragging = true; - case DOWN: - { - dragX = event.getMouseX() - getRealX(); - dragY = event.getMouseY() - getRealY(); - break; - } - case RELEASED: - dragging = false; - break; - } - } - } - - @Override - public void onRender(GuiRenderEvent event) { - if (isDraggable() && dragging) { - setX(event.getMouseX() - dragX); - setY(event.getMouseY() - dragY); - } - - super.onRender(event); - } - - @Override - public void onRenderPreBackground(GuiRenderEvent event) { - super.onRenderPreBackground(event); - - event - .getSurfaceBuilder() - .task(SurfaceBuilder::clearColor) - .task(SurfaceBuilder::disableTexture2D) - .task(SurfaceBuilder::enableBlend); - - // bar - event - .getSurfaceBuilder() - .push() - .color(getBackgroundColor()) - .beginQuads() - .rectangle(getX(), getY(), getWidth(), BAR_HEIGHT) - .end() - .color(0, 0, 0, 255) - .beginLineLoop() - .rectangle(getX(), getY(), getWidth(), BAR_HEIGHT) - .end() - .pop(); - - // bar headings - if (isCloseable() || isCollapsible()) {} - - // actual window - if (getHeight() > BAR_HEIGHT && !isCollapsed()) { - event - .getSurfaceBuilder() - .push() - .color(getBackgroundColor()) - .beginQuads() - .rectangle(getX(), getY() + BAR_HEIGHT, getWidth(), getHeight() - BAR_HEIGHT) - .end() - .color(0, 0, 0, 255) - .beginLineLoop() - .rectangle(getX(), getY() + BAR_HEIGHT, getWidth(), getHeight() - BAR_HEIGHT) - .end() - .pop(); - } - - event - .getSurfaceBuilder() - .task(SurfaceBuilder::disableFontRendering) - .task(SurfaceBuilder::disableBlend); - } -} diff --git a/src/main/java/com/matt/forgehax/util/gui/test/GuiTestMain.java b/src/main/java/com/matt/forgehax/util/gui/test/GuiTestMain.java deleted file mode 100644 index 0ecc1afb4..000000000 --- a/src/main/java/com/matt/forgehax/util/gui/test/GuiTestMain.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.matt.forgehax.util.gui.test; - -import com.matt.forgehax.util.Utils; -import com.matt.forgehax.util.draw.Fonts; -import com.matt.forgehax.util.gui.mc.GuiParentScreen; -import com.matt.forgehax.util.gui.mcgui.MButton; -import com.matt.forgehax.util.gui.mcgui.MCheckbox; -import com.matt.forgehax.util.gui.mcgui.MLabel; -import com.matt.forgehax.util.gui.mcgui.MWindow; - -/** Created on 9/12/2017 by fr1kin */ -public class GuiTestMain extends GuiParentScreen { - - public GuiTestMain() { - setFontRenderer(Fonts.ARIAL); - - MWindow window = new MWindow(); - window.setParent(this); - - window.setPos(50, 50); - window.setSize(100, 100); - - window.setBackgroundColor(Utils.toRGBA(255, 0, 0, 150)); - - window.setFontColor(Utils.Colors.WHITE); - window.setFontRenderer(Fonts.ARIAL); - - String[] labels = new String[] {"Hello", "These", "Are", "Labels"}; - - double h = 0; - for (int i = 0; i < labels.length; i++) { - MLabel label = new MLabel(); - label.setParent(window); - label.setText(labels[i]); - label.setFontColor(Utils.Colors.WHITE); - label.setPos(1, MWindow.BAR_HEIGHT + (i * label.getHeight() + 2)); - h = label.getHeight(); - } - - MCheckbox checkbox = new MCheckbox(); - checkbox.setParent(window); - checkbox.setText("Hello"); - checkbox.setHoverText("This is a checkbox"); - checkbox.setPos(1, MWindow.BAR_HEIGHT + (labels.length * h + 2)); - - // panel2 - MWindow window2 = new MWindow(); - window2.setParent(this); - - window2.setPos(50, 50); - window2.setSize(100, 100); - - window2.setBackgroundColor(Utils.toRGBA(0, 255, 0, 150)); - - MButton button1 = new MButton(); - button1.setParent(window2); - button1.setText("hello"); - button1.setSize(75, 25); - button1.setPos(1, MWindow.BAR_HEIGHT + 1); - - // panel3 - MWindow window3 = new MWindow(); - window3.setParent(this); - - window3.setPos(50, 50); - window3.setSize(100, 100); - - window3.setBackgroundColor(Utils.toRGBA(0, 0, 255, 150)); - - // focus - window.requestFocus(); - } -} diff --git a/src/main/java/com/matt/forgehax/util/key/BindingHelper.java b/src/main/java/com/matt/forgehax/util/key/BindingHelper.java index 0f738cfd2..957c5b8bd 100644 --- a/src/main/java/com/matt/forgehax/util/key/BindingHelper.java +++ b/src/main/java/com/matt/forgehax/util/key/BindingHelper.java @@ -8,36 +8,41 @@ import org.lwjgl.input.Mouse; public class BindingHelper { + private static final Map MOUSE_CODES = Maps.newHashMap(); private static final IKeyConflictContext EMPTY = - new IKeyConflictContext() { - @Override - public boolean isActive() { - return false; - } - - @Override - public boolean conflicts(IKeyConflictContext other) { - return false; - } - }; - + new IKeyConflictContext() { + @Override + public boolean isActive() { + return false; + } + + @Override + public boolean conflicts(IKeyConflictContext other) { + return false; + } + }; + static { MOUSE_CODES.put(-100, "MOUSE_LEFT"); MOUSE_CODES.put(-99, "MOUSE_RIGHT"); MOUSE_CODES.put(-98, "MOUSE_MIDDLE"); } - + public static String getIndexName(int code) { - if (MOUSE_CODES.get(code) != null) return MOUSE_CODES.get(code); - else if (code < 0) return Mouse.getButtonName(100 + code); - else return Keyboard.getKeyName(code); + if (MOUSE_CODES.get(code) != null) { + return MOUSE_CODES.get(code); + } else if (code < 0) { + return Mouse.getButtonName(100 + code); + } else { + return Keyboard.getKeyName(code); + } } - + public static String getIndexName(KeyBinding binding) { return getIndexName(binding.getKeyCode()); } - + public static IKeyConflictContext getEmptyKeyConflictContext() { return EMPTY; } diff --git a/src/main/java/com/matt/forgehax/util/key/Bindings.java b/src/main/java/com/matt/forgehax/util/key/Bindings.java index d856b6eab..ea306d760 100644 --- a/src/main/java/com/matt/forgehax/util/key/Bindings.java +++ b/src/main/java/com/matt/forgehax/util/key/Bindings.java @@ -12,46 +12,46 @@ import net.minecraft.client.settings.KeyBinding; public class Bindings implements Globals { - + public static final List KEY_LIST = getAllKeys(); - + @Nullable public static KeyBindingHandler getKey(String name) { return Bindings.KEY_LIST - .stream() - .filter(k -> k.getBinding().getKeyDescription().toLowerCase().contains(name.toLowerCase())) - .findFirst() - .orElse(null); + .stream() + .filter(k -> k.getBinding().getKeyDescription().toLowerCase().contains(name.toLowerCase())) + .findFirst() + .orElse(null); } - + public static final KeyBindingHandler forward = - new KeyBindingHandler(MC.gameSettings.keyBindForward); + new KeyBindingHandler(MC.gameSettings.keyBindForward); public static final KeyBindingHandler back = new KeyBindingHandler(MC.gameSettings.keyBindBack); public static final KeyBindingHandler left = new KeyBindingHandler(MC.gameSettings.keyBindLeft); public static final KeyBindingHandler right = new KeyBindingHandler(MC.gameSettings.keyBindRight); - + public static final KeyBindingHandler jump = new KeyBindingHandler(MC.gameSettings.keyBindJump); - + public static final KeyBindingHandler sprint = - new KeyBindingHandler(MC.gameSettings.keyBindSprint); + new KeyBindingHandler(MC.gameSettings.keyBindSprint); public static final KeyBindingHandler sneak = new KeyBindingHandler(MC.gameSettings.keyBindSneak); - + public static final KeyBindingHandler attack = - new KeyBindingHandler(MC.gameSettings.keyBindAttack); + new KeyBindingHandler(MC.gameSettings.keyBindAttack); public static final KeyBindingHandler use = new KeyBindingHandler(MC.gameSettings.keyBindUseItem); - + // reflectively get KeyBindingHandlers from GameSettings @Nullable private static List getAllKeys() { Field[] fields = GameSettings.class.getFields(); return Arrays.stream(fields) - .filter(f -> f.getType() == KeyBinding.class) - .map(Bindings::getBinding) - .filter(Objects::nonNull) - .map(KeyBindingHandler::new) - .collect(toList()); + .filter(f -> f.getType() == KeyBinding.class) + .map(Bindings::getBinding) + .filter(Objects::nonNull) + .map(KeyBindingHandler::new) + .collect(toList()); } - + private static KeyBinding getBinding(Field field) { try { return (KeyBinding) field.get(MC.gameSettings); diff --git a/src/main/java/com/matt/forgehax/util/key/IKeyBind.java b/src/main/java/com/matt/forgehax/util/key/IKeyBind.java index 58dab6bc9..aac1d3ff0 100644 --- a/src/main/java/com/matt/forgehax/util/key/IKeyBind.java +++ b/src/main/java/com/matt/forgehax/util/key/IKeyBind.java @@ -3,16 +3,19 @@ import net.minecraft.client.settings.KeyBinding; import org.lwjgl.input.Keyboard; -/** Created on 6/10/2017 by fr1kin */ +/** + * Created on 6/10/2017 by fr1kin + */ public interface IKeyBind { + void bind(int keyCode); - + KeyBinding getBind(); - + void onKeyPressed(); - + void onKeyDown(); - + default void unbind() { bind(Keyboard.KEY_NONE); } diff --git a/src/main/java/com/matt/forgehax/util/key/KeyBindingHandler.java b/src/main/java/com/matt/forgehax/util/key/KeyBindingHandler.java index 70fa8026a..833d3c7af 100644 --- a/src/main/java/com/matt/forgehax/util/key/KeyBindingHandler.java +++ b/src/main/java/com/matt/forgehax/util/key/KeyBindingHandler.java @@ -6,53 +6,54 @@ import net.minecraftforge.client.settings.IKeyConflictContext; public class KeyBindingHandler implements Globals { + private static final IKeyConflictContext OVERRIDE_KEYCONFLICT_CONTEXT = - new IKeyConflictContext() { - @Override - public boolean isActive() { - return true; - } - - @Override - public boolean conflicts(IKeyConflictContext other) { - return false; - } - }; - + new IKeyConflictContext() { + @Override + public boolean isActive() { + return true; + } + + @Override + public boolean conflicts(IKeyConflictContext other) { + return false; + } + }; + private final KeyBinding binding; - + private IKeyConflictContext oldConflictContext = null; - + private int bindingCount = 0; - + public KeyBindingHandler(KeyBinding bind) { binding = bind; } - + public KeyBinding getBinding() { return binding; } - + public boolean isPressed() { return FastReflection.Fields.Binding_pressed.get(binding); } - + public void setPressed(boolean pressed) { FastReflection.Fields.Binding_pressed.set(binding, pressed); } - + public int getPressTime() { return FastReflection.Fields.Binding_pressTime.get(binding); } - + public void setPressTime(int time) { FastReflection.Fields.Binding_pressTime.set(binding, time); } - + public boolean isBound() { return binding.getKeyConflictContext() == OVERRIDE_KEYCONFLICT_CONTEXT; } - + public void bind() { // increase every time bind is attempted // this is to prevent issues with mod compatibility @@ -62,11 +63,13 @@ public void bind() { binding.setKeyConflictContext(OVERRIDE_KEYCONFLICT_CONTEXT); } } - + public void attemptBind() { - if (!isBound()) bind(); + if (!isBound()) { + bind(); + } } - + public void unbind() { bindingCount--; // only unbind key conflict if the binding count is 0 or less (idk why it would be less) @@ -75,10 +78,14 @@ public void unbind() { oldConflictContext = null; } // reset to 0 just in case it somehow goes below - if (bindingCount < 0) bindingCount = 0; + if (bindingCount < 0) { + bindingCount = 0; + } } - + public void attemptUnbind() { - if (isBound()) unbind(); + if (isBound()) { + unbind(); + } } } diff --git a/src/main/java/com/matt/forgehax/util/markers/MarkersRenderGlobal.java b/src/main/java/com/matt/forgehax/util/markers/MarkersRenderGlobal.java index ed7fd4b17..1f660e885 100644 --- a/src/main/java/com/matt/forgehax/util/markers/MarkersRenderGlobal.java +++ b/src/main/java/com/matt/forgehax/util/markers/MarkersRenderGlobal.java @@ -22,226 +22,230 @@ import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; -/** Created on 7/26/2017 by fr1kin */ +/** + * Created on 7/26/2017 by fr1kin + */ public class MarkersRenderGlobal extends RenderGlobal implements Globals { + private static final MarkersRenderGlobal INSTANCE = new MarkersRenderGlobal(MC); - + public static MarkersRenderGlobal getInstance() { return INSTANCE; } - + private ChunkRenderDispatcher renderDispatcher = null; - + public MarkersRenderGlobal(Minecraft mcIn) { super(mcIn); } - + @Override public void onResourceManagerReload(IResourceManager resourceManager) { super.onResourceManagerReload(resourceManager); } - + @Override public void renderEntityOutlineFramebuffer() { super.renderEntityOutlineFramebuffer(); } - + @Override protected boolean isRenderEntityOutlines() { return super.isRenderEntityOutlines(); } - + @Override public void setWorldAndLoadRenderers(@Nullable WorldClient worldClientIn) { super.setWorldAndLoadRenderers(worldClientIn); } - + @Override public void loadRenderers() { super.loadRenderers(); } - + @Override protected void stopChunkUpdates() { super.stopChunkUpdates(); } - + @Override public void createBindEntityOutlineFbs(int width, int height) { super.createBindEntityOutlineFbs(width, height); } - + @Override public void renderEntities(Entity renderViewEntity, ICamera camera, float partialTicks) { super.renderEntities(renderViewEntity, camera, partialTicks); } - + @Override public String getDebugInfoRenders() { return super.getDebugInfoRenders(); } - + @Override protected int getRenderedChunks() { return super.getRenderedChunks(); } - + @Override public String getDebugInfoEntities() { return super.getDebugInfoEntities(); } - + @Override public void setupTerrain( - Entity viewEntity, - double partialTicks, - ICamera camera, - int frameCount, - boolean playerSpectator) { + Entity viewEntity, + double partialTicks, + ICamera camera, + int frameCount, + boolean playerSpectator) { super.setupTerrain(viewEntity, partialTicks, camera, frameCount, playerSpectator); } - + @Override public int renderBlockLayer( - BlockRenderLayer blockLayerIn, double partialTicks, int pass, Entity entityIn) { + BlockRenderLayer blockLayerIn, double partialTicks, int pass, Entity entityIn) { return super.renderBlockLayer(blockLayerIn, partialTicks, pass, entityIn); } - + @Override public void updateClouds() { super.updateClouds(); } - + @Override public void renderSky(float partialTicks, int pass) { super.renderSky(partialTicks, pass); } - + @Override public void renderClouds( - float partialTicks, int pass, double p_180447_3_, double p_180447_5_, double p_180447_7_) { + float partialTicks, int pass, double p_180447_3_, double p_180447_5_, double p_180447_7_) { super.renderClouds(partialTicks, pass, p_180447_3_, p_180447_5_, p_180447_7_); } - + @Override public boolean hasCloudFog(double x, double y, double z, float partialTicks) { return super.hasCloudFog(x, y, z, partialTicks); } - + @Override public void updateChunks(long finishTimeNano) { super.updateChunks(finishTimeNano); } - + @Override public void renderWorldBorder(Entity entityIn, float partialTicks) { super.renderWorldBorder(entityIn, partialTicks); } - + @Override public void drawBlockDamageTexture( - Tessellator tessellatorIn, - BufferBuilder worldRendererIn, - Entity entityIn, - float partialTicks) { + Tessellator tessellatorIn, + BufferBuilder worldRendererIn, + Entity entityIn, + float partialTicks) { super.drawBlockDamageTexture(tessellatorIn, worldRendererIn, entityIn, partialTicks); } - + @Override public void drawSelectionBox( - EntityPlayer player, RayTraceResult movingObjectPositionIn, int execute, float partialTicks) { + EntityPlayer player, RayTraceResult movingObjectPositionIn, int execute, float partialTicks) { super.drawSelectionBox(player, movingObjectPositionIn, execute, partialTicks); } - + @Override public void notifyBlockUpdate( - World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) { + World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) { super.notifyBlockUpdate(worldIn, pos, oldState, newState, flags); } - + @Override public void notifyLightSet(BlockPos pos) { super.notifyLightSet(pos); } - - public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {} - + + public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) { + } + @Override public void playRecord(@Nullable SoundEvent soundIn, BlockPos pos) { super.playRecord(soundIn, pos); } - + @Override public void playSoundToAllNearExcept( - @Nullable EntityPlayer player, - SoundEvent soundIn, - SoundCategory category, - double x, - double y, - double z, - float volume, - float pitch) { + @Nullable EntityPlayer player, + SoundEvent soundIn, + SoundCategory category, + double x, + double y, + double z, + float volume, + float pitch) { super.playSoundToAllNearExcept(player, soundIn, category, x, y, z, volume, pitch); } - + @Override public void spawnParticle( - int id, - boolean ignoreRange, - boolean p_190570_3_, - double x, - double y, - double z, - double xSpeed, - double ySpeed, - double zSpeed, - int... parameters) { + int id, + boolean ignoreRange, + boolean p_190570_3_, + double x, + double y, + double z, + double xSpeed, + double ySpeed, + double zSpeed, + int... parameters) { super.spawnParticle(id, ignoreRange, p_190570_3_, x, y, z, xSpeed, ySpeed, zSpeed, parameters); } - + @Override public void onEntityAdded(Entity entityIn) { super.onEntityAdded(entityIn); } - + @Override public void onEntityRemoved(Entity entityIn) { super.onEntityRemoved(entityIn); } - + @Override public void deleteAllDisplayLists() { super.deleteAllDisplayLists(); } - + @Override public void broadcastSound(int soundID, BlockPos pos, int data) { super.broadcastSound(soundID, pos, data); } - + @Override public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data) { super.playEvent(player, type, blockPosIn, data); } - + @Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) { super.sendBlockBreakProgress(breakerId, pos, progress); } - + @Override public boolean hasNoChunkUpdates() { return super.hasNoChunkUpdates(); } - + @Override public void setDisplayListEntitiesDirty() { super.setDisplayListEntitiesDirty(); } - + @Override public void updateTileEntities( - Collection tileEntitiesToRemove, Collection tileEntitiesToAdd) { + Collection tileEntitiesToRemove, Collection tileEntitiesToAdd) { super.updateTileEntities(tileEntitiesToRemove, tileEntitiesToAdd); } } diff --git a/src/main/java/com/matt/forgehax/util/markers/RenderUploader.java b/src/main/java/com/matt/forgehax/util/markers/RenderUploader.java index b7b86a267..724008dad 100644 --- a/src/main/java/com/matt/forgehax/util/markers/RenderUploader.java +++ b/src/main/java/com/matt/forgehax/util/markers/RenderUploader.java @@ -11,18 +11,27 @@ import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.util.math.BlockPos; -/** Created on 1/18/2018 by fr1kin */ +/** + * Created on 1/18/2018 by fr1kin + */ public class RenderUploader implements Globals { + private final Uploaders parent; private final ReentrantLock _lock = new ReentrantLock(); - - /** The vertex buffer instance (for uploading the tessellator data) */ + + /** + * The vertex buffer instance (for uploading the tessellator data) + */ private final VertexBuffer vertexBuffer; - - /** The tessellator instance */ + + /** + * The tessellator instance + */ private volatile E tessellator; - - /** The thread the current VBO is being processed on */ + + /** + * The thread the current VBO is being processed on + */ private volatile Thread currentThread; private boolean complete = false; @@ -57,9 +66,11 @@ public E getTessellator() { } public void setTessellator(E tessellator) throws UploaderException { - if (tessellator != null && this.tessellator != null) + if (tessellator != null && this.tessellator != null) { throw new UploaderException("Tried to set tessellator without removing the previous one"); - else this.tessellator = tessellator; + } else { + this.tessellator = tessellator; + } } public void takeTessellator() throws UploaderException, InterruptedException { @@ -67,10 +78,12 @@ public void takeTessellator() throws UploaderException, InterruptedException { } public void freeTessellator() - throws UploaderException, TessellatorCache.TessellatorCacheFreeException { + throws UploaderException, TessellatorCache.TessellatorCacheFreeException { if (tessellator != null) { // stop tessellator from drawing - if (isTessellatorDrawing()) getBufferBuilder().finishDrawing(); + if (isTessellatorDrawing()) { + getBufferBuilder().finishDrawing(); + } // reset translation getBufferBuilder().setTranslation(0.D, 0.D, 0.D); // free tessellator to parent @@ -83,8 +96,10 @@ public void freeTessellator() public BufferBuilder getBufferBuilder() { return getTessellator().getBuffer(); } - - /** Will set the current thread to the current thread running the method. */ + + /** + * Will set the current thread to the current thread running the method. + */ public void setCurrentThread() { currentThread = Thread.currentThread(); } @@ -92,19 +107,20 @@ public void setCurrentThread() { public void nullifyCurrentThread() { currentThread = null; } + /** * Verify that the current thread is the one doing the rendering * * @throws ThreadMismatchException if running in the incorrect thread */ public void validateCurrentThread() throws ThreadMismatchException { - if (currentThread != Thread.currentThread()) + if (currentThread != Thread.currentThread()) { throw new ThreadMismatchException("Tried executing in incorrect thread (this is normal)"); + } } + /** * Same thing but returns a boolean instead of throwing error - * - * @return */ public boolean isCorrectCurrentThread() { return currentThread == Thread.currentThread(); @@ -112,8 +128,6 @@ public boolean isCorrectCurrentThread() { /** * Get the vertex buffer used to upload - * - * @return */ public VertexBuffer getVertexBuffer() { return vertexBuffer; @@ -125,9 +139,12 @@ public VertexBuffer getVertexBuffer() { * @throws UploaderException if the upload failed */ public boolean upload() throws UploaderException { - if (getTessellator() == null) return false; // no tessellator - if (!MC.isCallingFromMinecraftThread()) + if (getTessellator() == null) { + return false; // no tessellator + } + if (!MC.isCallingFromMinecraftThread()) { throw new UploaderException("Not calling from main Minecraft thread"); + } // if(isTessellatorDrawing()) throw new UploaderException("Tried to upload VBO while tessellator // is still drawing"); @@ -158,9 +175,12 @@ public boolean upload() throws UploaderException { * @throws UploaderException if the unload failed */ public void unload() throws UploaderException { - if (!isUploaded()) return; - if (!MC.isCallingFromMinecraftThread()) + if (!isUploaded()) { + return; + } + if (!MC.isCallingFromMinecraftThread()) { throw new UploaderException("Not calling from main Minecraft thread"); + } try { vertexBuffer.deleteGlBuffers(); @@ -173,16 +193,16 @@ public void unload() throws UploaderException { /** * Check if the tessellator instance is current drawing - * - * @return */ public boolean isTessellatorDrawing() { return getTessellator() != null - && FastReflection.Fields.BufferBuilder_isDrawing.get(getBufferBuilder()); + && FastReflection.Fields.BufferBuilder_isDrawing.get(getBufferBuilder()); } public void finishDrawing() { - if (!isTessellatorDrawing()) return; + if (!isTessellatorDrawing()) { + return; + } renderCount = getBufferBuilder().getVertexCount() / 24; getBufferBuilder().finishDrawing(); @@ -190,8 +210,6 @@ public void finishDrawing() { /** * Check if the vertex buffer has been uploaded - * - * @return */ public boolean isUploaded() { return uploaded; @@ -231,18 +249,21 @@ public ReentrantLock lock() { } public static class UploaderException extends Exception { + public UploaderException(String msg) { super(msg); } } public static class ThreadMismatchException extends UploaderException { + public ThreadMismatchException(String msg) { super(msg); } } public static class VertexBufferException extends UploaderException { + public VertexBufferException(String msg) { super(msg); } diff --git a/src/main/java/com/matt/forgehax/util/markers/TessellatorCache.java b/src/main/java/com/matt/forgehax/util/markers/TessellatorCache.java index fa403412f..3257503e8 100644 --- a/src/main/java/com/matt/forgehax/util/markers/TessellatorCache.java +++ b/src/main/java/com/matt/forgehax/util/markers/TessellatorCache.java @@ -8,41 +8,48 @@ import java.util.function.Supplier; import net.minecraft.client.renderer.Tessellator; -/** Created on 1/18/2018 by fr1kin */ +/** + * Created on 1/18/2018 by fr1kin + */ public class TessellatorCache implements Globals { + private final BlockingQueue cache; private final List originals; - + public TessellatorCache(int capacity, Supplier supplier) { cache = Queues.newArrayBlockingQueue(capacity); - + // fill the cache - for (int i = 0; i < capacity; i++) cache.add(supplier.get()); - + for (int i = 0; i < capacity; i++) { + cache.add(supplier.get()); + } + // copy list of the original tessellators to prevent others from being added originals = ImmutableList.copyOf(cache); } - + public E take() throws InterruptedException { return cache.take(); } - + public boolean free(E tessellator) throws TessellatorCacheFreeException { - if (!originals.contains(tessellator)) + if (!originals.contains(tessellator)) { throw new TessellatorCacheFreeException( - "Tried to add tessellator that wasn't originally in cache"); + "Tried to add tessellator that wasn't originally in cache"); + } return tessellator != null && cache.offer(tessellator); } - + public int size() { return cache.size(); } - + public int capacity() { return originals.size(); } - + public static class TessellatorCacheFreeException extends Exception { + public TessellatorCacheFreeException(String msg) { super(msg); } diff --git a/src/main/java/com/matt/forgehax/util/markers/Uploaders.java b/src/main/java/com/matt/forgehax/util/markers/Uploaders.java index 48953805e..2fde4e458 100644 --- a/src/main/java/com/matt/forgehax/util/markers/Uploaders.java +++ b/src/main/java/com/matt/forgehax/util/markers/Uploaders.java @@ -9,36 +9,37 @@ import net.minecraft.client.renderer.chunk.CompiledChunk; import net.minecraft.client.renderer.chunk.RenderChunk; -/** Created on 1/18/2018 by fr1kin */ +/** + * Created on 1/18/2018 by fr1kin + */ public class Uploaders { + private final Map> uploaders = Maps.newConcurrentMap(); private final UploaderSupplier supplier; - + private final TessellatorCache cache; - + private Consumer> shutdownTask; - + public Uploaders(UploaderSupplier supplier, TessellatorCache cache) { this.supplier = supplier; this.cache = cache; } - + /** * Register RenderChunk and create new RenderUploader instance for it - * - * @param renderChunk */ public void register(RenderChunk renderChunk) { RenderUploader uploader = uploaders.get(renderChunk); // if a key for this object already exists, notify the shutdown hook and remove the old entry - if (uploader != null && shutdownTask != null) shutdownTask.accept(uploader); + if (uploader != null && shutdownTask != null) { + shutdownTask.accept(uploader); + } uploaders.put(renderChunk, supplier.get(this)); } - + /** * Unregister RenderChunk - * - * @param renderChunk */ public void unregister(RenderChunk renderChunk) { RenderUploader uploader = uploaders.get(renderChunk); @@ -48,34 +49,36 @@ public void unregister(RenderChunk renderChunk) { uploaders.remove(renderChunk); } } - - /** Unregister all added RenderChunks */ + + /** + * Unregister all added RenderChunks + */ public void unregisterAll() { forEach((k, v) -> unregister(k)); } - + public Optional> get(RenderChunk renderChunk) { return Optional.ofNullable(uploaders.get(renderChunk)); } - + /** * Current size of the RenderChunk map - * - * @return */ public int size() { return uploaders.size(); } - + public void computeIfPresent(RenderChunk renderChunk, final Consumer> task) { RenderUploader uploader = uploaders.get(renderChunk); - if (uploader != null) task.accept(uploader); + if (uploader != null) { + task.accept(uploader); + } } - + public void forEach(BiConsumer> action) { uploaders.forEach(action); } - + /** * Set the shutdown hook for when a RenderUploader is no longer needed * @@ -84,16 +87,17 @@ public void forEach(BiConsumer> action) { public void onShutdown(Consumer> shutdownTask) { this.shutdownTask = shutdownTask; } - + public TessellatorCache cache() { return cache; } - + public static boolean isDummy(RenderChunk chunk) { return chunk != null && chunk.getCompiledChunk() == CompiledChunk.DUMMY; } - + public interface UploaderSupplier { + RenderUploader get(Uploaders parent); } } diff --git a/src/main/java/com/matt/forgehax/util/math/Angle.java b/src/main/java/com/matt/forgehax/util/math/Angle.java index b20f9ff18..c622887b5 100644 --- a/src/main/java/com/matt/forgehax/util/math/Angle.java +++ b/src/main/java/com/matt/forgehax/util/math/Angle.java @@ -4,125 +4,128 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -/** Created on 6/21/2017 by fr1kin */ +/** + * Created on 6/21/2017 by fr1kin + */ public abstract class Angle { + public static final Angle ZERO = degrees(0.f, 0.f, 0.f); - + public static Angle radians(float pitch, float yaw, float roll) { return new Radians(pitch, yaw, roll); } - + public static Angle radians(float pitch, float yaw) { return radians(pitch, yaw, 0.f); } - + public static Angle radians(double pitch, double yaw, double roll) { return radians( - (float) AngleHelper.roundAngle(pitch), - (float) AngleHelper.roundAngle(yaw), - (float) AngleHelper.roundAngle(roll)); + (float) AngleHelper.roundAngle(pitch), + (float) AngleHelper.roundAngle(yaw), + (float) AngleHelper.roundAngle(roll)); } - + public static Angle radians(double pitch, double yaw) { return radians(pitch, yaw, 0.D); } - + public static Angle degrees(float pitch, float yaw, float roll) { return new Degrees(pitch, yaw, roll); } - + public static Angle degrees(float pitch, float yaw) { return degrees(pitch, yaw, 0.f); } - + public static Angle degrees(double pitch, double yaw, double roll) { return degrees( - (float) AngleHelper.roundAngle(pitch), - (float) AngleHelper.roundAngle(yaw), - (float) AngleHelper.roundAngle(roll)); + (float) AngleHelper.roundAngle(pitch), + (float) AngleHelper.roundAngle(yaw), + (float) AngleHelper.roundAngle(roll)); } - + public static Angle degrees(double pitch, double yaw) { return degrees(pitch, yaw, 0.D); } - + public static Angle copy(Angle ang) { return ang.newInstance(ang.getPitch(), ang.getYaw(), ang.getRoll()); } - + private final float pitch; private final float yaw; private final float roll; - + private Angle(float pitch, float yaw, float roll) { this.pitch = pitch; this.yaw = yaw; this.roll = roll; } - + public float getPitch() { return pitch; } - + public float getYaw() { return yaw; } - + public float getRoll() { return roll; } - + public Angle setPitch(float pitch) { return newInstance(pitch, getYaw(), getRoll()); } - + public Angle setYaw(float yaw) { return newInstance(getPitch(), yaw, getRoll()); } - + public Angle setRoll(float roll) { return newInstance(getPitch(), getYaw(), roll); } - + public abstract boolean isInDegrees(); - + public boolean isInRadians() { return !isInDegrees(); } - + public Angle add(Angle ang) { return newInstance( - getPitch() + ang.same(this).getPitch(), - getYaw() + ang.same(this).getYaw(), - getRoll() + ang.same(this).getRoll()); + getPitch() + ang.same(this).getPitch(), + getYaw() + ang.same(this).getYaw(), + getRoll() + ang.same(this).getRoll()); } - + public Angle add(float p, float y, float r) { return add(newInstance(p, y, r)); } - + public Angle add(float p, float y) { return add(p, y, 0.f); } - + public Angle sub(Angle ang) { return add(ang.scale(-1)); } - + public Angle sub(float p, float y, float r) { return add(-p, -y, -r); } - + public Angle sub(float p, float y) { return sub(p, y, 0.f); } - + public Angle scale(float factor) { return newInstance(getPitch() * factor, getYaw() * factor, getRoll() * factor); } - + public abstract Angle normalize(); - + public double[] getForwardVector() { // x = cos(yaw)cos(pitch) // y = sin(pitch) @@ -131,13 +134,13 @@ public double[] getForwardVector() { double kpc = Math.cos(inRadians().getPitch()); double kys = Math.sin(inRadians().getYaw()); double kyc = Math.cos(inRadians().getYaw()); - return new double[] { + return new double[]{ kpc * kyc, // x kps, // y kpc * kys // z }; } - + public Vec3d getDirectionVector() { float cy = MathHelper.cos(-inDegrees().getYaw() * 0.017453292F - (float) Math.PI); float sy = MathHelper.sin(-inDegrees().getYaw() * 0.017453292F - (float) Math.PI); @@ -145,119 +148,121 @@ public Vec3d getDirectionVector() { float sp = MathHelper.sin(-inDegrees().getPitch() * 0.017453292F); return new Vec3d((double) (sy * cp), (double) sp, (double) (cy * cp)); } - + public float[] toArray() { - return new float[] {getPitch(), getYaw(), getRoll()}; + return new float[]{getPitch(), getYaw(), getRoll()}; } - + public abstract Angle inRadians(); - + public abstract Angle inDegrees(); - + protected Angle same(Angle other) { return other.isInDegrees() ? inDegrees() : inRadians(); } - + protected abstract Angle newInstance(float pitch, float yaw, float roll); - + @Override public boolean equals(Object obj) { return this == obj || (obj instanceof Angle && AngleHelper.isEqual(this, (Angle) obj)); } - + @Override public int hashCode() { Angle a = normalize().inDegrees(); return Objects.hash(a.getPitch(), a.getYaw(), a.getRoll()); } - + @Override public String toString() { return String.format( - "(%.15f, %.15f, %.15f)[%s]", - getPitch(), getYaw(), getRoll(), isInRadians() ? "rad" : "deg"); + "(%.15f, %.15f, %.15f)[%s]", + getPitch(), getYaw(), getRoll(), isInRadians() ? "rad" : "deg"); } - + static class Degrees extends Angle { + private Radians radians = null; - + private Degrees(float pitch, float yaw, float roll) { super(pitch, yaw, roll); } - + @Override public boolean isInDegrees() { return true; } - + @Override public Angle normalize() { return newInstance( - AngleHelper.normalizeInDegrees(getPitch()), - AngleHelper.normalizeInDegrees(getYaw()), - AngleHelper.normalizeInDegrees(getRoll())); + AngleHelper.normalizeInDegrees(getPitch()), + AngleHelper.normalizeInDegrees(getYaw()), + AngleHelper.normalizeInDegrees(getRoll())); } - + @Override public Angle inRadians() { return radians == null - ? radians = - (Radians) - radians( - Math.toRadians(getPitch()), - Math.toRadians(getYaw()), - Math.toRadians(getRoll())) - : radians; + ? radians = + (Radians) + radians( + Math.toRadians(getPitch()), + Math.toRadians(getYaw()), + Math.toRadians(getRoll())) + : radians; } - + @Override public Angle inDegrees() { return this; } - + @Override protected Angle newInstance(float pitch, float yaw, float roll) { return new Degrees(pitch, yaw, roll); } } - + static class Radians extends Angle { + private Degrees degrees = null; - + private Radians(float pitch, float yaw, float roll) { super(pitch, yaw, roll); } - + @Override public boolean isInDegrees() { return false; } - + @Override public Angle normalize() { return newInstance( - AngleHelper.normalizeInRadians(getPitch()), - AngleHelper.normalizeInRadians(getYaw()), - AngleHelper.normalizeInRadians(getRoll())); + AngleHelper.normalizeInRadians(getPitch()), + AngleHelper.normalizeInRadians(getYaw()), + AngleHelper.normalizeInRadians(getRoll())); } - + @Override public Angle inRadians() { return this; } - + @Override public Angle inDegrees() { return degrees == null - ? degrees = - (Degrees) - degrees( - Math.toDegrees(getPitch()), - Math.toDegrees(getYaw()), - Math.toDegrees(getRoll())) - : degrees; + ? degrees = + (Degrees) + degrees( + Math.toDegrees(getPitch()), + Math.toDegrees(getYaw()), + Math.toDegrees(getRoll())) + : degrees; } - + @Override protected Angle newInstance(float pitch, float yaw, float roll) { return new Radians(pitch, yaw, roll); diff --git a/src/main/java/com/matt/forgehax/util/math/AngleHelper.java b/src/main/java/com/matt/forgehax/util/math/AngleHelper.java index 95cd370fb..671bf60f3 100644 --- a/src/main/java/com/matt/forgehax/util/math/AngleHelper.java +++ b/src/main/java/com/matt/forgehax/util/math/AngleHelper.java @@ -3,59 +3,70 @@ import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; -/** Created on 6/21/2017 by fr1kin */ +/** + * Created on 6/21/2017 by fr1kin + */ public class AngleHelper { + public static final long DEFAULT_N = 1000000000L; // 9 decimal places public static final double DEFAULT_EPSILON = (1.D / (double) DEFAULT_N); - + public static final double TWO_PI = Math.PI * 2.D; // 180 degrees public static final double HALF_PI = Math.PI / 2.D; // 90 degrees public static final double QUARTER_PI = Math.PI / 4.D; // 45 degrees - + public static double roundAngle(double a, long n) { return Math.round(a * n) / (double) n; } - + public static double roundAngle(double a) { return roundAngle(a, DEFAULT_N); } - + public static boolean isAngleEqual(double a1, double a2, double epsilon) { return Double.compare(a1, a2) == 0 || Math.abs(a1 - a2) < epsilon; } - + public static boolean isAngleEqual(double a1, double a2) { return isAngleEqual(a1, a2, 1E-4); } - + public static boolean isEqual(Angle ang1, Angle ang2) { Angle a1 = ang1.normalize(); Angle a2 = ang2.same(a1).normalize(); return isAngleEqual(a1.getPitch(), a2.getPitch()) - && isAngleEqual(a1.getYaw(), a2.getYaw()) - && isAngleEqual(a1.getRoll(), a2.getRoll()); + && isAngleEqual(a1.getYaw(), a2.getYaw()) + && isAngleEqual(a1.getRoll(), a2.getRoll()); } - + public static double normalizeInRadians(double ang) { - while (ang > Math.PI) ang -= 2 * Math.PI; - while (ang < -Math.PI) ang += 2 * Math.PI; + while (ang > Math.PI) { + ang -= 2 * Math.PI; + } + while (ang < -Math.PI) { + ang += 2 * Math.PI; + } return ang; } - + public static float normalizeInRadians(float ang) { - while (ang > Math.PI) ang -= 2 * Math.PI; - while (ang < -Math.PI) ang += 2 * Math.PI; + while (ang > Math.PI) { + ang -= 2 * Math.PI; + } + while (ang < -Math.PI) { + ang += 2 * Math.PI; + } return ang; } - + public static double normalizeInDegrees(double ang) { return MathHelper.wrapDegrees(ang); } - + public static float normalizeInDegrees(float ang) { return MathHelper.wrapDegrees(ang); } - + public static Angle getAngleFacingInRadians(Vec3d vector) { double pitch, yaw; if (vector.x == 0 && vector.z == 0) { @@ -68,7 +79,7 @@ public static Angle getAngleFacingInRadians(Vec3d vector) { } return Angle.radians((float) pitch, (float) yaw); } - + public static Angle getAngleFacingInDegrees(Vec3d vector) { return getAngleFacingInRadians(vector).inDegrees(); } diff --git a/src/main/java/com/matt/forgehax/util/math/Plane.java b/src/main/java/com/matt/forgehax/util/math/Plane.java index 4f1628426..088c0970f 100644 --- a/src/main/java/com/matt/forgehax/util/math/Plane.java +++ b/src/main/java/com/matt/forgehax/util/math/Plane.java @@ -1,7 +1,10 @@ package com.matt.forgehax.util.math; -/** Created on 9/2/2017 by fr1kin */ +/** + * Created on 9/2/2017 by fr1kin + */ public class Plane { + private final double x; private final double y; diff --git a/src/main/java/com/matt/forgehax/util/math/VectorUtils.java b/src/main/java/com/matt/forgehax/util/math/VectorUtils.java index 80281208a..22d1ba8d9 100644 --- a/src/main/java/com/matt/forgehax/util/math/VectorUtils.java +++ b/src/main/java/com/matt/forgehax/util/math/VectorUtils.java @@ -11,10 +11,10 @@ public class VectorUtils implements Globals { // Credits to Gregor and P47R1CK for the 3D vector transformation code - + static Matrix4f modelMatrix = new Matrix4f(); static Matrix4f projectionMatrix = new Matrix4f(); - + private static void VecTransformCoordinate(Vector4f vec, Matrix4f matrix) { float x = vec.x; float y = vec.y; @@ -24,30 +24,34 @@ private static void VecTransformCoordinate(Vector4f vec, Matrix4f matrix) { vec.z = (x * matrix.m02) + (y * matrix.m12) + (z * matrix.m22) + matrix.m32; vec.w = (x * matrix.m03) + (y * matrix.m13) + (z * matrix.m23) + matrix.m33; } - - /** Convert 3D coord into 2D coordinate projected onto the screen */ + + /** + * Convert 3D coord into 2D coordinate projected onto the screen + */ public static Plane toScreen(double x, double y, double z) { Entity view = MC.getRenderViewEntity(); - - if (view == null) return new Plane(0.D, 0.D, false); - + + if (view == null) { + return new Plane(0.D, 0.D, false); + } + Vec3d camPos = FastReflection.Fields.ActiveRenderInfo_position.getStatic(); Vec3d eyePos = ActiveRenderInfo.projectViewFromEntity(view, MC.getRenderPartialTicks()); - + float vecX = (float) ((camPos.x + eyePos.x) - (float) x); float vecY = (float) ((camPos.y + eyePos.y) - (float) y); float vecZ = (float) ((camPos.z + eyePos.z) - (float) z); - + Vector4f pos = new Vector4f(vecX, vecY, vecZ, 1.f); - + modelMatrix.load( - FastReflection.Fields.ActiveRenderInfo_MODELVIEW.getStatic().asReadOnlyBuffer()); + FastReflection.Fields.ActiveRenderInfo_MODELVIEW.getStatic().asReadOnlyBuffer()); projectionMatrix.load( - FastReflection.Fields.ActiveRenderInfo_PROJECTION.getStatic().asReadOnlyBuffer()); - + FastReflection.Fields.ActiveRenderInfo_PROJECTION.getStatic().asReadOnlyBuffer()); + VecTransformCoordinate(pos, modelMatrix); VecTransformCoordinate(pos, projectionMatrix); - + if (pos.w > 0.f) { pos.x *= -100000; pos.y *= -100000; @@ -56,64 +60,68 @@ public static Plane toScreen(double x, double y, double z) { pos.x *= invert; pos.y *= invert; } - + ScaledResolution res = new ScaledResolution(MC); float halfWidth = (float) res.getScaledWidth() / 2.f; float halfHeight = (float) res.getScaledHeight() / 2.f; - + pos.x = halfWidth + (0.5f * pos.x * res.getScaledWidth() + 0.5f); pos.y = halfHeight - (0.5f * pos.y * res.getScaledHeight() + 0.5f); - + boolean bVisible = true; - - if (pos.x < 0 || pos.y < 0 || pos.x > res.getScaledWidth() || pos.y > res.getScaledHeight()) + + if (pos.x < 0 || pos.y < 0 || pos.x > res.getScaledWidth() || pos.y > res.getScaledHeight()) { bVisible = false; - + } + return new Plane(pos.x, pos.y, bVisible); } - + public static Plane toScreen(Vec3d vec) { return toScreen(vec.x, vec.y, vec.z); } - + @Deprecated public static ScreenPos _toScreen(double x, double y, double z) { Plane plane = toScreen(x, y, z); return new ScreenPos(plane.getX(), plane.getY(), plane.isVisible()); } - + @Deprecated public static ScreenPos _toScreen(Vec3d vec3d) { return _toScreen(vec3d.x, vec3d.y, vec3d.z); } - - /** Convert a vector to a angle */ + + /** + * Convert a vector to a angle + */ @Deprecated public static Object vectorAngle(Vec3d vec3d) { return null; } - + public static Vec3d multiplyBy(Vec3d vec1, Vec3d vec2) { return new Vec3d(vec1.x * vec2.x, vec1.y * vec2.y, vec1.z * vec2.z); } - + public static Vec3d copy(Vec3d toCopy) { return new Vec3d(toCopy.x, toCopy.y, toCopy.z); } - + public static double getCrosshairDistance(Vec3d eyes, Vec3d directionVec, Vec3d pos) { return pos.subtract(eyes).normalize().subtract(directionVec).lengthSquared(); } - + @Deprecated public static class ScreenPos { + public final int x; public final int y; public final boolean isVisible; - + public final double xD; public final double yD; - + public ScreenPos(double x, double y, boolean isVisible) { this.x = (int) x; this.y = (int) y; diff --git a/src/main/java/com/matt/forgehax/util/mod/BaseMod.java b/src/main/java/com/matt/forgehax/util/mod/BaseMod.java index cdc15b1b3..67a5c5e57 100644 --- a/src/main/java/com/matt/forgehax/util/mod/BaseMod.java +++ b/src/main/java/com/matt/forgehax/util/mod/BaseMod.java @@ -14,45 +14,54 @@ import net.minecraftforge.common.MinecraftForge; public abstract class BaseMod implements Globals { + // name of the mod private final String modName; // description of mod private final String modDescription; // category of the mod private final Category category; - + protected final Command stubCommand; - + // is the mod registered on the forge bus? private boolean registered = false; - + public BaseMod(Category category, String name, String desc) { this.modName = name; this.modDescription = desc; this.category = category; stubCommand = - buildStubCommand( - getGlobalCommand() - .builders() - .newStubBuilder() - .name(name) - .description(desc) - .processor(this::onProcessCommand)) - .build(); + buildStubCommand( + getGlobalCommand() + .builders() + .newStubBuilder() + .name(name) + .description(desc) + .processor(this::onProcessCommand)) + .build(); } - + public BaseMod(Category category, String name) { this(category, name, Strings.EMPTY); } - - /** Load the mod */ + + /** + * Load the mod + */ public final void load() { - if (stubCommand != null) stubCommand.deserializeAll(); - if (isEnabled()) start(); + if (stubCommand != null) { + stubCommand.deserializeAll(); + } + if (isEnabled()) { + start(); + } onLoad(); } - - /** Unload the mod */ + + /** + * Unload the mod + */ public final void unload() { stop(); onUnload(); @@ -62,77 +71,97 @@ public final void unload() { stubCommand.leaveParent(); } } - - /** Enables the mod */ + + /** + * Enables the mod + */ protected final void start() { if (register()) { onEnabled(); LOGGER.info(String.format("%s enabled", getModName())); } } - + protected final void stop() { if (unregister()) { onDisabled(); LOGGER.info(String.format("%s disabled", getModName())); } } - + public void enable() { start(); } - + public void disable() { stop(); } - - /** Get the categories name */ + + /** + * Get the categories name + */ public final String getModName() { return modName; } - - /** Get mod description */ + + /** + * Get mod description + */ public final String getModDescription() { return modDescription; } - - /** Get mod category */ + + /** + * Get mod category + */ public Category getModCategory() { return category; } - - /** The main mod command */ + + /** + * The main mod command + */ public Command getCommandStub() { return stubCommand; } - - /** Check if mod is currently registered */ + + /** + * Check if mod is currently registered + */ public final boolean isRegistered() { return registered; } - - /** Register event to forge bus */ + + /** + * Register event to forge bus + */ public final boolean register() { if (!registered) { MinecraftForge.EVENT_BUS.register(this); registered = true; return true; - } else return false; + } else { + return false; + } } - - /** Unregister event on forge bus */ + + /** + * Unregister event on forge bus + */ public final boolean unregister() { if (registered) { MinecraftForge.EVENT_BUS.unregister(this); registered = false; return true; - } else return false; + } else { + return false; + } } - + protected StubBuilder buildStubCommand(StubBuilder builder) { return builder; } - + @SuppressWarnings("unchecked") public final T getCommand(String commandName) { try { @@ -141,42 +170,49 @@ public final T getCommand(String commandName) { return null; } } - + public final Setting getSetting(String settingName) { return getCommand(settingName); } - + public final Collection getCommands() { - if (stubCommand != null) return stubCommand.getChildren(); - else return Collections.emptyList(); + if (stubCommand != null) { + return stubCommand.getChildren(); + } else { + return Collections.emptyList(); + } } - - /** Check if the mod is hidden DEFAULT: true */ + + /** + * Check if the mod is hidden DEFAULT: true + */ public abstract boolean isHidden(); - - /** Check if the mod is enabled */ + + /** + * Check if the mod is enabled + */ public abstract boolean isEnabled(); - + private void writeChildren( - StringBuilder builder, Command command, final boolean deep, final String append) { + StringBuilder builder, Command command, final boolean deep, final String append) { command - .getChildren() - .forEach( - child -> { - boolean invalid = Strings.isNullOrEmpty(append); - if (!invalid) { - builder.append(append); - builder.append(' '); - } - builder.append(child.getPrintText()); - builder.append('\n'); - if (deep) { - String app = invalid ? Strings.EMPTY : append; - writeChildren(builder, child, deep, app + ">"); - } - }); + .getChildren() + .forEach( + child -> { + boolean invalid = Strings.isNullOrEmpty(append); + if (!invalid) { + builder.append(append); + builder.append(' '); + } + builder.append(child.getPrintText()); + builder.append('\n'); + if (deep) { + String app = invalid ? Strings.EMPTY : append; + writeChildren(builder, child, deep, app + ">"); + } + }); } - + protected void onProcessCommand(ExecuteData data) { if (data.getArgumentCount() == 0 && !data.options().hasOptions()) { final StringBuilder builder = new StringBuilder(); @@ -184,33 +220,45 @@ protected void onProcessCommand(ExecuteData data) { data.write(builder.toString()); } } - - /** Called when the mod is loaded */ + + /** + * Called when the mod is loaded + */ protected abstract void onLoad(); - - /** Called when unloaded */ + + /** + * Called when unloaded + */ protected abstract void onUnload(); - - /** Called when the mod is enabled */ + + /** + * Called when the mod is enabled + */ protected abstract void onEnabled(); - - /** Called when the mod is disabled */ + + /** + * Called when the mod is disabled + */ protected abstract void onDisabled(); - - /** Called when the bind is initially pressed */ + + /** + * Called when the bind is initially pressed + */ protected abstract void onBindPressed(CallbackData cb); - - /** Called while the bind key is pressed down */ + + /** + * Called while the bind key is pressed down + */ protected abstract void onBindKeyDown(CallbackData cb); - + public String getDisplayText() { return getModName(); } - + public String getDebugDisplayText() { return getDisplayText(); } - + @Override public String toString() { return getModName() + ": " + getModDescription(); diff --git a/src/main/java/com/matt/forgehax/util/mod/Category.java b/src/main/java/com/matt/forgehax/util/mod/Category.java index 73f464462..d8ca55841 100644 --- a/src/main/java/com/matt/forgehax/util/mod/Category.java +++ b/src/main/java/com/matt/forgehax/util/mod/Category.java @@ -1,6 +1,8 @@ package com.matt.forgehax.util.mod; -/** Created on 9/4/2017 by fr1kin */ +/** + * Created on 9/4/2017 by fr1kin + */ public enum Category { NONE("", ""), COMBAT("Combat", "Combat related mods"), @@ -10,19 +12,19 @@ public enum Category { MISC("Misc", "Miscellaneous"), SERVICE("Service", "Background mods"), ; - + private String prettyName; private String description; - + Category(String prettyName, String description) { this.prettyName = prettyName; this.description = description; } - + public String getPrettyName() { return prettyName; } - + public String getDescription() { return description; } diff --git a/src/main/java/com/matt/forgehax/util/mod/CommandMod.java b/src/main/java/com/matt/forgehax/util/mod/CommandMod.java index 62e34000d..ec121c33e 100644 --- a/src/main/java/com/matt/forgehax/util/mod/CommandMod.java +++ b/src/main/java/com/matt/forgehax/util/mod/CommandMod.java @@ -2,7 +2,6 @@ import com.google.common.collect.Lists; import com.matt.forgehax.Helper; -import com.matt.forgehax.mcversion.MCVersionChecker; import com.matt.forgehax.util.command.Command; import com.matt.forgehax.util.command.CommandBuilders; import java.lang.annotation.ElementType; @@ -14,18 +13,21 @@ import java.util.Collection; import joptsimple.internal.Strings; -/** Created on 6/1/2017 by fr1kin */ +/** + * Created on 6/1/2017 by fr1kin + */ public class CommandMod extends ServiceMod { + private final Collection commands = Lists.newArrayList(); - + public CommandMod(String name, String desc) { super(name, desc); } - + public CommandMod(String name) { super(name, Strings.EMPTY); } - + @Override protected void onLoad() { try { @@ -33,9 +35,8 @@ protected void onLoad() { try { m.setAccessible(true); if (m.isAnnotationPresent(RegisterCommand.class) - && Arrays.equals(m.getParameterTypes(), new Class[] {CommandBuilders.class}) - && Command.class.isAssignableFrom(m.getReturnType())) { - MCVersionChecker.requireValidVersion(m); + && Arrays.equals(m.getParameterTypes(), new Class[]{CommandBuilders.class}) + && Command.class.isAssignableFrom(m.getReturnType())) { commands.add((Command) m.invoke(this, Helper.getGlobalCommand().builders())); } } catch (Throwable t) { @@ -46,13 +47,15 @@ protected void onLoad() { Helper.handleThrowable(t); } } - + @Override protected void onUnload() { commands.forEach(Command::leaveParent); } - + @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) - public @interface RegisterCommand {} + public @interface RegisterCommand { + + } } diff --git a/src/main/java/com/matt/forgehax/util/mod/ServiceMod.java b/src/main/java/com/matt/forgehax/util/mod/ServiceMod.java index 4e1977a91..f115698cc 100644 --- a/src/main/java/com/matt/forgehax/util/mod/ServiceMod.java +++ b/src/main/java/com/matt/forgehax/util/mod/ServiceMod.java @@ -2,41 +2,50 @@ import com.matt.forgehax.util.command.callbacks.CallbackData; -/** Created on 6/14/2017 by fr1kin */ +/** + * Created on 6/14/2017 by fr1kin + */ public class ServiceMod extends BaseMod { + public ServiceMod(String name, String desc) { super(Category.SERVICE, name, desc); } - + public ServiceMod(String name) { super(Category.SERVICE, name); } - + @Override public boolean isHidden() { return true; } - + @Override public boolean isEnabled() { return true; } - + @Override - protected void onLoad() {} - + protected void onLoad() { + } + @Override - protected void onUnload() {} - + protected void onUnload() { + } + @Override - protected void onEnabled() {} - + protected void onEnabled() { + } + @Override - protected void onDisabled() {} - + protected void onDisabled() { + } + @Override - protected void onBindPressed(CallbackData cb) {} - + protected void onBindPressed(CallbackData cb) { + } + @Override - protected void onBindKeyDown(CallbackData cb) {} + protected void onBindKeyDown(CallbackData cb) { + } } diff --git a/src/main/java/com/matt/forgehax/util/mod/ToggleMod.java b/src/main/java/com/matt/forgehax/util/mod/ToggleMod.java index 0ae669c67..e13f6fecf 100644 --- a/src/main/java/com/matt/forgehax/util/mod/ToggleMod.java +++ b/src/main/java/com/matt/forgehax/util/mod/ToggleMod.java @@ -5,81 +5,99 @@ import com.matt.forgehax.util.command.callbacks.CallbackData; public class ToggleMod extends BaseMod { + private final Setting enabled; - + public ToggleMod(Category category, String modName, boolean defaultValue, String description) { super(category, modName, description); this.enabled = - getCommandStub() - .builders() - .newSettingBuilder() - .name("enabled") - .description("Enables the mod") - .defaultTo(defaultValue) - .changed( - cb -> { // value is set after callback is ran 🤡 - // do not call anything that might infinitely call this callback - if (cb.getTo()) start(); - else stop(); - }) - .build(); + getCommandStub() + .builders() + .newSettingBuilder() + .name("enabled") + .description("Enables the mod") + .defaultTo(defaultValue) + .changed( + cb -> { // value is set after callback is ran 🤡 + // do not call anything that might infinitely call this callback + if (cb.getTo()) { + start(); + } else { + stop(); + } + }) + .build(); } - - /** Toggle mod to be on/off */ + + /** + * Toggle mod to be on/off + */ public final void toggle() { - if (isEnabled()) disable(); - else enable(); + if (isEnabled()) { + disable(); + } else { + enable(); + } } - + @Override public void enable() { enabled.set(true); } - + @Override public void disable() { enabled.set(false); } - + @Override protected StubBuilder buildStubCommand(StubBuilder builder) { return builder.kpressed(this::onBindPressed).kdown(this::onBindKeyDown).bind(); } - + @Override public String getDebugDisplayText() { return super.getDebugDisplayText(); } - + @Override public boolean isHidden() { return false; } - - /** Check if the mod is currently enabled */ + + /** + * Check if the mod is currently enabled + */ @Override public final boolean isEnabled() { return enabled.get(); } - + @Override - protected void onLoad() {} - + protected void onLoad() { + } + @Override - protected void onUnload() {} - + protected void onUnload() { + } + @Override - protected void onEnabled() {} - + protected void onEnabled() { + } + @Override - protected void onDisabled() {} - - /** Toggles the mod */ + protected void onDisabled() { + } + + /** + * Toggles the mod + */ @Override public void onBindPressed(CallbackData cb) { toggle(); } - + @Override - protected void onBindKeyDown(CallbackData cb) {} + protected void onBindKeyDown(CallbackData cb) { + } } diff --git a/src/main/java/com/matt/forgehax/util/mod/loader/ModManager.java b/src/main/java/com/matt/forgehax/util/mod/loader/ModManager.java index 6629c4a61..353447025 100644 --- a/src/main/java/com/matt/forgehax/util/mod/loader/ModManager.java +++ b/src/main/java/com/matt/forgehax/util/mod/loader/ModManager.java @@ -17,56 +17,66 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.*; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.Consumer; import java.util.stream.Stream; import javax.annotation.Nullable; -/** Created on 5/16/2017 by fr1kin */ +/** + * Created on 5/16/2017 by fr1kin + */ public class ModManager extends AbstractClassLoader implements Globals { + private static final ModManager INSTANCE = new ModManager(); - + public static ModManager getInstance() { return INSTANCE; } - + // // // - + private final Set> classes = Sets.newHashSet(); private final Set active = - Sets.newTreeSet(Comparator.comparing(BaseMod::getModName, String.CASE_INSENSITIVE_ORDER)); - + Sets.newTreeSet(Comparator.comparing(BaseMod::getModName, String.CASE_INSENSITIVE_ORDER)); + public boolean searchPackage(String packageDir) { try { return classes.addAll( - filterClassPaths( - getFMLClassLoader(), - ClassLoaderHelper.getClassPathsInPackage(getFMLClassLoader(), packageDir))); + filterClassPaths( + getFMLClassLoader(), + ClassLoaderHelper.getClassPathsInPackage(getFMLClassLoader(), packageDir))); } catch (IOException e) { e.printStackTrace(); return false; } } - + public boolean searchPlugin(Path jar, String packageDir) { - if (!Files.exists(jar)) + if (!Files.exists(jar)) { throw new IllegalArgumentException("path must lead to an existing jar file"); + } try { FileSystem fs = FileHelper.newFileSystem(jar); ClassLoader classLoader = CustomClassLoaders.newFsClassLoader(getFMLClassLoader(), fs); return classes.addAll( - filterClassPaths(classLoader, ClassLoaderHelper.getClassPathsInJar(jar, packageDir))); + filterClassPaths(classLoader, ClassLoaderHelper.getClassPathsInJar(jar, packageDir))); } catch (IOException e) { e.printStackTrace(); return false; } } - + public boolean searchPluginDirectory(Path directory, String... packageDir) { - if (packageDir.length > 1) + if (packageDir.length > 1) { throw new IllegalArgumentException("Path should be contained in first array index"); + } if (!Files.exists(directory)) { getLog().warn("plugin directory '" + directory.toString() + "' does not exist"); return false; @@ -77,91 +87,95 @@ public boolean searchPluginDirectory(Path directory, String... packageDir) { } try { return Files.list(directory) - .filter(Files::isRegularFile) - .filter(path -> FileHelper.getFileExtension(path).equals("jar")) - .anyMatch(path -> searchPlugin(path, ArrayHelper.getOrDefault(packageDir, 0, ""))); + .filter(Files::isRegularFile) + .filter(path -> FileHelper.getFileExtension(path).equals("jar")) + .anyMatch(path -> searchPlugin(path, ArrayHelper.getOrDefault(packageDir, 0, ""))); } catch (IOException e) { e.printStackTrace(); return false; } } - + public boolean searchPluginDirectory(String directory, String... packageDir) { return searchPluginDirectory(Paths.get(directory), packageDir); } - + private Stream> unloadedClasses() { return classes - .stream() - .filter(clazz -> active.stream().noneMatch(mod -> mod.getClass().equals(clazz))); + .stream() + .filter(clazz -> active.stream().noneMatch(mod -> mod.getClass().equals(clazz))); } - + private Stream> loadedClasses() { return classes - .stream() - .filter(clazz -> active.stream().anyMatch(mod -> mod.getClass().equals(clazz))); + .stream() + .filter(clazz -> active.stream().anyMatch(mod -> mod.getClass().equals(clazz))); } - + public Collection> getUnloadedClasses() { return unloadedClasses().collect(Immutables.toImmutableList()); } - + public Collection> getLoadedClasses() { return loadedClasses().collect(Immutables.toImmutableList()); } - + public Collection getMods() { return Collections.unmodifiableCollection(active); } - + public Optional get(final String modName) { return active.stream().filter(mod -> mod.getModName().equalsIgnoreCase(modName)).findFirst(); } - + @SuppressWarnings("unchecked") public Optional get(final Class clazz) { return active - .stream() - .filter(mod -> Objects.equals(clazz, mod.getClass())) - .map(mod -> (T) mod) - .findFirst(); + .stream() + .filter(mod -> Objects.equals(clazz, mod.getClass())) + .map(mod -> (T) mod) + .findFirst(); } - + public void load(Class clazz) { unloadedClasses().filter(clazz::equals).findFirst().ifPresent(this::_load); } - + private void _load(Class clazz) { - if (active.add(loadClass(clazz))) getLog().info("Loaded mod " + clazz.getSimpleName()); + if (active.add(loadClass(clazz))) { + getLog().info("Loaded mod " + clazz.getSimpleName()); + } } - + public void loadAll() { unloadedClasses().forEach(this::_load); } - + public void unload(BaseMod mod) { - if (active.remove(mod)) mod.unload(); + if (active.remove(mod)) { + mod.unload(); + } } - + public void unloadAll() { active.forEach(this::unload); } - + public void refresh() { forEach(BaseMod::unload); forEach(BaseMod::load); } - + public void forEach(final Consumer consumer) { active.forEach(consumer); } - + @Nullable @Override public Class getInheritedClass() { return BaseMod.class; } - + @Nullable @Override public Class getAnnotationClass() { diff --git a/src/main/java/com/matt/forgehax/util/mod/loader/RegisterMod.java b/src/main/java/com/matt/forgehax/util/mod/loader/RegisterMod.java index d7e7eeb38..38be79fd3 100644 --- a/src/main/java/com/matt/forgehax/util/mod/loader/RegisterMod.java +++ b/src/main/java/com/matt/forgehax/util/mod/loader/RegisterMod.java @@ -5,7 +5,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -/** Created on 5/16/2017 by fr1kin */ +/** + * Created on 5/16/2017 by fr1kin + */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -public @interface RegisterMod {} +public @interface RegisterMod { + +} diff --git a/src/main/java/com/matt/forgehax/util/projectile/IProjectile.java b/src/main/java/com/matt/forgehax/util/projectile/IProjectile.java index 22f9db6fa..713da30da 100644 --- a/src/main/java/com/matt/forgehax/util/projectile/IProjectile.java +++ b/src/main/java/com/matt/forgehax/util/projectile/IProjectile.java @@ -2,34 +2,37 @@ import net.minecraft.item.Item; -/** Created on 6/21/2017 by fr1kin */ +/** + * Created on 6/21/2017 by fr1kin + */ public interface IProjectile { + Item getItem(); - + default double getForce(int charge) { return 1.5D; } - + default double getMaxForce() { return 1.5D; } - + default double getMinForce() { return 1.5D; } - + default double getGravity() { return 0.03D; } - + default double getDrag() { return 0.99D; } - + default double getWaterDrag() { return 0.8D; } - + default double getProjectileSize() { return 0.25D; } diff --git a/src/main/java/com/matt/forgehax/util/projectile/Projectile.java b/src/main/java/com/matt/forgehax/util/projectile/Projectile.java index e615bccbf..7de618df4 100644 --- a/src/main/java/com/matt/forgehax/util/projectile/Projectile.java +++ b/src/main/java/com/matt/forgehax/util/projectile/Projectile.java @@ -19,44 +19,46 @@ import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; -/** Created on 6/21/2017 by fr1kin */ +/** + * Created on 6/21/2017 by fr1kin + */ public enum Projectile implements IProjectile { NULL() { @Override public Item getItem() { return null; } - + @Override public double getForce(int charge) { return 0; } - + @Override public double getMaxForce() { return 0; } - + @Override public double getMinForce() { return 0; } - + @Override public double getGravity() { return 0; } - + @Override public double getDrag() { return 0; } - + @Override public double getWaterDrag() { return 0; } - + @Override public double getProjectileSize() { return 0; @@ -67,36 +69,38 @@ public double getProjectileSize() { public Item getItem() { return Items.BOW; } - + @Override public double getForce(int charge) { double force = (double) charge / 20.0F; // force = (force * force + force * 2.0F) / 3.0F; - if (force > 1.0F) force = 1.0F; + if (force > 1.0F) { + force = 1.0F; + } force *= 2d * 1.5d; return force; } - + @Override public double getMaxForce() { return 3.D; } - + @Override public double getMinForce() { return 0.15D; } - + @Override public double getGravity() { return 0.05D; } - + @Override public double getWaterDrag() { return 0.6D; } - + @Override public double getProjectileSize() { return 0.5D; @@ -119,12 +123,12 @@ public Item getItem() { public Item getItem() { return Items.FISHING_ROD; } - + @Override public double getGravity() { return 0.03999999910593033D; } - + @Override public double getDrag() { return 0.92D; @@ -136,45 +140,47 @@ public Item getItem() { return Items.ENDER_PEARL; } }; - + private static final int MAX_ITERATIONS = - 1000; // fail safe to prevent infinite loops. MUST be greater than 1 + 1000; // fail safe to prevent infinite loops. MUST be greater than 1 private static final double SHOOT_POS_OFFSET = 0.10000000149011612D; - + public boolean isNull() { return getItem() == null; } - + @Nullable public SimulationResult getSimulatedTrajectory( - Vec3d shootPos, Angle angle, double force, int factor) throws IllegalArgumentException { - if (isNull()) return null; - + Vec3d shootPos, Angle angle, double force, int factor) throws IllegalArgumentException { + if (isNull()) { + return null; + } + Entity hitEntity = null; - + double[] forward = angle.getForwardVector(); Vec3d v = new Vec3d(forward[0], forward[1], forward[2]).normalize().scale(force); - + double velocityX = v.x; double velocityY = v.y; double velocityZ = v.z; - + double distanceTraveledSq = 0.D; - + RayTraceResult trace; - + List points = Lists.newArrayList(); points.add(shootPos); // add the initial position - + Vec3d next = new Vec3d(shootPos.x, shootPos.y, shootPos.z); Vec3d previous = next; - + for (int index = points.size(), n = 0; index < MAX_ITERATIONS; index++) { next = next.addVector(velocityX, velocityY, velocityZ); - + AxisAlignedBB bb = getBoundBox(next); trace = rayTraceCheckEntityCollisions(previous, next, bb, velocityX, velocityY, velocityZ); - + if (trace != null) { hitEntity = trace.entityHit; distanceTraveledSq += previous.squareDistanceTo(trace.hitVec); @@ -186,76 +192,86 @@ public SimulationResult getSimulatedTrajectory( if (n == factor) { points.add(next); n = 0; - } else n++; - + } else { + n++; + } + distanceTraveledSq += previous.squareDistanceTo(next); - + // in the void, stop - if (next.y <= 0) break; - + if (next.y <= 0) { + break; + } + double d = getWorld().isMaterialInBB(bb, Material.WATER) ? getWaterDrag() : getDrag(); - + velocityX = (velocityX * d); velocityY = (velocityY * d) - getGravity(); velocityZ = (velocityZ * d); - + previous = next; } return new SimulationResult(points, distanceTraveledSq, hitEntity); } - + @Nullable public SimulationResult getSimulatedTrajectoryFromEntity( - Entity shooter, Angle angle, double force, int factor) { + Entity shooter, Angle angle, double force, int factor) { angle = getAngleFacing(angle); return getSimulatedTrajectory(getShootPosFacing(shooter, angle), angle, force, factor); } - + @Nullable public Angle getEstimatedImpactAngleInRadians(Vec3d shooterPos, Vec3d targetPos, double force) { - if (isNull()) return null; + if (isNull()) { + return null; + } Vec3d start = shooterPos.subtract(targetPos); - + double pitch; double yaw = AngleHelper.getAngleFacingInRadians(targetPos.subtract(shooterPos)).getYaw(); - + // to find the pitch we use this equation // https://en.wikipedia.org/wiki/Trajectory_of_a_projectile#Angle_.7F.27.22.60UNIQ--postMath-00000010-QINU.60.22.27.7F_required_to_hit_coordinate_.28x.2Cy.29 - + // calculate air resistance in the acceleration force *= getDrag(); - + // magnitude of a 2d vector double x = Math.sqrt(start.x * start.x + start.z * start.z); double g = getGravity(); - + double root = Math.pow(force, 4) - g * (g * Math.pow(x, 2) + 2 * start.y * Math.pow(force, 2)); - + // if the root is negative then we will get a non-real result - if (root < 0) return null; - + if (root < 0) { + return null; + } + // there are two possible solutions // +root and -root double A = (Math.pow(force, 2) + Math.sqrt(root)) / (g * x); double B = (Math.pow(force, 2) - Math.sqrt(root)) / (g * x); - + // use the lowest pitch pitch = Math.atan(Math.max(A, B)); - + return Angle.radians((float) pitch, (float) yaw).normalize(); } - + @Nullable public Angle getEstimatedImpactAngleInRadiansFromEntity( - Entity entity, Vec3d targetPos, double force) { + Entity entity, Vec3d targetPos, double force) { return getEstimatedImpactAngleInRadians(getEntityShootPos(entity), targetPos, force); } - + public boolean canHitEntity(Vec3d shooterPos, Entity targetEntity) { - if (isNull()) return false; - + if (isNull()) { + return false; + } + Vec3d targetPos = EntityUtils.getOBBCenter(targetEntity); - + double min = getMinForce(); double max = getMaxForce(); // work backwards @@ -264,44 +280,51 @@ public boolean canHitEntity(Vec3d shooterPos, Entity targetEntity) { // im just abusing it so that I can get it to work with other projectile items for (double force = max; force >= min; force -= min) { Angle shootAngle = getEstimatedImpactAngleInRadians(shooterPos, targetPos, force); - if (shootAngle == null) continue; - + if (shootAngle == null) { + continue; + } + SimulationResult result = getSimulatedTrajectory(shooterPos, shootAngle, force, -1); - if (result == null) + if (result == null) { return false; // this shouldn't happen, but I put it here to stop intelliJ from complaining - + } + // the trace has intercepted with our target - if (Objects.equals(targetEntity, result.getHitEntity())) return true; + if (Objects.equals(targetEntity, result.getHitEntity())) { + return true; + } } return false; } - + // #################################################################################################### - + private AxisAlignedBB getBoundBox(Vec3d pos) { double mp = getProjectileSize() / 2.D; return new AxisAlignedBB( - pos.x - mp, pos.y - mp, pos.z - mp, pos.x + mp, pos.y + mp, pos.z + mp); + pos.x - mp, pos.y - mp, pos.z - mp, pos.x + mp, pos.y + mp, pos.z + mp); } - + // #################################################################################################### - + private static RayTraceResult rayTraceCheckEntityCollisions( - Vec3d start, Vec3d end, AxisAlignedBB bb, double motionX, double motionY, double motionZ) { + Vec3d start, Vec3d end, AxisAlignedBB bb, double motionX, double motionY, double motionZ) { RayTraceResult trace = getWorld().rayTraceBlocks(start, end, false, true, false); - - if (trace != null) end = trace.hitVec; - + + if (trace != null) { + end = trace.hitVec; + } + // now check entity collisions List entities = - getWorld() - .getEntitiesWithinAABBExcludingEntity( - getLocalPlayer(), bb.expand(motionX, motionY, motionZ).grow(1.D)); - + getWorld() + .getEntitiesWithinAABBExcludingEntity( + getLocalPlayer(), bb.expand(motionX, motionY, motionZ).grow(1.D)); + double best = 0.D; Vec3d hitPos = Vec3d.ZERO; Entity hitEntity = null; - + for (Entity entity : entities) { if (entity.canBeCollidedWith()) { float size = entity.getCollisionBorderSize(); @@ -317,37 +340,42 @@ private static RayTraceResult rayTraceCheckEntityCollisions( } } } - + if (hitEntity != null) { trace = new RayTraceResult(hitEntity, hitPos); } - + return trace; } - + private static Vec3d getEntityShootPos(Entity entity) { return EntityUtils.getEyePos(entity).subtract(0.D, SHOOT_POS_OFFSET, 0.D); } - + private static Vec3d getShootPosFacing(Entity entity, Angle angleFacing) { return getEntityShootPos(entity) - .subtract( - Math.cos(angleFacing.inRadians().getYaw() - AngleHelper.HALF_PI) * 0.16D, - 0.D, - Math.sin(angleFacing.inRadians().getYaw() - AngleHelper.HALF_PI) * 0.16D); + .subtract( + Math.cos(angleFacing.inRadians().getYaw() - AngleHelper.HALF_PI) * 0.16D, + 0.D, + Math.sin(angleFacing.inRadians().getYaw() - AngleHelper.HALF_PI) * 0.16D); } - + private static Angle getAngleFacing(Angle angle) { return Angle.radians( - -angle.inRadians().getPitch(), (float) (angle.inRadians().getYaw() + (Math.PI / 2.D))); + -angle.inRadians().getPitch(), (float) (angle.inRadians().getYaw() + (Math.PI / 2.D))); } - + public static Projectile getProjectileByItem(Item item) { - if (item != null) - for (Projectile p : values()) if (p.getItem() != null && p.getItem().equals(item)) return p; + if (item != null) { + for (Projectile p : values()) { + if (p.getItem() != null && p.getItem().equals(item)) { + return p; + } + } + } return NULL; } - + public static Projectile getProjectileByItemStack(ItemStack item) { return item == null ? NULL : getProjectileByItem(item.getItem()); } diff --git a/src/main/java/com/matt/forgehax/util/projectile/SimulationResult.java b/src/main/java/com/matt/forgehax/util/projectile/SimulationResult.java index 39982d2da..6416fbb5e 100644 --- a/src/main/java/com/matt/forgehax/util/projectile/SimulationResult.java +++ b/src/main/java/com/matt/forgehax/util/projectile/SimulationResult.java @@ -5,8 +5,11 @@ import net.minecraft.entity.Entity; import net.minecraft.util.math.Vec3d; -/** Created on 6/22/2017 by fr1kin */ +/** + * Created on 6/22/2017 by fr1kin + */ public class SimulationResult { + private final List points; private final double distanceTraveledSq; private final Entity hitEntity; @@ -50,7 +53,9 @@ public double getDistanceApartSq() { Vec3d hit = getHitPos(); if (start != null && hit != null) { return start.squareDistanceTo(hit); - } else return 0.D; + } else { + return 0.D; + } } public List getPathTraveled() { diff --git a/src/main/java/com/matt/forgehax/util/serialization/GsonConstant.java b/src/main/java/com/matt/forgehax/util/serialization/GsonConstant.java index e2281f1e3..6a8b1459c 100644 --- a/src/main/java/com/matt/forgehax/util/serialization/GsonConstant.java +++ b/src/main/java/com/matt/forgehax/util/serialization/GsonConstant.java @@ -4,8 +4,11 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonParser; -/** Created on 5/23/2017 by fr1kin */ +/** + * Created on 5/23/2017 by fr1kin + */ public interface GsonConstant { + Gson GSON = new Gson(); Gson GSON_PRETTY = new GsonBuilder().setPrettyPrinting().create(); JsonParser PARSER = new JsonParser(); diff --git a/src/main/java/com/matt/forgehax/util/serialization/ISerializableImmutable.java b/src/main/java/com/matt/forgehax/util/serialization/ISerializableImmutable.java index a24c86a4c..1b1500e61 100644 --- a/src/main/java/com/matt/forgehax/util/serialization/ISerializableImmutable.java +++ b/src/main/java/com/matt/forgehax/util/serialization/ISerializableImmutable.java @@ -6,6 +6,7 @@ import javax.annotation.Nullable; public interface ISerializableImmutable { + void serialize(JsonWriter writer, @Nullable E instance) throws IOException; @Nullable diff --git a/src/main/java/com/matt/forgehax/util/serialization/ISerializableJson.java b/src/main/java/com/matt/forgehax/util/serialization/ISerializableJson.java index 9d2470afe..0bdb4af7d 100644 --- a/src/main/java/com/matt/forgehax/util/serialization/ISerializableJson.java +++ b/src/main/java/com/matt/forgehax/util/serialization/ISerializableJson.java @@ -4,8 +4,11 @@ import com.google.gson.stream.JsonWriter; import java.io.IOException; -/** Created on 5/20/2017 by fr1kin */ +/** + * Created on 5/20/2017 by fr1kin + */ public interface ISerializableJson { + /** * Serialize this object and all necessary data into json * @@ -13,7 +16,7 @@ public interface ISerializableJson { * @throws IOException if you format the json incorrectly */ void serialize(final JsonWriter writer) throws IOException; - + /** * Deserialize data from json into a new object. * @@ -21,7 +24,7 @@ public interface ISerializableJson { * @throws IOException if you read the json incorrectly */ void deserialize(final JsonReader reader) throws IOException; - + /** * A unique heading to identify this object. * diff --git a/src/main/java/com/matt/forgehax/util/serialization/ISerializableMutable.java b/src/main/java/com/matt/forgehax/util/serialization/ISerializableMutable.java index 2eea2e30e..433177d5a 100644 --- a/src/main/java/com/matt/forgehax/util/serialization/ISerializableMutable.java +++ b/src/main/java/com/matt/forgehax/util/serialization/ISerializableMutable.java @@ -5,6 +5,7 @@ import java.io.IOException; public interface ISerializableMutable { + void serialize(E instance, JsonWriter writer) throws IOException; void deserialize(E instance, JsonReader reader) throws IOException; diff --git a/src/main/java/com/matt/forgehax/util/serialization/ISerializer.java b/src/main/java/com/matt/forgehax/util/serialization/ISerializer.java index 1c213de78..fbf74ae3d 100644 --- a/src/main/java/com/matt/forgehax/util/serialization/ISerializer.java +++ b/src/main/java/com/matt/forgehax/util/serialization/ISerializer.java @@ -1,8 +1,11 @@ package com.matt.forgehax.util.serialization; -/** Created on 6/4/2017 by fr1kin */ +/** + * Created on 6/4/2017 by fr1kin + */ public interface ISerializer { + void serialize(); - + void deserialize(); } diff --git a/src/main/java/com/matt/forgehax/util/serialization/Serializers.java b/src/main/java/com/matt/forgehax/util/serialization/Serializers.java index b73c638f1..a7a178709 100644 --- a/src/main/java/com/matt/forgehax/util/serialization/Serializers.java +++ b/src/main/java/com/matt/forgehax/util/serialization/Serializers.java @@ -6,20 +6,21 @@ import javax.annotation.Nullable; public class Serializers { - private static final ISerializableImmutable IMMUTABLE_NULL = - new ISerializableImmutable() { - @Override - public void serialize(JsonWriter writer, @Nullable Object instance) throws IOException { - writer.nullValue(); - } - @Nullable - @Override - public Object deserialize(JsonReader reader) throws IOException { - reader.nextNull(); - return null; - } - }; + private static final ISerializableImmutable IMMUTABLE_NULL = + new ISerializableImmutable() { + @Override + public void serialize(JsonWriter writer, @Nullable Object instance) throws IOException { + writer.nullValue(); + } + + @Nullable + @Override + public Object deserialize(JsonReader reader) throws IOException { + reader.nextNull(); + return null; + } + }; public static ISerializableImmutable nullSerializer() { return IMMUTABLE_NULL; diff --git a/src/main/java/com/matt/forgehax/util/spam/SpamEntry.java b/src/main/java/com/matt/forgehax/util/spam/SpamEntry.java index 92fe6ca88..eff397c23 100644 --- a/src/main/java/com/matt/forgehax/util/spam/SpamEntry.java +++ b/src/main/java/com/matt/forgehax/util/spam/SpamEntry.java @@ -10,42 +10,59 @@ import java.util.concurrent.ThreadLocalRandom; import joptsimple.internal.Strings; -/** Created on 7/18/2017 by fr1kin */ +/** + * Created on 7/18/2017 by fr1kin + */ public class SpamEntry implements ISerializableJson { - /** A unique name used to identify this entry */ + + /** + * A unique name used to identify this entry + */ private final String name; - - /** List of messages (no duplicates allowed) */ + + /** + * List of messages (no duplicates allowed) + */ private final List messages = Lists.newCopyOnWriteArrayList(); - + private boolean enabled = true; - - /** Keyword that triggers this */ + + /** + * Keyword that triggers this + */ private String keyword = Strings.EMPTY; - - /** How the message should be selected from the list */ + + /** + * How the message should be selected from the list + */ private SpamType type = SpamType.RANDOM; - - /** What should trigger a message from being outputted */ + + /** + * What should trigger a message from being outputted + */ private SpamTrigger trigger = SpamTrigger.SPAM; - - /** Custom delay */ + + /** + * Custom delay + */ private long delay = 0; - + public SpamEntry(String name) { this.name = name; } - + public void add(String msg) { - if (!Strings.isNullOrEmpty(msg) && !messages.contains(msg)) messages.add(msg); + if (!Strings.isNullOrEmpty(msg) && !messages.contains(msg)) { + messages.add(msg); + } } - + public void remove(String msg) { messages.remove(msg); } - + private int nextIndex = 0; - + public String next() { if (!messages.isEmpty()) { switch (type) { @@ -57,104 +74,108 @@ public String next() { } return Strings.EMPTY; } - + public void reset() { nextIndex = 0; } - + public boolean isEnabled() { return enabled; } - + public String getName() { return name; } - + public String getKeyword() { return keyword; } - + public SpamType getType() { return type; } - + public SpamTrigger getTrigger() { return trigger; } - + public List getMessages() { return Collections.unmodifiableList(messages); } - + public long getDelay() { return delay; } - + public void setEnabled(boolean enabled) { this.enabled = enabled; } - + public void setKeyword(String keyword) { this.keyword = keyword; } - + public void setType(SpamType type) { - if (type != null) this.type = type; + if (type != null) { + this.type = type; + } } - + public void setType(String type) { setType(SpamType.valueOf(type.toUpperCase())); } - + public void setTrigger(SpamTrigger trigger) { - if (trigger != null) this.trigger = trigger; + if (trigger != null) { + this.trigger = trigger; + } } - + public void setTrigger(String trigger) { setTrigger(SpamTrigger.valueOf(trigger.toUpperCase())); } - + public void setDelay(long delay) { this.delay = delay; } - + public boolean isEmpty() { return messages.isEmpty(); } - + @Override public void serialize(JsonWriter writer) throws IOException { writer.beginObject(); - + writer.name("enabled"); writer.value(enabled); - + writer.name("keyword"); writer.value(keyword); - + writer.name("type"); writer.value(type.name()); - + writer.name("trigger"); writer.value(trigger.name()); - + writer.name("delay"); writer.value(getDelay()); - + writer.name("messages"); writer.beginArray(); for (String msg : messages) { writer.value(msg); } writer.endArray(); - + writer.endObject(); } - + @Override public void deserialize(JsonReader reader) throws IOException { reader.beginObject(); - + while (reader.hasNext()) { switch (reader.nextName()) { case "enabled": @@ -183,23 +204,23 @@ public void deserialize(JsonReader reader) throws IOException { break; } } - + reader.endObject(); } - + @Override public boolean equals(Object obj) { return (obj instanceof SpamEntry - && String.CASE_INSENSITIVE_ORDER.compare(name, ((SpamEntry) obj).name) == 0) - || (obj instanceof String - && String.CASE_INSENSITIVE_ORDER.compare(name, (String) obj) == 0); + && String.CASE_INSENSITIVE_ORDER.compare(name, ((SpamEntry) obj).name) == 0) + || (obj instanceof String + && String.CASE_INSENSITIVE_ORDER.compare(name, (String) obj) == 0); } - + @Override public int hashCode() { return name.toLowerCase().hashCode(); } - + @Override public String toString() { return name; diff --git a/src/main/java/com/matt/forgehax/util/spam/SpamMessage.java b/src/main/java/com/matt/forgehax/util/spam/SpamMessage.java index 3572b26d5..9e26a1e55 100644 --- a/src/main/java/com/matt/forgehax/util/spam/SpamMessage.java +++ b/src/main/java/com/matt/forgehax/util/spam/SpamMessage.java @@ -2,8 +2,11 @@ import com.matt.forgehax.util.common.PriorityEnum; -/** Created on 7/21/2017 by fr1kin */ +/** + * Created on 7/21/2017 by fr1kin + */ public class SpamMessage implements Comparable { + private final String message; private final String type; private final long delay; @@ -11,7 +14,7 @@ public class SpamMessage implements Comparable { private final PriorityEnum priority; public SpamMessage( - String message, String type, long delay, String activator, PriorityEnum priority) { + String message, String type, long delay, String activator, PriorityEnum priority) { this.message = message; this.type = type.toLowerCase(); this.delay = delay; @@ -43,10 +46,10 @@ public int compareTo(SpamMessage o) { @Override public boolean equals(Object obj) { return obj == this - || (obj instanceof SpamMessage - && activator != null - && ((SpamMessage) obj).activator != null - && activator.equalsIgnoreCase(((SpamMessage) obj).activator)); + || (obj instanceof SpamMessage + && activator != null + && ((SpamMessage) obj).activator != null + && activator.equalsIgnoreCase(((SpamMessage) obj).activator)); } @Override diff --git a/src/main/java/com/matt/forgehax/util/spam/SpamTokens.java b/src/main/java/com/matt/forgehax/util/spam/SpamTokens.java index 5a13e72aa..b0801d948 100644 --- a/src/main/java/com/matt/forgehax/util/spam/SpamTokens.java +++ b/src/main/java/com/matt/forgehax/util/spam/SpamTokens.java @@ -2,25 +2,35 @@ import java.util.regex.Matcher; -/** Created on 7/18/2017 by fr1kin */ +/** + * Created on 7/18/2017 by fr1kin + */ public enum SpamTokens { - /** The main subjects name */ + /** + * The main subjects name + */ PLAYER_NAME("PLAYER_NAME"), - - /** History of the main subjects name */ + + /** + * History of the main subjects name + */ NAME_HISTORY("NAME_HISTORY"), - - /** Person sending the message */ + + /** + * Person sending the message + */ SENDER_NAME("SENDER_NAME"), - - /** Message */ + + /** + * Message + */ MESSAGE("MESSAGE"), ; public static SpamTokens[] ALL = - new SpamTokens[] {PLAYER_NAME, NAME_HISTORY, SENDER_NAME, MESSAGE}; - public static SpamTokens[] PLAYERNAME_NAMEHISTORY = new SpamTokens[] {PLAYER_NAME, NAME_HISTORY}; - public static SpamTokens[] PLAYERNAME_SENDERNAME = new SpamTokens[] {PLAYER_NAME, SENDER_NAME}; + new SpamTokens[]{PLAYER_NAME, NAME_HISTORY, SENDER_NAME, MESSAGE}; + public static SpamTokens[] PLAYERNAME_NAMEHISTORY = new SpamTokens[]{PLAYER_NAME, NAME_HISTORY}; + public static SpamTokens[] PLAYERNAME_SENDERNAME = new SpamTokens[]{PLAYER_NAME, SENDER_NAME}; final String token; @@ -33,8 +43,9 @@ public String fill(String str, String with) { } public static String fillAll(String str, SpamTokens[] tokens, String... replacements) { - if (replacements.length != tokens.length) + if (replacements.length != tokens.length) { throw new IllegalArgumentException("replacements length != tokens length"); + } for (int i = 0; i < replacements.length; i++) { str = tokens[i].fill(str, replacements[i]); } diff --git a/src/main/java/com/matt/forgehax/util/spam/SpamTrigger.java b/src/main/java/com/matt/forgehax/util/spam/SpamTrigger.java index 3ac715cfb..a7c174563 100644 --- a/src/main/java/com/matt/forgehax/util/spam/SpamTrigger.java +++ b/src/main/java/com/matt/forgehax/util/spam/SpamTrigger.java @@ -1,18 +1,30 @@ package com.matt.forgehax.util.spam; -/** Created on 7/19/2017 by fr1kin */ +/** + * Created on 7/19/2017 by fr1kin + */ public enum SpamTrigger { - /** Triggered every X amount of time */ + /** + * Triggered every X amount of time + */ SPAM, - /** Triggered when a player enters the keyword */ + /** + * Triggered when a player enters the keyword + */ REPLY, - - /** Triggered when a player enters the keyword and has an argument present */ + + /** + * Triggered when a player enters the keyword and has an argument present + */ REPLY_WITH_INPUT, - - /** Triggered when player connects to server */ + + /** + * Triggered when player connects to server + */ PLAYER_CONNECT, - - /** Triggered when player disconnects from server */ + + /** + * Triggered when player disconnects from server + */ PLAYER_DISCONNECT; } diff --git a/src/main/java/com/matt/forgehax/util/spam/SpamType.java b/src/main/java/com/matt/forgehax/util/spam/SpamType.java index b20bfad05..5345006da 100644 --- a/src/main/java/com/matt/forgehax/util/spam/SpamType.java +++ b/src/main/java/com/matt/forgehax/util/spam/SpamType.java @@ -1,11 +1,17 @@ package com.matt.forgehax.util.spam; -/** Created on 7/18/2017 by fr1kin */ +/** + * Created on 7/18/2017 by fr1kin + */ public enum SpamType { - /** Randomly select from list */ + /** + * Randomly select from list + */ RANDOM, - - /** Sequentially select from list */ + + /** + * Sequentially select from list + */ SEQUENTIAL, ; } diff --git a/src/main/java/com/matt/forgehax/util/task/IProcess.java b/src/main/java/com/matt/forgehax/util/task/IProcess.java index 3abd4f6a1..358b5ed6f 100644 --- a/src/main/java/com/matt/forgehax/util/task/IProcess.java +++ b/src/main/java/com/matt/forgehax/util/task/IProcess.java @@ -3,11 +3,15 @@ import com.google.common.collect.Maps; import java.util.Map; -/** Created on 8/5/2017 by fr1kin */ +/** + * Created on 8/5/2017 by fr1kin + */ public interface IProcess { + void process(DataEntry data); class DataEntry { + private final Map data = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); public T getOrDefault(String o, T defaultValue) { diff --git a/src/main/java/com/matt/forgehax/util/task/SimpleManagerContainer.java b/src/main/java/com/matt/forgehax/util/task/SimpleManagerContainer.java index 259b9e90c..bb8936636 100644 --- a/src/main/java/com/matt/forgehax/util/task/SimpleManagerContainer.java +++ b/src/main/java/com/matt/forgehax/util/task/SimpleManagerContainer.java @@ -2,34 +2,41 @@ import com.google.common.collect.Lists; import com.matt.forgehax.util.common.PriorityEnum; -import java.util.*; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Collectors; public class SimpleManagerContainer { + private final List> functions = Lists.newArrayList(); private final List> listeners = Lists.newArrayList(); - - public SimpleManagerContainer() {} - + + public SimpleManagerContainer() { + } + private Optional> get(T func) { synchronized (functions) { return functions - .stream() - .filter(member -> member.getFunction() == func) // compare references - .findFirst(); + .stream() + .filter(member -> member.getFunction() == func) // compare references + .findFirst(); } } - + private Optional> find(Predicate> predicate) { synchronized (functions) { return functions.stream().filter(predicate).findFirst(); } } - + private boolean register(T func, PriorityEnum priority, boolean once) { synchronized (functions) { - if (get(func).isPresent()) throw new IllegalArgumentException("function already registered"); + if (get(func).isPresent()) { + throw new IllegalArgumentException("function already registered"); + } synchronized (listeners) { listeners.forEach(l -> l.onRegister(func)); } @@ -38,23 +45,23 @@ private boolean register(T func, PriorityEnum priority, boolean once) { return r; } } - + public boolean register(T func, PriorityEnum priority) { return register(func, priority, false); } - + public boolean register(T func) { return register(func, PriorityEnum.DEFAULT); } - + public boolean registerTemporary(T func, PriorityEnum priority) { return register(func, priority, true); } - + public boolean registerTemporary(T func) { return registerTemporary(func, PriorityEnum.DEFAULT); } - + private void unregister(Member member) { synchronized (functions) { synchronized (listeners) { @@ -63,31 +70,31 @@ private void unregister(Member member) { functions.remove(member); } } - + public void unregister(T func) { synchronized (functions) { get(func).ifPresent(this::unregister); } } - + public boolean registerListener(Listener listener) { synchronized (listeners) { return listeners.add(listener); } } - + public boolean unregisterListener(Listener listener) { synchronized (listeners) { return listeners.remove(listener); } } - + public List functions() { synchronized (functions) { return functions.stream().map(Member::getFunction).collect(Collectors.toList()); } } - + private void setRunning(Member member, boolean state) { synchronized (listeners) { if (state) { @@ -99,45 +106,52 @@ private void setRunning(Member member, boolean state) { } } } - + public void begin(T function) { synchronized (functions) { Member member = get(function).orElse(null); - - if (member == null) return; - + + if (member == null) { + return; + } + find(Member::isRunning) - .ifPresent( - m -> { - synchronized (listeners) { - listeners.forEach(l -> l.onFunctionStopped(m.getFunction())); - } - m.setRunning(false); - }); - + .ifPresent( + m -> { + synchronized (listeners) { + listeners.forEach(l -> l.onFunctionStopped(m.getFunction())); + } + m.setRunning(false); + }); + setRunning(member, true); } } - + public void finish(T function) { synchronized (functions) { Member member = get(function).orElse(null); - - if (member == null || !member.isRunning()) return; - + + if (member == null || !member.isRunning()) { + return; + } + setRunning(member, false); - - if (member.isOnce()) unregister(member); + + if (member.isOnce()) { + unregister(member); + } } } - + protected static class Member implements Comparable { + private final E function; private final PriorityEnum priority; private final boolean once; - + private boolean running = false; - + private Member(E function, PriorityEnum priority, boolean once) { Objects.requireNonNull(function); Objects.requireNonNull(priority); @@ -145,55 +159,56 @@ private Member(E function, PriorityEnum priority, boolean once) { this.priority = priority; this.once = once; } - + public E getFunction() { return function; } - + public PriorityEnum getPriority() { return priority; } - + private boolean isOnce() { return once; } - + public boolean isRunning() { return running; } - + private void setRunning(boolean running) { this.running = running; } - + @Override public int compareTo(Member o) { return (isOnce() || o.isOnce()) - ? Boolean.compare(isOnce(), o.isOnce()) - : getPriority().compareTo(o.getPriority()); + ? Boolean.compare(isOnce(), o.isOnce()) + : getPriority().compareTo(o.getPriority()); } - + @Override public int hashCode() { return System.identityHashCode(getFunction()); } - + @Override public boolean equals(Object obj) { return this == obj - || (obj instanceof SimpleManagerContainer.Member - && this.getFunction() - == ((Member) obj).getFunction()); // compare references, don't use equals() + || (obj instanceof SimpleManagerContainer.Member + && this.getFunction() + == ((Member) obj).getFunction()); // compare references, don't use equals() } } - + public interface Listener { + void onRegister(E function); - + void onUnregister(E function); - + void onFunctionStarted(E function); - + void onFunctionStopped(E function); } } diff --git a/src/main/java/com/matt/forgehax/util/task/Task.java b/src/main/java/com/matt/forgehax/util/task/Task.java deleted file mode 100644 index 5ba92860b..000000000 --- a/src/main/java/com/matt/forgehax/util/task/Task.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.matt.forgehax.util.task; - -import static com.matt.forgehax.Helper.getLocalPlayer; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; -import com.matt.forgehax.util.common.PriorityEnum; -import java.util.function.Consumer; - -/** Created on 8/5/2017 by fr1kin */ -public class Task implements Comparable { - private final Multimap> pre = - Multimaps.newListMultimap(Maps.newHashMap(), Lists::newArrayList); - private final Multimap> post = - Multimaps.newListMultimap(Maps.newHashMap(), Lists::newArrayList); - - private boolean active = false; - private PriorityEnum priority = PriorityEnum.DEFAULT; - - public Task( - Multimap> pre, - Multimap> post) { - this.pre.putAll(pre); - this.post.putAll(post); - } - - public void start() { - active = true; - TaskManager.register(this); - } - - public void stop() { - TaskManager.unregister(this); - active = false; - } - - public boolean isActivated() { - return active; - } - - public void setPriority(PriorityEnum priority) { - this.priority = priority; - } - - public boolean hasTask(Type type) { - return !pre.get(type).isEmpty() || !post.get(type).isEmpty(); - } - - public TaskProcessing newTaskProcessing(Type type) { - return new TaskProcessing(this, type); - } - - @Override - public int compareTo(Task o) { - return priority.compareTo(o.priority); - } - - public enum Type implements IProcess { - LOOK { - @Override - public void process(DataEntry data) { - data.set("previousPitch", getLocalPlayer().rotationPitch); - data.set("previousYaw", getLocalPlayer().rotationYaw); - } - }, - ; - } - - public static class TaskProcessing { - private final Task task; - private final Type type; - - private final IProcess.DataEntry data = new IProcess.DataEntry(); - - public TaskProcessing(Task task, Type type) { - this.task = task; - this.type = type; - type.process(data); - } - - public void preProcessing() { - task.pre.get(type).forEach(consumer -> consumer.accept(data)); - } - - public void postProcessing() { - task.post.get(type).forEach(consumer -> consumer.accept(data)); - } - } -} diff --git a/src/main/java/com/matt/forgehax/util/task/TaskChain.java b/src/main/java/com/matt/forgehax/util/task/TaskChain.java index 0f1df513e..6d133caec 100644 --- a/src/main/java/com/matt/forgehax/util/task/TaskChain.java +++ b/src/main/java/com/matt/forgehax/util/task/TaskChain.java @@ -8,28 +8,29 @@ import java.util.Queue; public interface TaskChain extends Iterator { + TaskChain EMPTY = - new TaskChain() { - @Override - public TaskChain then(Object task) { - throw new UnsupportedOperationException(); - } - - @Override - public TaskChain thenLast(Object task) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean hasNext() { - return false; - } - - @Override - public Object next() { - return null; - } - }; + new TaskChain() { + @Override + public TaskChain then(Object task) { + throw new UnsupportedOperationException(); + } + + @Override + public TaskChain thenLast(Object task) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasNext() { + return false; + } + + @Override + public Object next() { + return null; + } + }; static Builder builder() { return new Builder<>(); @@ -77,6 +78,7 @@ default boolean isEmpty() { // not really needed anymore class Builder { + private final Queue queue = Queues.newArrayDeque(); public Builder then(T task) { @@ -90,7 +92,9 @@ public Builder addAll(Collection tsks) { } public Builder collect(TaskChain ts) { - while (ts.hasNext()) queue.add(ts.next()); + while (ts.hasNext()) { + queue.add(ts.next()); + } return this; } @@ -100,9 +104,11 @@ public TaskChain build() { } class DynamicTaskChain implements TaskChain { + private final List tasks = Lists.newArrayList(); - - private DynamicTaskChain() {} + + private DynamicTaskChain() { + } private DynamicTaskChain(Collection collection) { tasks.addAll(collection); diff --git a/src/main/java/com/matt/forgehax/util/task/TaskManager.java b/src/main/java/com/matt/forgehax/util/task/TaskManager.java deleted file mode 100644 index 8e3a2028f..000000000 --- a/src/main/java/com/matt/forgehax/util/task/TaskManager.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.matt.forgehax.util.task; - -import com.google.common.collect.Lists; -import java.util.List; -import java.util.Optional; -import javax.annotation.Nullable; - -/** Created on 6/15/2017 by fr1kin */ -public class TaskManager { - private static final List tasks = Lists.newCopyOnWriteArrayList(); - - public static void register(Task task) { - tasks.add(task); - } - - public static void unregister(Task task) { - tasks.remove(task); - } - - @Nullable - public static Task.TaskProcessing getTop(final Task.Type type) { - Optional t = - tasks - .stream() - .filter(Task::isActivated) - .filter(task -> task.hasTask(type)) - .sorted() - .findFirst(); - return t.isPresent() ? t.get().newTaskProcessing(type) : null; - } -} diff --git a/src/main/java/com/github/lunatrius/core/client/renderer/unique/GeometryMasks.java b/src/main/java/com/matt/forgehax/util/tesselation/GeometryMasks.java similarity index 86% rename from src/main/java/com/github/lunatrius/core/client/renderer/unique/GeometryMasks.java rename to src/main/java/com/matt/forgehax/util/tesselation/GeometryMasks.java index 0bde10be7..e13ff2211 100644 --- a/src/main/java/com/github/lunatrius/core/client/renderer/unique/GeometryMasks.java +++ b/src/main/java/com/matt/forgehax/util/tesselation/GeometryMasks.java @@ -1,4 +1,4 @@ -package com.github.lunatrius.core.client.renderer.unique; +package com.matt.forgehax.util.tesselation; /* The MIT License (MIT) @@ -25,7 +25,9 @@ of this software and associated documentation files (the "Software"), to deal */ public final class GeometryMasks { + public static final class Quad { + public static final int DOWN = 0x01; public static final int UP = 0x02; public static final int NORTH = 0x04; @@ -36,6 +38,7 @@ public static final class Quad { } public static final class Line { + public static final int DOWN_WEST = 0x11; public static final int UP_WEST = 0x12; public static final int DOWN_EAST = 0x21; @@ -49,17 +52,17 @@ public static final class Line { public static final int SOUTH_WEST = 0x18; public static final int SOUTH_EAST = 0x28; public static final int ALL = - DOWN_WEST - | UP_WEST - | DOWN_EAST - | UP_EAST - | DOWN_NORTH - | UP_NORTH - | DOWN_SOUTH - | UP_SOUTH - | NORTH_WEST - | NORTH_EAST - | SOUTH_WEST - | SOUTH_EAST; + DOWN_WEST + | UP_WEST + | DOWN_EAST + | UP_EAST + | DOWN_NORTH + | UP_NORTH + | DOWN_SOUTH + | UP_SOUTH + | NORTH_WEST + | NORTH_EAST + | SOUTH_WEST + | SOUTH_EAST; } } diff --git a/src/main/java/com/github/lunatrius/core/client/renderer/unique/GeometryTessellator.java b/src/main/java/com/matt/forgehax/util/tesselation/GeometryTessellator.java similarity index 83% rename from src/main/java/com/github/lunatrius/core/client/renderer/unique/GeometryTessellator.java rename to src/main/java/com/matt/forgehax/util/tesselation/GeometryTessellator.java index 072b9dd6e..4344fc358 100644 --- a/src/main/java/com/github/lunatrius/core/client/renderer/unique/GeometryTessellator.java +++ b/src/main/java/com/matt/forgehax/util/tesselation/GeometryTessellator.java @@ -1,4 +1,4 @@ -package com.github.lunatrius.core.client.renderer.unique; +package com.matt.forgehax.util.tesselation; /* The MIT License (MIT) @@ -31,177 +31,178 @@ of this software and associated documentation files (the "Software"), to deal import org.lwjgl.opengl.GL11; public class GeometryTessellator extends Tessellator { + private static GeometryTessellator instance = null; - + private static double deltaS = 0; private double delta = 0; - + public GeometryTessellator() { this(0x200000); } - + public GeometryTessellator(final int size) { super(size); } - + public static GeometryTessellator getInstance() { if (instance == null) { instance = new GeometryTessellator(); } - + return instance; } - + public void setTranslation(final double x, final double y, final double z) { getBuffer().setTranslation(x, y, z); } - + public void beginQuads() { begin(GL11.GL_QUADS); } - + public void beginLines() { begin(GL11.GL_LINES); } - + public void begin(final int mode) { getBuffer().begin(mode, DefaultVertexFormats.POSITION_COLOR); } - + @Override public void draw() { super.draw(); } - + public void setDelta(final double delta) { this.delta = delta; } - + public static void setStaticDelta(final double delta) { deltaS = delta; } - + public void drawCuboid(final BlockPos pos, final int sides, final int argb) { drawCuboid(pos, pos, sides, argb); } - + public void drawCuboid( - final BlockPos begin, final BlockPos end, final int sides, final int argb) { + final BlockPos begin, final BlockPos end, final int sides, final int argb) { drawCuboid(getBuffer(), begin, end, sides, argb, this.delta); } - + public static void drawCuboid( - final BufferBuilder buffer, final BlockPos pos, final int sides, final int argb) { + final BufferBuilder buffer, final BlockPos pos, final int sides, final int argb) { drawCuboid(buffer, pos, pos, sides, argb); } - + public static void drawCuboid( - final BufferBuilder buffer, - final BlockPos begin, - final BlockPos end, - final int sides, - final int argb) { + final BufferBuilder buffer, + final BlockPos begin, + final BlockPos end, + final int sides, + final int argb) { drawCuboid(buffer, begin, end, sides, argb, GeometryTessellator.deltaS); } - + private static void drawCuboid( - final BufferBuilder buffer, - final BlockPos begin, - final BlockPos end, - final int sides, - final int argb, - final double delta) { + final BufferBuilder buffer, + final BlockPos begin, + final BlockPos end, + final int sides, + final int argb, + final double delta) { if (buffer.getDrawMode() == -1 || sides == 0) { return; } - + final double x0 = begin.getX() - delta; final double y0 = begin.getY() - delta; final double z0 = begin.getZ() - delta; final double x1 = end.getX() + 1 + delta; final double y1 = end.getY() + 1 + delta; final double z1 = end.getZ() + 1 + delta; - + switch (buffer.getDrawMode()) { case GL11.GL_QUADS: drawQuads(buffer, x0, y0, z0, x1, y1, z1, sides, argb); break; - + case GL11.GL_LINES: drawLines(buffer, x0, y0, z0, x1, y1, z1, sides, argb); break; - + default: throw new IllegalStateException("Unsupported mode!"); } } - + public static void drawQuads( - final BufferBuilder buffer, - final double x0, - final double y0, - final double z0, - final double x1, - final double y1, - final double z1, - final int sides, - final int argb) { + final BufferBuilder buffer, + final double x0, + final double y0, + final double z0, + final double x1, + final double y1, + final double z1, + final int sides, + final int argb) { final int a = (argb >>> 24) & 0xFF; final int r = (argb >>> 16) & 0xFF; final int g = (argb >>> 8) & 0xFF; final int b = argb & 0xFF; - + drawQuads(buffer, x0, y0, z0, x1, y1, z1, sides, a, r, g, b); } - + public static void drawQuads( - final BufferBuilder buffer, - final double x0, - final double y0, - final double z0, - final double x1, - final double y1, - final double z1, - final int sides, - final int a, - final int r, - final int g, - final int b) { + final BufferBuilder buffer, + final double x0, + final double y0, + final double z0, + final double x1, + final double y1, + final double z1, + final int sides, + final int a, + final int r, + final int g, + final int b) { if ((sides & GeometryMasks.Quad.DOWN) != 0) { buffer.pos(x1, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x1, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x0, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x0, y0, z0).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Quad.UP) != 0) { buffer.pos(x1, y1, z0).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z0).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z1).color(r, g, b, a).endVertex(); buffer.pos(x1, y1, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Quad.NORTH) != 0) { buffer.pos(x1, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x0, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z0).color(r, g, b, a).endVertex(); buffer.pos(x1, y1, z0).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Quad.SOUTH) != 0) { buffer.pos(x0, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x1, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x1, y1, z1).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Quad.WEST) != 0) { buffer.pos(x0, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x0, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z1).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z0).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Quad.EAST) != 0) { buffer.pos(x1, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x1, y0, z0).color(r, g, b, a).endVertex(); @@ -209,93 +210,93 @@ public static void drawQuads( buffer.pos(x1, y1, z1).color(r, g, b, a).endVertex(); } } - + public static void drawLines( - final BufferBuilder buffer, - final double x0, - final double y0, - final double z0, - final double x1, - final double y1, - final double z1, - final int sides, - final int argb) { + final BufferBuilder buffer, + final double x0, + final double y0, + final double z0, + final double x1, + final double y1, + final double z1, + final int sides, + final int argb) { final int a = (argb >>> 24) & 0xFF; final int r = (argb >>> 16) & 0xFF; final int g = (argb >>> 8) & 0xFF; final int b = argb & 0xFF; - + drawLines(buffer, x0, y0, z0, x1, y1, z1, sides, a, r, g, b); } - + public static void drawLines( - final BufferBuilder buffer, - final double x0, - final double y0, - final double z0, - final double x1, - final double y1, - final double z1, - final int sides, - final int a, - final int r, - final int g, - final int b) { + final BufferBuilder buffer, + final double x0, + final double y0, + final double z0, + final double x1, + final double y1, + final double z1, + final int sides, + final int a, + final int r, + final int g, + final int b) { if ((sides & GeometryMasks.Line.DOWN_WEST) != 0) { buffer.pos(x0, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x0, y0, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.UP_WEST) != 0) { buffer.pos(x0, y1, z0).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.DOWN_EAST) != 0) { buffer.pos(x1, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x1, y0, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.UP_EAST) != 0) { buffer.pos(x1, y1, z0).color(r, g, b, a).endVertex(); buffer.pos(x1, y1, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.DOWN_NORTH) != 0) { buffer.pos(x0, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x1, y0, z0).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.UP_NORTH) != 0) { buffer.pos(x0, y1, z0).color(r, g, b, a).endVertex(); buffer.pos(x1, y1, z0).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.DOWN_SOUTH) != 0) { buffer.pos(x0, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x1, y0, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.UP_SOUTH) != 0) { buffer.pos(x0, y1, z1).color(r, g, b, a).endVertex(); buffer.pos(x1, y1, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.NORTH_WEST) != 0) { buffer.pos(x0, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z0).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.NORTH_EAST) != 0) { buffer.pos(x1, y0, z0).color(r, g, b, a).endVertex(); buffer.pos(x1, y1, z0).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.SOUTH_WEST) != 0) { buffer.pos(x0, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x0, y1, z1).color(r, g, b, a).endVertex(); } - + if ((sides & GeometryMasks.Line.SOUTH_EAST) != 0) { buffer.pos(x1, y0, z1).color(r, g, b, a).endVertex(); buffer.pos(x1, y1, z1).color(r, g, b, a).endVertex(); diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverter.java b/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverter.java index 39baee5e3..53f0577a0 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverter.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverter.java @@ -5,14 +5,17 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public abstract class TypeConverter { + public abstract String label(); - + public abstract Class type(); - + public abstract E parse(String value); - + public E parse(String value, @Nullable E defaultTo) { try { return parse(value); @@ -20,9 +23,9 @@ public E parse(String value, @Nullable E defaultTo) { return defaultTo; } } - + public abstract String toString(E value); - + public String toString(E value, @Nonnull String defaultTo) { try { return toString(value); @@ -30,30 +33,30 @@ public String toString(E value, @Nonnull String defaultTo) { return defaultTo; } } - + @Nullable public E parseSafe(String value) { return parse(value, null); } - + @Nonnull public String toStringSafe(E value) { return toString(value, String.valueOf((Object) null)); } - + public boolean isType(Class clazz) { return Objects.equals(type(), clazz); } - + public boolean isAssignableFrom(Class clazz) { return isType(clazz) || (type() != null && clazz != null && type().isAssignableFrom(clazz)); } - + @Nullable public Comparator comparator() { return null; } - + @Override public boolean equals(Object obj) { return obj instanceof TypeConverter && Objects.equals(label(), ((TypeConverter) obj).label()); diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverterRegistry.java b/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverterRegistry.java index fd4e7d489..8c111a199 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverterRegistry.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverterRegistry.java @@ -7,8 +7,11 @@ import java.util.Objects; import javax.annotation.Nullable; -/** Created on 6/3/2017 by fr1kin */ +/** + * Created on 6/3/2017 by fr1kin + */ public class TypeConverterRegistry { + private static final Map, TypeConverter> REGISTRY = Maps.newHashMap(); public static void registerAll(final TypeConverter converter, Class... types) { @@ -23,17 +26,22 @@ public static void register(TypeConverter converter) { public static void unregister(final TypeConverter converter) { REGISTRY.forEach( - (k, v) -> { - if (v.equals(converter)) REGISTRY.remove(k); - }); + (k, v) -> { + if (v.equals(converter)) { + REGISTRY.remove(k); + } + }); } @SuppressWarnings("unchecked") @Nullable public static TypeConverter get(Class type) { try { - for (TypeConverter converter : REGISTRY.values()) - if (converter.isType(type)) return (TypeConverter) converter; + for (TypeConverter converter : REGISTRY.values()) { + if (converter.isType(type)) { + return (TypeConverter) converter; + } + } } catch (Throwable t) { } return null; @@ -43,19 +51,19 @@ public static TypeConverter get(Class type) { @Nullable public static TypeConverter getByName(String className) { return REGISTRY - .entrySet() - .stream() - .filter(entry -> Objects.equals(className, entry.getKey().getName())) - .findFirst() - .map( - entry -> { - try { - return (TypeConverter) entry.getValue(); - } catch (Throwable t) { - return null; - } - }) - .orElse(null); + .entrySet() + .stream() + .filter(entry -> Objects.equals(className, entry.getKey().getName())) + .findFirst() + .map( + entry -> { + try { + return (TypeConverter) entry.getValue(); + } catch (Throwable t) { + return null; + } + }) + .orElse(null); } static { diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverters.java b/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverters.java index 285de21bf..3bb6bee82 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverters.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/TypeConverters.java @@ -1,9 +1,20 @@ package com.matt.forgehax.util.typeconverter; -import com.matt.forgehax.util.typeconverter.types.*; +import com.matt.forgehax.util.typeconverter.types.BooleanType; +import com.matt.forgehax.util.typeconverter.types.ByteType; +import com.matt.forgehax.util.typeconverter.types.CharacterType; +import com.matt.forgehax.util.typeconverter.types.DoubleType; +import com.matt.forgehax.util.typeconverter.types.FloatType; +import com.matt.forgehax.util.typeconverter.types.IntegerType; +import com.matt.forgehax.util.typeconverter.types.LongType; +import com.matt.forgehax.util.typeconverter.types.ShortType; +import com.matt.forgehax.util.typeconverter.types.StringType; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public interface TypeConverters { + TypeConverter BOOLEAN = new BooleanType(); TypeConverter BYTE = new ByteType(); TypeConverter CHARACTER = new CharacterType(); diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/BooleanType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/BooleanType.java index ad92e0eb8..e5c0f42a1 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/BooleanType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/BooleanType.java @@ -5,8 +5,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class BooleanType extends TypeConverter { + @Override public String label() { return "bool"; diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/ByteType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/ByteType.java index f7b5c5933..68bd7cc4b 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/ByteType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/ByteType.java @@ -5,8 +5,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class ByteType extends TypeConverter { + @Override public String label() { return "byte"; diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/CharacterType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/CharacterType.java index ef0d1cb36..ff52aeaff 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/CharacterType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/CharacterType.java @@ -5,8 +5,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class CharacterType extends TypeConverter { + @Override public String label() { return "char"; diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/DoubleType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/DoubleType.java index 33bea8c71..14a4970bd 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/DoubleType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/DoubleType.java @@ -5,8 +5,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class DoubleType extends TypeConverter { + @Override public String label() { return "double"; diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/FloatType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/FloatType.java index 987f0b79c..153ecd6c5 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/FloatType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/FloatType.java @@ -5,8 +5,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class FloatType extends TypeConverter { + @Override public String label() { return "float"; diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/IntegerType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/IntegerType.java index 08a2eb605..cefe6a356 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/IntegerType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/IntegerType.java @@ -5,8 +5,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class IntegerType extends TypeConverter { + @Override public String label() { return "int"; diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/LongType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/LongType.java index a6fe0c51b..e011aec3b 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/LongType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/LongType.java @@ -5,8 +5,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class LongType extends TypeConverter { + @Override public String label() { return "long"; diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/ShortType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/ShortType.java index 743e8b0fe..84629d9e6 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/ShortType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/ShortType.java @@ -5,8 +5,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class ShortType extends TypeConverter { + @Override public String label() { return "short"; diff --git a/src/main/java/com/matt/forgehax/util/typeconverter/types/StringType.java b/src/main/java/com/matt/forgehax/util/typeconverter/types/StringType.java index 2e16891e0..46500e9e4 100644 --- a/src/main/java/com/matt/forgehax/util/typeconverter/types/StringType.java +++ b/src/main/java/com/matt/forgehax/util/typeconverter/types/StringType.java @@ -4,8 +4,11 @@ import java.util.Comparator; import javax.annotation.Nullable; -/** Created on 3/23/2017 by fr1kin */ +/** + * Created on 3/23/2017 by fr1kin + */ public class StringType extends TypeConverter { + @Override public String label() { return "string"; diff --git a/src/main/resources/assets/minecraft/textures/forgehax/waifu1.png b/src/main/resources/assets/minecraft/textures/forgehax/waifu1.png deleted file mode 100644 index 592a30792396b69b31cee799f03a67bc354383fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1303255 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�`IK3OXiYoUGt={`I~cK7+}^n~z&H|e|U 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Œp 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⋘Ol|Ef+zUI?!J+v6Q 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
*Puj|U&?<%ZEdhWS% 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�J-<+XDq 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

7_T25w!3v1f% zIhLjTM35&C06xQ5Zew?Q3rQ4u@WPNi>Af(tzoCwcmO zr8PO1%V}F z7Uymv&`PvJ`I1CEcch{XsxX%N0tT9-Rnr0QE?4w9y zEoF9-`atF&wIaN~Z{W?FHaZdGp65uj2m+8Xfw;(!P+G(~(MG4-SkCBuRokQ!%-HMt z&$#v2F6qTL_gX-~w(vW39N@~;RUGUOMBB{82g9vt8g~v-?CkXgbup<`jEfAN{C4*Lz;4=}ZzQFbz{+<+a)}yn1Z}D^^TDwd)0J zM+qp!ugPdpGOoPzL0#Blf9@#2_dfd3F9y;+QH zS(@MV-{YBLxN*n4Sy`QxuBxu8uC5;F_JoCG^MYj|frJ1*&^L_fZrmZWBHd?& zPV9LN-UL2qZgAs#;Tj=5Ikmj2+?KQTs~x|4HBp2W{h>G>E#_W zo&})p_&n>K%XZ%w#vP`Nj~qok%QANwWmT!)`O53k(b%og?3I2kFf+CmeivXIINw4` zC_u!AjSE?9`u$dJ*1o_li%AAs1Pq7ecjulpXwtQeSvD4OLC6vk?%ZiccJ~;b({~qH zzmFqLtSB3rucnp#?%X;)HOj#p z#KOY2?}A_W{F+l8V_&p`Tq{n@mri|7YoqsR#CS1e!I)>Y`8kP`)Eu^sk7lQRy1w@z zfWXs@oDV^R)>T|XU=4wbLEsBtXrh;I-1;X$8GfXVw&W!EZ2TYxczJ%}Fr3rveqKec-V;=s9c+AH;QKmT!k`lmml zs+@i8Vl_Vht*?Ih`+wo>yGOeHQ=ig2t5jky+d5tZi!lTgL{@kYcgQFRl}B=oAZ`&7 zHfQcn4~|r4nULg@%2rdsGcmA_JSO^rK>e)^#r>YLEK@d}Tbs$t=SLp4ott;;(7r_t z8AoAPcDBq6#NMeI?LFAD*zM#`T|8lFQi9eA810LqK>Lq&EfT>92E<@s;asua-GB5@ zSykxTt(Qa?QcQL7+2YvzgtF+{Rm6<@FDg-YOHTj)M7D&4LqozOTWz0sq@(*H&sP)q z@}+qPFc_AK!$gO(43FH}>^E98vF25-riAN&UyscEE4=Ymu5Z3wDUV~bM=$G4HU2hQ zQx1o(x-sC(r997^@b@nJk#WcP;b?QZManrRs^3emT+?*E(0qo!h1mSbFz1WB(mOxi z(`1Z_c4LlTqqMI$9vH)tcGDxwasTtMc#%vApQn}AC7Aq}f=~<^V=ft$8Nz5PG}^jm zOgI}M$3v%9oJw)hGAO&5AD_FIf!8`+J_sDICBACS(itK=a0tyNOcW%EuvB|+ARW#t z^BVze)-^Yo$*F--8I}7f7y?IZk~1Y_4gWVT-&Yu$6H65U9$*V*IEri zlUcO>W==cr7IhiUR~Z(|b8_1aQ*oj0v|>Q5WV84fAkw_^!q_Xf~GR2 z1Z@GKaLCz`n5j(VF)%gG@!p>9-g#H~e5QUFo7Mn+7WmGH^w!IHuje%B;Iy-`^?Rv` zVy-YM^tqpXRiFO!ZN*`wx@i9C^TM!cn(#}%{hd!w~|{g6*CE$ zmmYKoWkbeV-wi~&z-<}C?QAkOXJ6(>(5npMybEtlT(^D_K%LTlPs6QEBVK3IsWi_` z!@(1VzKxUxa|C1vZ3vLUAdYn9`Zd#jFb#<5Oh@~K{UnrKE#QwijsKAs`A{zyMw9&m zVL!jQwXG(==DN}%n``gjz|2ZEHa8VTsX39%=b3q^#~Eoits*S`8ReYz^Ut64$e0K* z<7j!l}&T0+IcJ|4}@atgR&Z+79)r!lJFU0(L zzspfeSBq}Hck9LYCS_%zqG}W-fpWqu@8{axhgqH|Ofc^#OoL8A&lnS>a-&tr7iO9h z`ntUA-Wj~9Zauo^-8y|(&S^P+Bx_5{kbo({UZdP;6l8Uw9!%uJBYp3yUsr=qiLeln za4dQg42pI?VU2Ol7N5L69&1{_HfS|0JicK20U@1nM2wbZ0OJ%cfp^t-K`6I-1q3U# zWY0{Kp30n%$kYIhipWKVvULKc6iz4cr*!`BtQvITde%G7dmosv9{Zmf;N$8`o2*@6 zKw;#3YCKlp~qzpZRyX zN5-j{bhK*#<>qCrAnxhz{oU@X>+=s01fINde25yeuId^BYY1En0{_e3Ir^{Tu=gt_ zfiQImLM}Sw!Xqef!r9auQ^H9$#)n6G_~3ySlbL$xf`ildbFr|y8gvmmn@ajPCk&Mrl@9jyRY#$&-n^kO!R@tFEpj8^gE%zL^H#AB;Ge7OQZ1A= zlOj{6Eli37d_acLq99qH+1c6uOw!d#)NquB1I+n6)5G0eZ4N=&=uf0^r3xI1mx)p=lMk?ocz1KDoqFvo66Va_~@l*Ez`#L?dtLDnt!lQs5i(Z zM}N*3@ArFp>80zsb8lB_QX?+nIMVoNp~IuOiYhRzscAOVaI|SiAQH?7mmDi0fN9YO zp)JvcoP~?4Yt5$qM)Of+I+n-9P-s zceMZB9re>lbGb0nW*gY5Tw3%6cF0ys@FMl{Yeo|~$Gk*T@!AbVnH%H72?ktWdB>QZ zp>kdsX3Ag;57%FqAB16I%vknm_93qgY3805F4^r(c70yvKe1=7erFZ$;bYHR0g8LK zs~Pz?>DL|Oj0gO0cw7$ngX6fV@4h`z&RLatp8K{wKR)-mS<)f|Vt)L(kl1MC_I0>F zv6Ha6p|CvM|+cI;05 zFEwq6Ot)UTu3z}Y&uTP`2|@T<+uPfF&)AF;pMCL*-;8d3dT;t(F1p zLAnmnew^$ag!|-1&nCx)yvPXCS(`+WdnE6v8^!_%4Vn%-13shCNI?>5k!8xWOe&nT z!GFv5-OZnC%4yOdVtaer z>}HWP(YND$r!BF$jbDIJC3#O5#smN^h5)umx*6=E<{7|7@x~obJ{nNY`3K|XtRLlr z+z=}rn_TZ-f@2qEK6|H*dy-*+*$2#-5Xl$Fa1^S@N{x>WH0(tRtI7z`Sy3ntTnN&9 zCPh_WVXx8s@ut4>y@l@H&D2YV>S2dYXjc5CG>)-k<#)%8uh56!=;6qbHgPm{cat>L zHm+X2eM|d$hvwW8=_G{7{d5ZpvJ3&qn#dZ7 zw)x?t(eA-i^DF?D=SrHXZ`GEx^fP4V08(B z;mn+^+dTYKWzQq|>y@k?yR^L9Hj$?}Hnz~2k!eiCFvwR6U%h@T*X0fJ=kJ40C(Asq z4#3gU3ef!hZvXpsu-7_)Qwwh&e%ilq3NF)m^nsls*dSRO5HhuXJ-|;fNn9DuA6UKC z1w9`G;^+H({q-6GYY2RpAn+Ie#@-)l8vRxF(mHC?LmJ#_^s@y8N>GkhW1g^G=)lon zsLB4m-uuy;%BM4pdM>&K1P*HPm12b&sYX3IDilT_E|rGEkrZGy5ThBPS6vw+GpbycKeCMIJe^Clh;p_mX5 zI;=(&xHPAb^kqTwH@q4bRj&p4^Lroq|b+k9LnC+;_dgqYl+%Jw4g|YIY zP!uMbAKcY^G11P|TWb27LK7mW7CL%(*YpGiH(yc^^^}B>X4y`UBdu0g$v~KYA(bQH4)U62oQC@%2?NWGllsr6=ANVDikHH z?X{K9xvz+m9wUL{Ru_5q=f=xDe&2t0@(45Z-1LOU=YIPF9-<9o$xA0!F!|2(KeaR? zZrX278~vw#^b|K8!yz%AL0Pemv>)RDxR!c2yTq?V0)scz-jQ@?H_$=eQ#6{Z&gna+ zIfo-=q9z$JT{=cxb*x3id+5gb0$e#nKtfVXVyF#^cUSCf!CJjHduYW~Z-Ib*JZ3nXbz^So3Phw7(^YT5|s43#-!4YIlYg!T6< zhIQL7t4d|YL_1l<_G-D1bo-!O2uhvW|s<_hKBzhJdI?G@OIdPv%!tTVKqvj zO;KA!ttRMeZ&vEh{W)vw`IE#Kus&WI2%JCbE=@Jp6= z8okw&2!|$7xq3a(&;8=Zbo=(U7THW;n2y6R{_mf+P5%4g&;I-kqKGVt!u&sgAW=t> zCnQX&;5WAxVRDigc0}jwvlqoipe<%|MW##<7~_KXKukH}`5);V8WSMS8(W(ei6iOv zR4g);cwIxIg0O_Gl$tu2&2Gz>;6C|)*zN3WtKY-Nfm2D`fAr{>Ux`{?bS!;eY)nb-uw7I2Cd`pD*Styhj^wAQL^KkJnJnhK1@IQl< zdHG)6JMEj*d&i87w(Xv{pkAge!3`w(te+aWClM~}=qXT6*NN1_}EK`&&Bd^gv9yz|q7&;eDesHZE8KwNJtaiZI zxUhA}5tZb-SP=S=xeFnL6UUMIL!+Q#~TGs9oeFsI>)o;*6oakcW|}v3~NSrRV(&4(}s8&~l(|<^T~hFSH$uNr>qc1T~S65-AyI_psK(gIXC(P^=6K z_bt&K=rhlBVBccxh1J+i-6_qQ#n1P(Kk`23t3SKnhSBamLwoIcetyk8>-faH>6`Xv zeg{}9`L%y#fe#~0>d=gEOkt*yt&@`Np@X!ix4-{G-GBFv`B9oICbo}+PGPDGLU;ZY zCowi?B63R`(%d3;I3E+{yJGcv zHM@&mx9gc73;r|O$?r+Y_xBUuGd9EH`I+Y92{R6Ia=MT{Ps&)G_x_oi|FzSK^*7ri zj0lg*aO)!N;XMzF$NH|*zpH$nA6)C3U&A-HX;_XE3-cWSF^6>X>b0SM_H!T6M?X4JoK$t1=wnx| zY;13BZM`t>MBBqF|4~+8UeQwlB8##@D=q47h#;iY8-xy4gA03zJ!NK$7q)nOOB{|5 zRW^8~261zy9WZ3f^a7;a)LDuAA@vBuiI?xD)co*J^>kt3RMD!-FH?r{ns@u$9n+s>?t@4U$UFhpHJQy}shQud+_`y}Lbq=RFB! ziZqDL1f{5I^C7}FMjtn5nRo%r`?r0rw(VrgU)&Ya<0$ND``VTc4i-w%fgU|vXfZF9 zgaZ|IuJLrHL4V^I!AD99VtOV*_!QN1sPajZAr_&q4(+#^6>#Yy?Jy=FY0QaiP-~IT z)!(?{d<0a*v1%{*L_wo80g-Lzz~lJ*YH?>?KdJ2>RR5h>!3#d<)|1if2ogWOFPI6h zb%=|n`0B~8wrdBPV}u%lF=6|Ut;?0sl7vq_$^z{kHrk!$Dw^CpdNxIB{ASunBD6B! zT5263`u00*h-JGy9FCv2cI@2u_g0VO``A60t>^t*ZO;6EOpJA+-*oSt`JsQ%?j1ff z?(w&#H;2|35_9HXWQ-fM&zdM!L6oh!Q9p?^-P_l9zw%WrCKJOI%1Czf+Dzyl((V(f zW$c`|cj^WB1WYjM;Lh2f364}3nT;#%6TX>rOxOqDA1h^^n!gKk$-d3Hk@kA#dj?0S z;3rQ^D-6?PE`597*T)~v%8&J;yJqrkpZS?r^ogIor6!nak?C)|eDm5{&)k@m5C79Y{TrYA*M8r> z{;P|k`8RU2AVoWX9ko(`_CxD0fX_VgWRAvKqMWD@Y;zDcwuhI6(3YsO9M_)~_W_0g zyDuuCj)f>INEI*%Zi{c`BbR)I)(Wij`Z00B1jIC=}WUY^)tZ9iJ3eukRQF z0Zhk76YcLFD5x5hO{uWL#AGSCKuZGEM;IgH{X=7%3`ZNzUqoFipUgBn94qeim2PcV zzh#)EEEc8}Lj4UEEiws0V@OT4ltOpm^d!4$bQ{h~6}}%@b$nxZnO}`sQR;>w<|!ue zHVL^yG=2FX^rpVrYEt-etpB>m5txaYsGxy@>Z*&(@$S2K^xDgxR$XSwqDTo$DTQXP z6IO-6tSKsUh`E_I%I2ZI`29?2Q0bRm?Q2oxikhBqm{!1KGW5M^5j>~e(nSb;{hsFN z5US%v&cNaPnf&Cs0*@ClcDs4h z6=48f*|9BMjWIJ}2wUn!+MCq6e^_fT3zSE(>ZVYXqk$EgQ((plTY@nzA%JQa@Qz7Q zcB1aA($>Huf(hL+;RtKYSR>4&Z>t{zt}@HfwA2#w6>aOgdhm@~z29DUwKz_Fs=39J2rumAW>1fwb1cw+@8l;&9d50LcRX_>pHx5U;QN3Jevup)_mU()dE%h z*3XCI+;ZvK%*f`eFOjuzg|q=O1H<`>J(TE>E7#$&6|RuGL&WB9b0wi=y`TLdI%FQPT$$G!`q<66hIPAjIDXvp)st4c zlKKFT66Tge`i$xJa9+GB>6@#ct*d;RVhsS%4Q4QefK@>J$z`$SZXE?`LPKHv^vO3-QW5jNern$ zOJJU7ic^qNh>^;O5RW|i&EAlzR`P|<1vDXI^9bJP@L*pD2YUt!q&95MFedm0DX}pr zO#0>|#_9Hsg3vK^it$v_$yf;?9>PFbP$_J~Z5a{7rjO*tYb-R4ZoG6u>7Z}KAwDA> zJbb9KHIt!U+X^<+6V`sLKmpXd1tHbG$u6^WXDe7r9 zn`ttgsF*LzW|aPCvtLE1JRz{j-eSd%T_$0&=M8TwRAiBo+aWGAwGUhYQ7IVk+ zGQtSr(h>a2a#j$(%{I?*|TR(nRKlA%C3lW(?m;x&_AVjFh zQpupFX+{W+nHGywy+N(LX{guVOm+RLbbBY3DkO@vb39+xV75w}$lW229??5ducyE8 zW5U|=f(X2e)&j=Fa5U1xdzto*X4>7IXgViiPNKcThbnS3bb87QCylNv)V?EyajvFv zQaJB)3@K_iJ<$f<8%}pV^7E82h?av_8|FTUGUEwEbY5f{Pbca#uA)SBIa5&;8g1RM z{-Up&1U4Q767w}OLd%fp5N01L<0tFesm6s*yM1@zk1orLEmLB(I-Z_@Sok25?|WaS zC+wW$7j3bi_1Oc%H`Ju4^zfk4qp?(A>J|rT@<=FH;2#LO(X+-Fnic}GWemfcW-TQ7 za&3&Y#IdhK_j&i;S?8;3=~?f6(D!{Coz&lzZu6;x0bHp92S9@gMKXL5gpKb0@ca7a z>;F>2IxuEEnk$ncS6sr#EmTLfP)vj4YH zwV0rSABBP84>7_R82n7AXH*+09y$ZC6S^S=c~15li6SX!8hOg z_dou#FTWc&$55*^SYKa42&@?sm#|aTRa!&fML^*5Uue?X_4sRzf|pqP*_YsklR!e) z2-yT!+=&E1>h}h!2)B6mo{k1^QY`sY0nrFaS*8APt6;5 zn$-H#XFj6OeD3)gTjF-;9d;s}vYHe(8i3lY4 z)*t~N;LdZ#8>-dRk)uc0x@Da}RIo#@8%4d;2p1fvUAvlUvB(u>V{L72X?NyA!-1Ow zn9$Ur2K_`h+0<-oOp`*fHU_EobLmUpFZIWMJ`su?NTr;fNk{5v<{%bG^tf8j!=qSj zW4C?B1-uU@X0;XKB(jg8x$fLO)I2MMq&i6=dBy}C>Kx%h z`aetZj4$6_4+q8p=kym6FrIS_A!T#0EVamUiw@MMbIj~ys=<{FZC!uK{N|)#sv>G! zcu=Nf6sX@zEPOAj#;bGjS?cenMv=;u`?zs-whgkHWEP&0KFMCSf8SZ3a``F_vvl=oZL2-MJ3U0iPS& z#^P$tfOy48bC;TC?2n!);X_251BXt2FZ^_6KUvKm%{!l5-@wpuvkrI@h0D>X&XHnJ zls3QE4;SN^e(=q2sjonr!+~iq48xxC5(mndF!q$Uj11p*{z#cX4K2g-5`=42M=pkM z5Q|X7yssHR_Fq>i7BzaJ(Evrq%f* zJ)v%UPUP!rva;x}zTe?7oc8%+_l!~2`H1z7JYlA?$N4qOGeFR8J@&^$N46Rqn5p0o zjJ*(Mh2b8a;SC|*uGbdSf;L!mvA}R0LW@%-_ziimN5jDF_xtuU?ZmK9QTNpJ@lP~R z91m5%muqYvWfq*@|GaFGQR+}t6e{fx6c2`~%SOErfz$GPKac$p;6;po#z4e= z1@k3Tn)H<>iOOnAMOOU&Ds0|9Je>cBlD_a5z}Gh}B?Q)tiA&in>q@O5@SG6%!WW`j z>CyiiM#(41iH(K@oj=ZFHZYD}wOuk5O*r)Ul-PUt$f77f#2H6|81U^o71pR|M&hl! zfty|{P67>*ff4;toav(<+tFt}cT*d~;NQJWQ6_IO{Q zVF5!T><`STqVm$rD0s618J1&6AVo058t03s7`CP*AYgDYZrr?PND?L``}_NvO{dNW z1xySi!{+0lu?QU%5jv7kNPG?-?F(6cZ)?*KmawcfJv_3u?_9lR3=Je4FqsO%W)Z%v zl{6b7V^WDWG;G^EFFmC8K6QmG{@&9ZQ7=W30Yi&K7*i6?%@*T@X{*pqQrIF@^b3E^>qdVFdUDt!GaB9Jfd5|zvdnJAJTCLq8 zRu(kM%Ss!B#|s<%_)ejJxmD|zUkwd8W2i$AgAl@OF<<6OF!^dd_0h)UQ-Ag1K0rcN z3-9U!i%{|X@4sdKRxpFg%c%~I_S75fsA(eeQPPBk>ITGBrc#gdF_${P=pyTFpPp4? z+TZO<-t+y>(VLp^4%aXUS&xb=*K|5HJ9B&ogiWnQF*og@C>m%!MRv|7i`D|Wj2p1)pw@3LP%4^zUo&G(hRe%7OhAp}3??$60! zr-d|`qbUKCf-s?|aF;eFZ9NGiQ|tD1fz1gM9)A>N+xv|E`V()-;My4Q)oiXGedl*{|3^R8AWbyQ zrV7f^qFF>iWX#Jdg&|xUlgLaJPMhniQ9)KJV9uB^<3PJ9YAgy8euoOoDPc%9fudGz z$48Lz%pb?RT*+|d6732ijNu=F^&73q633Tj=E-KfBz#vsz1ZdIfLZy9v3t?v%{_cn z4#p>NvD9jwG#y40^8qY_@0=FNQri&I3)d%g>nPjh;{*+kUBp=B9UHqS$jO;JnE(U4 zBXmyA(cDBk$+T+>hbhem7N&IIRwmqF9F&CpW_>2FRzu@S@U8JD#Ke&?BdD1%WAN)` zY^`Pg__+l<{J3Vlvh^Q~E3BPR!*~@A@UwZY@p!7+^|e2}W=vdkB>v>zTQeqp@_n$b z!5RWD7y?c3>*?%Qnof@pjuqxb!jpTy7jKKj(WZ~yfHH@u({ZU`^ zQ4&QOA025i&sC$nf-^A6j3A;hLx4f#)X_n%rt^tLX5tGhq#%zKKm1hejNzWuirft#G+P(jtqTlmb(_8@# zFmM>?I6GY|dfMsd8gHeV?uSa^OnE(5TE!alrPqJh=rcFw8V>p*I)EWhrVwgdxI6Z@8%ier|->4&$B*qaooK z9c06pe38kmCCfZluU}+YFETGr2o@MIsyzTe>ZG@Ap#{^ypO}(5c zJYCetQ4|B#V!Uz(YgRA3rwG>Rt@Pv_~L6D@%VA3~@dT}fx@=eob^{eGI1oktf3veX5 zdj)l3Pa*jc!*kz0r{n2r!hQ)JK@qIq9i`A?fb$N_3fo)B$Jk~7Z8_du`M$KrTS=Yx zSv}0@WgE$ebId+kM^HqR001BWNkl9J4 z9&h3^U(U&Mv`E}Do*(A{z7d9+&8C`+XP9>V@=DR`%S#LaH^VP+1=m$uLtqVor-Q&> z_&@i4e;Ddd;@EG9Dr#0JsT%d;#2j0i?}b*SzhJ>vprj5pf4HyRx8D_Zeh|#_I#-0# zsWP`sfmq<4YmNjmYDxu7Ur{qu)S%86>DrCHKKZHZy7khQvibbKeY%>T|Mt;j{wMz7 z-~amEdq13i?X{2pye7iNolvC-K}(gvgopxj(1~+J+(arQv?fT7X%?ETq$%ryq?z4n zt14L)nop*1C~U(;BFiS1H<>D|Lx@cmx|rUE2PcW5YdeaYQoYzQbU*}9b+0n)E|EkN zpbm2h=Zq>1aSlqTtH8_{uHL+%WRx1B7%SH9I}a5EwZb$uWU4|7z#@AfO(3i*+8c%D z4-XU+jnbPp%nmb-L+$N7(s(}8_Vue8ZfvGq# zn}e$s5wxD5-bT#1qnSapYQW$P4tD^tIqm2A(jkG70z#qUU^5CuSk<~H)y#AAmtm$J zZ9VwP>e3>g9yvPe2!uh>AX0I<3h``gw5Cwfi}c>zTsMXX8U%eUlxYz56y-hDabImZXpc0JZB+wdz=@pVaf)nK5e$@TZXJJLZDn^pnLxDe(BrVM!XkLGQZS)8>wn|J3d zlx@}h3|ZB@kyMoKb|IhlNxRY)+Uh*s{q^!^*H`!<-#5+%g9YG47l@Z5cnB9HY>UEF{%V zN(X`ooT{o&O1R>x(D>j${Rn-pxiaLeb)wn)p5m?R#H-P;m}$X!S2ilm2TP)j-rN{{ zXh|iZGZ|to+Rwn}k#wi#&n-XZPlx?UqJ=tk)9Ur=vnThxlh!})dl1Snll{+$xEqCN z4w#zw^2mJZ{$M%=A@qVk(Na$y8rNY{8&jQ}Tv=mc3 zi0yOas;Kujp=r0_7pNf$6k|Eh6qyNQE=7!VzZ;%@#OUGtKflti93k8x&LNi1_|Yc6 zuK_;~LksK5E{5NQc7Aqq2XC=!_Vf@YPG#Di#;gEngfR#I0AIjAR(I!U{WhQ#h?#_q z57t0qjJWlVPPWkG2&`}ziX-%#djlKuML7eIPHRw@jDSHBL4_WVR8?#SSk!`Dx&(Ad z^mX^g9Kx4{F%<0BuJ!D7wq~>$tQ?Nv#>mDJ2muJHjFcNL3?E1b*Gv#Ho@5Gwavhyx z1%{XT()HwJuHm|FYY40%aA631{_{=T>-WCEHUMIXKZHTQZ)O*HQJ8ND5PgzuMuY{8 zV;vqH=)uDW7P$c_KT>&~vj+xoWCZQ3nAv9rRy)htfZf)AO^b;`mQb3rjxY6xw+c6rIWhg z46DcqJ$N!jNK{~WwBjJ_D5E6S=Ju9J{qZ3|C{CV(fRHB%^#Hg)N54jpGWvk~5dCN` zIP(%*P$as#vtzKQKMo!pn4>9#(rnWFEH7+K&B>_CcQT!7I-9D$G1SJ^rrFICL1cb3 zF`{j_xn;-*WkURSk${sed&a9%5YVT}$uve{)0Xg?&soxxi{uMRbXEfPlgUJNftqq< z_Omc9K$6UfX;~{@#7fdi*RF+%BOInWIZrl6<7TMIgSo!^#!QP4+vKS#B^IJEz%-^D zTG77GT?mo0YIAw-qmEnFjW$M`x_<4d_7ChH}^?9+c`{~eFdpFj)G zp)K0lgo;9Z>bNn6`aVQI^AqhGlCiIR}<%ZfHt!R zn~xy~(l)Y@U&kq&HS$U6Nw70!zyO*@s)%lbWoBLL ztv9}>2k*SA0LQVd)ST~^uyA|PDaAa~Ek7Tz3Nt35g@kq563>)j=OY^zO{6$VoyjF^ z26J@H++U8F&L0dwVXr?ypT){^V3=8lT7$)GBr=_Q9 zlhdO-EtjXeXKbYw_i|sh434rfyb8^d29D=CeJCLClb@L%3NWoJxrV@p00K=Dy!?wt z|7#kB9|egp1_TJbNh47ITT1vq03itRm4NxfqX!RlcyMrxd^iNrA#@Nf#u%PRfJ6= z+6OQt+Wp2KeOGyri@%1jY8f&f;WEUsZZsQDlxJ|(U0%i*F!;F8h(?~w} z)wNTdN3LV3X*4^SXr5)-+}zTr-?u)Vj3>&*Q*8`K+SuAsnT94sDHroj%YSmG-Z49) z4`B-7<_c75eY?)78vSwJ&#CCUKJ$GF(gZSQ44)$xktB_s14W#^qH~OjFnv^H^lzoX zpw_J$gt@JiVZIdgRMbe>Mtb+*NZ)>^Qj_ApqET)UDnnsGz}R!Y)-T2h1l~1_dR^A! z#%pMf1z}L$ynRy-9^5lR?*79E3e$mN%wyWI%@OSor|G~=Cg3^0=V-X^Pdiq%nMon> zp3f%6l(2cy&iN)_Jqon3am5&hC&vtos6eT?pl1}i{`eqz^-*JwZR*GA+Zl0<1jkyf#-z4ul~)w|1t`~{}|%Sq(!YaW;S}H^(^ET@c=CW^Q{n~*`Npa?rVH_ zbgWK^6C*QyXfZ6$r10vNFeSjph!1Wl$aL%WKtKKImo*rs+3xtkr+)e6muJt}oa4`D zv)L<;9!~%4KmW~d>FP_LP&gWDUS?+Z4?=70Jq4M>A>MLhb=f(@)G-jalSF~C#Y~I& z%wU4F4o8tNZP?^Ucs3{AyTwgUBK0>n_|S;AGA}frPF3T7!+bJ0<_|m|(*&Rn=41*f zU~K0g$Xi#pG}!2?DA2}`4!TUCmJvi<=?IK3a2|eVbPc6*>B)fv)aIJ68!a2;f%%R-#Q+nG>tpdVX%2Pe#`K4JG9emVeYPew|edKGF-@C*qXg8zjOQe)aL^>Wvt|u z!RW6s1M>PBeq8&mUq*+S@xa#{0`J|Md280qc`X4S_Xd;!=0dx^im>TnqyL z^Iw1TA0$Ea-$AI8@NwW1QbrbUHU~2~Al5Tp%ZpNv9`5Sk(VjVd?8S*me(KiA9Z@9k z31CPa_K2v?V#6QD>J3t1@|k6GUB5ZfCqH{zeQeYhM?d|`pZe6UFZ+3qP18i#Ecu#Mq`Rphw*a&_|Ue&!WSp z)ohXI%iqrRU>+#$VMB{-Ve^x<$oWoys0o#o zGt+Vzj;`2qbN9xWHDsK~1Ja-e(M#XEdZRY}yvh37tGjokv4#}Cfc&4ge%SD$^iw~uP-MA){KeE*)Qu_ts!t>2>eg~*YuZ?-r%o=NovtD zkV<1`4YCK}&W3N!81Yw7x)|P2AxHcBdU)ra`62+xuW(3++!5atAS_j75_!I7Q)0nK z@|c(ncdbP>)0Lf(KJ}TO(#|y_=KihEe*ERPFI@2pyf~Zcul(rEd!v8+#joq5pZJW@ zfzvX8<4{y6_#zc^42ae2j5*OFpZ3lvh-i^7G@rLlFJWS^u^~-I#nd)>_IJn7A^&tV zP}J)?xYmsp)0qOaB|3%koqcQ4DyK2QV?tUYf!Y|2w6$|ZMN^p8$KIm@ji(bMym$|% zStJgGPQ&)Ms&fkm3WC_%7%5C}q$y4I_6&*NyuPDw&{LIF3bK-zcuFE7dn|v3z&n!M zA@dipv3)Lvgf+t<3Ls8(qqNtP`8qknKGl73@&8?^BrrF`q?Hnq3sE}uc6XIDQ;U28 z5d=|-Srg+rD_yK~>-RcTF9@`=EnT}BN=2a%$9GAg!7$O@qeQ>??LrS1wT8n`vjVLd z#taOycI+_5K*l@7D(Br~W21{ebss+GIe9-#0%^x&$aQm|!7$RTTQ~HhAH1o_WTuU+ zt0tLtDpszosNd5jq@3?(axipMEDR{jfAD={(KW2-+C0zW{4C2S>J2v3A8e~aW#15W zr?w3Pg>@@UWAioQVf2)sdZwoOvYzSV7w{1<^u*{3$nKf4U__n<2di5fSph-{2COk| zP3tIDoJ2azrS~2!%zUGXo%7{9n_Fl@CndJrZTylS3G$P*)8%h2f>gn{ZkfjZz17A5 zr;DU6k;uMjzjn>O$oJiM&~P~G)0W5Hef_cX<8N2iX&hbhv%Sp2r5y`|pf*Mj-!!E* zhJEebc~9T`?JsMDnH>&7@$*0krIxAA(ZkKJF#h_nN)J zb`ehSt6=F2ro_oSPQS{Eg%DIZ91>qJE>G}77{xwe=GskNhDZ0DcUISeRR;0$xyy5T z-IlPjaGR5J%Q&+Apv#;{dn1hxXNF&eY4m?IO#^p&oh~^9){Kcu-a+f?ts!t81b*W; z_OHZhzRbqK0^Z%cSk@uHa3ltU0%QaPkZ_cThlkqT-8H`oe9PuhR=HtuY}$U~<{P3u zSl+FFfT}J`sD)GL!di7p1E#vhaKVLAggfW461q=dGcf9)dp8B{#Q26nS`f?N|njVdnPY*R13@kP} z{bA!9GoC6|hPpD*RT8O0b0!S*^2U}dbsNw4fVMnO0*SM^EoYjPSA{0X)7=gN!RFco3?COq0IEfunO*q64GCgk} zeUNp1(PjDhZEHbitor>0%`g~Tz{nh#8kOpNo*a!!-8qsD2>`=BW?`xcIn3IRCV<P!{n>);)>;_rM3CVAF{8ruJMQ4$~u7Q2J4s;Ms)LfzSX9i zlRL)*k;GmVH-U1(mshomuvD>!od5TDjwkQ1mm{Q^FBW$6`!b9c#@v&BCv&@eR|p%> zlpp~^(=G#M;2Ye>w8ti2yCFmIwLiZu`J-Wa?1;1{<}oX1BKz?3|EIK8%-$NKv6L14|8xO{!G zuF)C-7lHs@hRf^eKWZX{Z0HcQCV7HTvuG1;gE6K=>u&(f2_jJJ?d_RgiC(Yg{7!)Q zwRV?mL~ICb>LHFZiOOM)$fO{Rl~<)9Ft2^`6ME&Rc9a)0RYmYCFH(fMcW?5!APD~I z+i$+3@4WG*KK|LC)1oSr7juObPCHZEkkJS@FZm7Xtas)!v?ZMM+_V$0Z8b(t-8#Em zhRzypY*;i5b8Hy|njX!JP%;nl9uw^#30+NhVCg+v?_9a!qH%yQ%`#&W#X(|P5Jw$kKJbP14zjm-@u{nVrt<0EV*3vFH5R?tsXKyaZliwO=UDV@-urZHmjuanNa zx=}k$J3k9@Cj26LVF_OWW1f5I)u!*@2xyEy1WVej`_}c9Cl+!<$g8 zROPYDCm~voeQ<#r&y#1~+Lwc{n}fhI*K4o6s^P{+!{I=^v~T0isu4P5&&sQw(03Q8 z_k~{Rj2-G~cH%H$&A$M4Gz@tpz?q9al%%ezEu)rdQeO~c9QS(PA{Q$A1-|q=ee?pW z@e|3a%K)GPem$@yvkfJR)((tjh;)KIenH)@hpDQj{*Cq$HjBsD@LsB*I% zH-927rp051U zv=0J&lmxLw@Pb+CIvr**3&Yaf^+mPwv^qRZ-X0z&OcOg9tj;C>$i}lDIPF;SdHHv` z$5jo7?z6Mb(WZrY=!FX2x%XM`pI5&BrfL0Pcp-{E^86y-`+ThZ9elxSQj&jOWagWT zck8;j?!Q?dFE0e*00X6UT0>wBfe#%7e*JGA{$iA-zhr(1a7NiK%pfS<_k#J7z{f;D zST@Wx3LV_v)%3xht`M`F5Cg_>wr$7k2Hk?-?0jKT5d9*EQn6H2B?LgBk9=gL*FF|& zUQRR!(m(k7KKshIUlaiE-5cKw2L0D3ld1l}Kl+{q{TsSEx}vNkZg*-@Z=*QsWB(G4=OVz)! ztqgMn!l*4WHHQbskvDwkEJ`&*7U!2?pfW(B8xd91G*6;YqU~E7s#PecA|2d2R53*w zh@`5pxa#o#VIWc8Sg~fau@1+(>WvZ&uUu82MEPQ0vx9pIHm+;q+AWne^+mn1FuxxV z;fpdic@zEOaZGdI+3BcL7k`i7w8#PNF|FTYcpLuj5C^l+0D*KwtGOF(9aDj%nI;KD z0?r4+L@`z}v)pQs$AQp(L1OBV>J_;M<$7epH^55jFr&=XNPAs5$tc~3<5L7bK~!tj zgj(F+)zwcQ>cM`bv>s_%Hws5n4T>$z<}>AJ66K8s@rF6xE9y*J!+}2es`T!ismAkK zaX%7%GV?IhckbrO1_S-uuN`WkZ8fnJ!EnL42nT*RbHl5B=^$(l)F6hC^j^RO!p0D7 z^&RAooxZbE2G&aQAmjFv7$(%QtOx`jE6g(Iw;{$^?pVR_mhw7KoJOV!t&)+KsH|oR z(m_zm3mnDEq4w^!pY>XPd3cvVJq#jac5>^GLxwWhqug-va)$+^FEfs0tx#} z;m&PUajtZpY8H*P8C+@oNhIp)NY{Fa@+?u*FV&QR>U7B*1K~djH($S#wO+k?yf06F z7c7mSSJ-f_-EN&;&2@SGB;?$W6aR(NVsR!-+&hm@>Qv2t{?x~?GcWnr<+PgKbWwZooxVDXeG8Dt2F@nXU;}*FZ#^M|S;TqCGYh)? za6G5m`R)7gcx|R`Z3X<1GFF!j>JYZmzgrG-9&Hj9eVjIrVdkfasxnuML(wqO1kV=}D_2Wgf3$$9oT3Nf? z8IEPj8H@;bGw9$Ez7EH2Y;QR2waA&EfCn&t2|?fH0zB=Twja=r^K*h{j3ER*FiXrR z$PG)3cvKgm;z6WfJka68Ir^xo!t$!G%ldeEA@HPi&>qqJ+W;Q#<207*naR5xe(>RXuhIHp9FM^Z0Vq=mw=freV9*6+mf#?wiJy5GIX zb2LThGsYfp9Q22}fB(LYjwagP+IfuO_ae)_NM7_1^}>XMu}ug;<{)F;6P0EI9R%7K zZP~jJrZD!LnE+$bX+-fpZS}v4l>dIed} zIP5v0h9S0Fr>CAt;=c1GeQ?Lq#shVJ+GN@j9Zj3#JXX0S7s%KX`>U^lmw4x~JVUe2 z@3D-#<1&x?VKs;M@48!dSChn>cUZ}2Ow?#a5(SJsUOVq!jn+B8CzZX{3)ycTf zzxb^;q|rdzw{B{jXU^kvjDsUbNa1#j^dtlWFYkuDwVOCd3y$<=ld*m4zlTs>l>nQ> zERM8sW!r7a=p`(2O~(^sCUjK~yKwM%B7J}*NbWgFMcvALXB_&UuQI z!?(-w>mX3RjXY-*l3y3;0_J`=@oq2eDPLqx;*Den3CXG$&=+PE^w8+ue9CjAvSF-) z!-@KFp`J-@aXN~m2!yv$QK1P$1Xz>D8$k;KhKM&P3hiu$x_K?t#vn1XAJop_IV_4; zUwS*!H{Q%u2Z_?S(j09Nv=72Ur%8+)0_e6~U~<-P71mGL>f_hR=e)#o>R=4J)_m*j zx87Br7upbHDC4xm_(kfTFXqM|MT$%Lp3%rRL<)k?-Q2!% zOjzMtq#HFPNfMI;Tfdq-?R>bLR+r0u&-?uF#N`KF-&Ji1%146hG#H#j(_=N>zn zK7RarEtzLwte!;xcE|r&@0?rD?nCBMJD+S`SGD?>F|f$R1Rtt23?qH}i(l5gJ9ibb zr-sg%v}bOUou4bL?%n!9*!v&z^SqzS$IUgqvFny__Sa~2#-@$wqJZG|(o|&ZZTGLc zuXJwPsn^8l-naEU=^L{Gh6_%9!5h$Up&d-WL=>(1kQ)RU+Is3 zRblXFc&mqVCzI~FO&_L&Z5R+$CO~kT@%Z3Sci+3CVzyAf*E8ZPZ=95Ll__C}Br233 z3)uZ4%?K(*!&to=+d5LAAKbh9rC<4@Kl_98Yx;Cg-+OTIb5)uB5s=Mqee*}U_wGWk ze)6X^D;q6{7}82oObY=b-bZ0D!g%Tb5(L0|CHDlE`CGt`MjKrun=e!>oD_*#g4B1V zP23}Y)IWQJq2m6)Y@ic4rn3cZ?WbLWa<8r9^pP=>=X2>Om) zsP7Lm&L|ebmqeQMG#G6dVldg?S2oMEd38sljST}bs`3zUNR^3=XzlLc87KDlr(jCJ zDlv8m8FYT=fbgRTUyLuq5DLCy3>`nk@nx#{A~VGJ{qir-9dRHhIBJcP#C&9Yc@eXDN2Mg(~ zhhrVhD}`~QCX7{^wggJ;f%(f}LFsBu@GV3J^#zetUY-_Sv!f@Q&&=0=- z9ew}xubD|hA2W}tRETdP%nw-*+x>63y89AO9{u`%*74-q&VwG*r$K?~x zm|5Pr*jbk;fkRjuW9{BdL=NyI?yWK!R&z&?;F%Ju&zLzpBOjkQk6UvOm>`x~Ey>6C z2>;dc_%yJ5ysww_SmwAid0O6U_gMcrHa%ga@nmMat|$t(m+!96E-M5+7|iIhwtii& zH3U9n5csvfHU60}2>+xZNoEVk6lN86h=^^xt;#9y^pnI?HSfLqp7JRwo1vPrFrpd+ z#33|GiHJimmq5YU<*Z()9>hwoZK#N99cEcEX|n%p`PPd$>qqH-qae}IB-20tt*>bF z`bRXna!re(P@MLyu4e8~RYq){A!I#SnW~k9w^HFK4$Ke3VmdWM%#ay8l&>`0Hs%(w z9$wir9|>rWLjWu$IQuLO+39Zn9+tiWz@K}lrY_1t8=FIIZf!V(QPR=DSXJJdaUkOH zQZBSv+6W=@qa)?>g*Lag6{o3!y42p@u4zeZUA<<`NL^^R!tAfD>{d!i*{jL48dkAi zUOEdySwI#aupC|t(eamomOJ}DYZ9N== z)#X4tVU%0{;`t%lH&DbX?~+NI(=Wv|uJPFr%%d&jr2`_5_ic<$B~ z{MR^53EuO}ZDMe;S1})|Y@yMhukqd^ef?j4S^ZXP5@to2b(r*KCADNw_&Sj9)20)| zce{ST;O4%EG2zD%sF=3jvCbeR`8D~RQd=K3Nb!vrXRRfASey!HmmbG44T8#PNMPRQ z=3QsZo>xRW4$gVyeR*WKiDv-7d;xBq^};a?=y$g++nyW{64|fUr?>A+9H4Cl^OaO>Ph`iS6lmFHu1vsA?AM7ja^)%YX zlqA+{dZ@{KqK)kx4Mtm{j}Qgad1+x_P1O>q9_Awi>4Is5V5X(~-636Bh1_z*X zI)X!eJ9v^+-{YR{nbWdhyh4B=B`wOrH`9qbPQ&h3GhKf1*csA(#_?)0q%H!niiO0i zs7lTDC%XAsqwn4$ENG$rMudTqnkv*{4$_h+Fvnwz7xJvk`J<_bB6UY|VpvNzY9)uE z9z8-0J<=d;lvRPg^!-L<5a@HSMvCK1W!O{9ybN&YrB=PR?E}-2adX!rd8=)Bzpssm zZOv~$;BlUtXPF*8*jJL?kRli`*)g&ESbe&k{n*2c-8hZd@%QM%qF9(SS2Q1@I8=!b z7TmuEiJ5T3L8!TM(x$lWYWIN>d{aQT84H*DAlN_op5jPOc8a_5it=rPgKR%!K(C&9`yB^+^v_LR%$v}LO;;>2OK zZ+PhUC}80GnR@zl*55mkQRkxj+?gH%r)6H038Mye63#I^L-S~u_7s+tzW7i6nT~dM zb!E`gydV-0em@)|g7ul1;m4pqc8a%C?vuK8S$*fk^~ze|zvqZhJDX>Yfk^bKc4o4N zIv3n0a#GMWA;4^bbO{C&&2GqKGF2BB_Y)CG}}q^E);VM zK?Fh!KYH*`hx-QtfoGd<@YLL@Y_mDA0ot##Z;&@p6iAd6Zx2;$CYq}FYrpm<{>YEt z52nO}2hB!ZHOYJL?dwZl{_pPMR4?i)hzlLmnST36mA?AJOjXcR1RciMLU3E!Q14K0IxLMIeM=P1w&snibOSq}GpiD;+HyK?xHbCz%!jDt7)}Ad_H9FgA{V zt)>fQd2Io&De>$zKmAMAZ#RaPExRaF!g7SVYJa}2FlX?KVfOEie{g!?7rD#&hQ^-< zw0#pQ1Q#&IUgpAm2RNAw^qt>+U3b3s0}aB+=8D(Svsu#A3Zd-56o_)rA?Pnsl~dn= zA+gGoFrpfK#5uA>kdos=s&0(YTeqepr{+hWw~mRI&)xV4VK%m%!y3=NQlnjo&x)2M z$=*Yxkr%P&EXzOt?0M!Pasx(Q_s7O+_q$85ZMH7@O;<2=e$7rk^|ZZXE4XKje|pN# zJ?^q^S~^AJtlL)4U~(@%`G2?Ev)}GE+6IHY+Cf*`wVw~5iD7KcoM*EI>YSsq^Iku> zED%`f<;zm7bv@P)SVN!-fxrB>@841s{_jXY3{irhz$Ww*58wzW$Bx z>8*Dj>Z2e3xH6S0@=8gRYJ_Te-IytWvq6O!e!4Wl*NytKvC?*HcgvVq%XEjhfVlM*x1^z5MX&$=xBU|o~lOMo7OhkXk)yq8;!!rl3?f(R_&Of?|kZ>`+Fb6k+w4Km{TzQ_V*9Xf#>FMON+c4R>aq)!@=~o zp7TiCef#~ufl>^C{(S+vI)6GZn zrOp25%lWV#S(h$fTCS?DKOBSGGz1i4rKZWE*6#j9M@6J2Ocl{@MQ$b@%rqFtae%D< z^!9mXJV)EZI>hhkUpyO>EX;4%uCc3Gc=d_Z`=?xcMjMYRG~_z#fq#8<>~sILd;a~? zj?S!QIiK(ml~<+u!-3xX(GT>-|Igl=#@d#q_g()r?%_;#uDPn)c6*F*aAH{&MB)QM z837r|5_|x}mw*_BKo){XB_R<7%W(iDwo!JT?|S!MXWxC!J-6z1)v4~Yj`mq=y=$#^c;4xmpI5%Dl+e}YH;Qn^?6EH5 z4Gg@rhm+V)d6t{G#kw+{NLssBP!@zQ&UQJ7&fy7K_E5&mx?dHAD%(7m%P<<)>-~{L zv6)PAkK;=ZZ!{&)pyTjqXPte1{!CdP1>diqx%=lrel;d%L|1rHA zH;CEVBM3|{$lqR`FClOVfeQeEU;Wi4Q84{|R5RJQErec0RCm) zKXdT%f9z$JPaYuAr1~pOfB4evJ4gD$@4l*+p8XMRZr{{yJ~79hS)Hq4w=oBOAX5+= zsAu9d(nU`&iGE9@cM%PoSE4P_n5w#rS%c38R3xhi59N+&5yg?pJU4$3NRf)5)|D$) zG#qYgV$KpH6{E3=*;vX;g~OiNK6~%ieid~pistIgX$w?|svy_!#!$UYoWT`})YpUe z_f?mP6wZ`1p|DC(5Ss)a(~JCYUpm-VJa|TNZ&SlG)Y07o%|~NxKli-)TURt67)K{t-&rg*cZ|L>|$5h(fxT5(i*B9QHYp>bVzxwGy<0e!R1xlJi z(v7_1x+6R6wb%omfb2M_M6t};{g<~i#Y2V;<5q)K6#O2L7~8_%i=YYnqhNg8NU z?rSUBRsqpl&2)WhCRM4bI8+Ra$q?&GQG-SZx!MG5^Y^OXl()Wp_TmR19Q}9aJ%_B- zr!oq?8QL;8h`8m^nMljT$GXClf@7KQi2^LlBob)WQP)v^6|k*DQN(&pxaJUUxUy2( zo7TF29O!tqrC#Es*TjvggW3pX3S*t9P{(F1V~oLIMsKUtmZ4g#xo81!beR*~8m@wl zIRb-waj^cFAChHQP|7w*u`%&im~#w=&gZtytTTu6FBO$JBP;_az2AsZHCd**7i(6R z>IJmX5pOU-IJ)!L&m+=li&F>)7i}OSjcH<3QcB*HGuz0@(k-oFt?jh0qj%oZSO34? z)qFJ4Mw%Mq$5u<2k}&-U)d_RlumnOo$HwIAj(@`Lt{&aGu0FH-mI=c(1R~lpao{3k zu&(sdSap%9n$Hv@p*h)3!&F68D~kh#p3ATRNAH(3|lAcVNM&) zfM2MnQOw$J44zskeqUl)NNg8%2Mr)6C?ab&W?dLqriQOMeYU!qB3uf=A8b8#+IfWW zW-YLT`O(ga?&w?0>!z}L0uw72N6syC2H!$;6REecspH*Rd;4Sk&}WiMjfrmmU(jne zTQ6wkE~|A3f$wz);8!AediwW+Ab5$zcZv2n$lwD4X=h&Kwn6sOo=|PxzyCl)p6C(= zEZm+TDriz#PEv^;%J*{bD-(7k>4Ze(rtV`;G5lCw%s^pN*5W_a9>C|A$|C zRijC+AO6hqPIDkDRENFRF=M;Etr9|~ZMbcnK`@K5GW&UKmuHiy5m{`AsvXkFh6#aY z@C_mrLdqU#u!*(=cEu3ijfnS-)HY5cr(SM^mfwg^0?81kHVMhXm7Oh@f0(G4Fz7eY;e4tgD+h& zCe{J=f~Bo8ur65jE~|41f$wbyJpU7uUkJnCFLa^cH$|jGsJiAgwz-up+QcD0e6VM} zC2IT*bW}!7^4YnE#y}Ek8yXU+z-bCh%j}Q+-IgiQE%!TdedC26e1`J(AB^>ful$jA zZa$~M)vLmTa?kuTEO%*-tWpm%e{U<)C8RxUd|k;K*np(q*pGPDNX%eZc)MhXS9~9s zH*3s8kmL+Dw6VEm5+w2tIpKRSUE7;|g&4epoQ3W!#cq*mWLuN;%dh;WC<7$UYViw}@yd95JrV2!nM zB_SUFOTG2>``X@;c7~0@A~8lC{R{kw1W@B_%orpbYm;hb2p?b zLl{hbmCc4mO{G`fF7(B>DwRb!?~o z$Q>UYnFQ2e1B`4;(T3%96Gkc{B*wM2x35{hdBzU&+XRp30a+y2RhI7g>w8h(>@u0Z zQ*~r1am&fcIl%0teAYkTpQa~<1QXl-Hf(iNLAXSkmyzxrmAZ2<(J=vpBIvyml>h)B z07*naR2aZ8k(}=d@-VFjV{O1dH(qdCwiV{q5D2=K=!YPB+{5@&eCK~{2Bedp`C@`u zxkAjIw;bDxT8GD6(=K2Uqq`MFn$2bwp^0l$B|Pl>xm(U^8g=ZZ*)@Av5Lg)IC?U!a z4QY%i!F817`s(NZKySbPnwiVMq@ylIJhp{(^X!)Yq^`T`6Z4zH2+@cr4}=LdwKQXJ z;jEDP-2LWJ^}rVfOjUL)_Sz&)G|w~V2=W8=5bXqrP`sxb9nSKkTNQ=h{YU zj9>};ZOJ$=<(pL@&YBD#8t3hlVoZS-fje<9M%WiwSG}ptn(W-WoqG6p&NEj{h;Yh& zOFljitDB$u;ASh!fUQf$96`unUt0Y~qlt>L8TvY1o-Zy0me|V0t>b0QE+Oze34y=) zo5z1DNTUCeO^+X_wMQZhiEF7u2w8j{Kv*B`?&-n3`zo{C9KP9x0@ByoUbCtApXF6I zE)*sz@@1_e2!8AT`0M}HosSCO{Xz7Tc`kkVm2c{3Tz)AB!aELPE1x3IG7(MFn{q(5!R-bo?wyMq)1+jW*s0X_T3d%#>+C+sEV<@MA z4lz8N6FDGkZIvBz>?G~qMM0u#JJRz{McUcutExcY@RCyLmG?9K z-s`!_CNX>G@f6keSYeY|ufrf)Feezx+?&&NpAMWHQNDUU4-DNmj*xU-{98n`C5#BA zNj`UO-_!VLt}9n>nr|0WVeL4<=z21J=KGa1KZrLYTFP3p=~P8FSJSj=^nSptb~5)t zWo85$n^(+nB3|kt`cNBpj(%(PB4ayMD4qWz>WBu8G0KUE)0f7jbmu_2eNgI{E=}=glBmfbC~dSmCUGYusBe=o&zTEm zrscxz`my8RIq!L~Hg-Pnd3j<7V*Vjwt@Hlsr6;CHcZ`Tux?YmlW&*2RC*uq3@_3(A^>Co7ABlZR(XmQ#!G@LBf5#ia(8tc-_ufVfQd6T1i+9 zbqv{6*O~{lX1(a=T`3>U|2P`_2lwtC>hoXxx~|`PLCIiKCHBSU5DRIjs|WR65LJ+A ztplcYwe*`SXW9j!fW>Ah38l`ukK1=lE=T9{rWz1V%5*E-r8*@kZH2t1*;QV29pkv2|`j?7Wh z=9R08FdLa?A{s}pKh$97iut3!krn+4Q;IfHtVz^XH3rrJsFQZu>q~*6;M*wd8+`jKuy0h64#bM@#T~5e?ILzXQz3weADIMPAYtx z-~bnU^eEDM@7-2j;CE)=JbAzv=wgk_Y~0n#v-8x?%J1X@EHN3ulnTEiS(fSe=+LQU zx2o9wbwe~)25ec)6h^5whuh8v1%#jp#8ERg3v?k#Ce$b-XzKn;D0m1h#ZsX0R5l`CDjPoW@x7^=vnBc&n2|8C9OofU0{jsG z3(OjWP${OYr3LqP<#eh% zC@!1L^x*bgGXa3efY^oT@X{^5weL@CKT;VvVhCh@JkT%w`hWkYzxq*u^y^=5(y;FT z>woa2Z)$&1=+<*DnK~!Y5~zQ^&;-CS)Wb^^%!$(uk8t4-lmp)q_}oCN#2hV|1UzuQ z%TPa#oM{I{DNKo|pIX!sTrXwWOxa{?s)T%RjDR3oI3V+NSVw5%tK!PFZSxC9nwYh!entB@ps~2Sw4i)tj9Czjv&=X=Q^KEpevf-@nnDUwY?f>; zWO=FVIM)leaFR&G2cQlB@o^BUYy)+8mE%X1SCyCn;iCafi@=cnjX|O3ZYFx}+J=In zP}C$Avh2(6Hu`7Zo@=Z?o5MgkekPcgEpx)nPuNwCaR_l@&pmhUQI%PF?&kn!)`9LE z@{A9%W;`=C@88=~6!z7Wk>bdO*z z976c#nGu{%94#R^FULxgzWRe5%d4yk=WMaHJx836#uLs*IRd|CtknNR-WT}hk%;+s zu$`wr9XV$UR%P{>P$PcbsE_+a{b)#@1I)WBOdU*A8$S{81TTP*X!BW)P?TxQDgzrVK6_ z6AOS{+>6J@WG`-8E^BrPf$tg!q)qS>U37tk_5@R+l~Q37n~$g3yL(@w<72atHKM-6 zg13X@tPnSTQBR6SdD!T1pg#z{Ir*=H!q3T4}!Dy!=KFVt}@Ug$PB02jUn88jnV1 z0)lO>>oYiGyAKa_iLaI7q=OuCCbJWT@;fkDChV{Gg5 znYOpKOhaN;<{Itqo1cj**RQFLV%vNvhj6c6Gr^lqSbh%y$=7Ikrk2Z^F4O(hdGqn_ zugi@*ylQD#7RChf?=KJ*>dJd7e};6e8jt#qA9X%4CLn;Ii0}!LsLU%J?ap;|qtes2 z+Awmh8Z=)1i5lR>g$r#;QQbcEMfwXxNhBpb#zCb#a~*K~dZZiMk)oJLDYcR$ z(3kH@zy0+i9Zx{|=*!l$s?%qTdFtSOpiri(lP~?z=XLLs#;RvthDh*@ zDbY4^!N@o#QFTK%m-aNv=4N{7*KRi#P9KXN#_m1Vf+ZlB zyHhj)qgY{y=3H%2KfdrgzoQ55zOT*xK-p|+kw=*8z|^!W>Z;YW@F48=uupsR*~9R( z^Frm(XXW?DkPyyMYg$=bq$14e*n_<)e&81e|Ltk#){KLY!9`IDC#*?G^s-0Kk<;q! z(TTweq;N#<>_!Gk1z2UVHahACv{7) zA=#NPd-Dfrj?BJB|pVBwJ_p9W*%U~gahyL%>y?j@;h9uVQE+xdgV+JCc53)IgW zO~YpQ-O1=r{ra!}+&M)QK8Fu^4&q<@%9p;Oqw!qNz4R#&+VgmHq@;B~i45qWqqF&W zHN=PB=_CL{Hd6>Mq^BmCh3nsu$niSN0aVI+{l0Cw<_xpl>?cI>Xo(~cI}lm&@%_X1 z-D}IQMGm$$H#I=N-#pkCIzBvFsM3N|(w|l*L+~rp>_7`*V{_B;g!wR;PDHeo!N$-c zMfkEzTf)k=?Aw29VAg&71g}BJjit~*3Vim~eAIT^aG>7o#YX}2@A>oU*!1a~PiRf7 zDXaVL>NNyMRpYI^R=+pUyr?wZ$5%+Er=Hp{*khN?0e=FiFMZ5+XVuA<6BUHntyL6L zP4l^h8CC4&pu$YIp6%(WD|4m2v5Io8CJ*#ScL)0C-zXJLeJ<|o39*x@kAHWbdUtb0 znsj({q}|;;4TqbG^FQ>!8`6sM8uqFNgjWHnEwDE@UY z2Y`VI(#$>M(llX=uxObS?Zb*wl-gK2JIA+G&Afbew^%l?FAr8cfFIvZVNLvQIzDB!y8a>!mQ#elcbUw3<1Z1U{X9}AThn4~b;kws2 zUkA3?WQD$cC7SII!XNtFFa6x?qXhGpUmx9i|E>3b=6ApHuAX}ShZKdW#Uw}5E)V+_ z#xxCG^bNoH*#_8=hFdr>RJ2hIZJ8OK$ma}^l9Y|+$75BqnG#{*;yh_aiPOYDy*&(K z6-{N1vxZxn5}^|@alza7?vcW*u>6I@35G=NVr5scQcj1{(wQha0NW4TX32O-*JK$nb8fYGwjPP`4j;{Npu>orii4MN z8sQ|14pY%z;0MGehbe|V>h@4oRw$`VUMxlOeYo>IgP?8U{SqB;irN-8` zm9ijEzj4mky7g+SV>l;$U&evWuORLz#$*JhS3}4|Ft$WZS?cEXO+9t3ubo&L2C>2_ z);ITR{he3mM!XeOqz2Qax-yk_BJI%6aTPjAG-}(}U$;mi(OTU224=ux`Ge8rP-9}l zcWb`9Zt%n4Rpg6U{eGwidk=JXFV|rEd1ZAj1%;Ak;NaRi5hDlt4oxIVZTqZ?xbhC8 z&i}Ya&76T5h0ft#K@=Jy;UFQc3QM0&MjB7XHbx>-?In@{bCp?!vp!dUr#6gjI@(aN zG}==#yrpn3P+8?_0vy(sW>;-0?)5-dlbQN;s0^GmrEQo`NwGyTYV&Q|;>Mw$EsmM% z$JV;D`}*|%-L-4oHBw#wV`*Cb;l%Uw`Qg?f?DP3STlil~y;>jnep**c_x{PbXLN5n z%L~RO4p~`SDzu*5+J!b*!APqzt6v?YI?4jw-f#5oUZvf6s-kzzm=;Z4*vP3H{2+uX zt3*vrt6>7VwF%gkOj!lSp!VZ)wa(qK#+u~6_b__sjCqFHjxEO|B}5@odN;-xXA!=B z7`J9V0Ds;Ym#mi0J;bw_Le+r^@*>17>rG8mt4ecr>DV#I4&QoHZ@&7fe(;BWSXr9r zFmFVN;V1{n%)`ojpwRk=u%a6Da@9lGL~`&Ev1ca-+n{i z{QT#&6Zeb>0em3d^DH-$kA^5IG{UqIAZqcWE!QII4$~8pL(EN$ z_GRrTYo%$bGA}im7wYu~wobBU#Gx~*#CHaMO8l|fuRa~$0qi9kY0u^n>n%RFI82Mc zPY8eZAGT*4XRrO?l)7?SW6WC{4QqH%j*aa{>&Y|Y+levoV#LPm_A-C=!V!9eKDM4A z{HOs6=n9FY`ZkjlI6=gUW%kvw7K z5Zc#3)N0iKzarhk*1=X&CM4pNMg9rZOE)#oYt6IiC1ausunT&9 zvR5x?B`>RW34!kw2sBL-M8Wib2bbbtWAYxVadO4R3&Any548VaSG)J_YdW18(!%>J z=xpMKNVYbD#^7kAB9zLYQCPb3ajI;T)!+C3y!>bOU1=ZP|5U+W{py!rH%$8ajav%h z)MAf2X(x8b^+HSGtXi3-14vf2v{(0=xqVmFX0y)5XRz^V^4R3I#E97fH;r&g*6R_} zv6V{Un_@mU4yW13A=u&|76^Mz zIMU;>As79Pq58vtW@Cu8i3Xb+rpW;!0P;)UTG<^YjW5HWJ3&Dv4@(Lm z+?&~2!!wE^YoAH6AaFYji0(HZs&Z$14B}dpZY=eZz9Gm52YWg`8f#;7sAsN3!W z`o<`!^2$_!!ReeH#Tl8mQl3RS)^GwyLcMrvE7h~l_O-bQ(l%F9Hp(Z7{^?hw+fxZw zAxRM{G0$SP8ccSmL+jj>K8H9#4Hl*sWtQbK#=IYoAh`b8^+mgooY4%N;q4wA7;>B@ zAo@>MaSD5HB)WN#+dN65SVWRxJVVss@RA?I6790_-Kz3;tL^8T^GfK5X&90)6B%cw zzD*cL=3}d=!&C;xU6S4olIERaR7|p7?=q`tVt=|8%qzyg|bREm!i58uDb02PmDaFW}cc&cMkZMfJtPL zb=tAhS&RHTk9(#ZG>bU=I$*3O=4VyutvB8@N&eOA*NtJALZ~;jF#}*atscIwR{L$u z(qi+xsEgJKVWoZ(>JNYK3l@2!C^ORnq!%qu_AA>j+`jcu`ITq^3lT@j=-tgQV)~!<**#L{(Z;T z_Uj~JLY-LzI1T~__8=UWvd(%YivRXWoMDjpxwM)exYcTzUc2g{ciTnY;1Pw&(3U)& zEYZA9yh*bfGsxfZ5;=|DA_9gpkEjw@noqtI}XN z(B{sj^$Q63{{Fs-JTu7^d4ae>ZI&TnDhnMQ?mNbWMe*oqc6g+t=}bGs9KxrE3=;%NP`$rlMd;0!cXvY*Pf<%KbRz5G4<&A}MH7_kKaAl3;mZE z(QV-`Au=&p;I}N=SHaFs!}sL2?g?5hIih-E7XsXZ2Ix;`hA&wcl<9? zAAQAK_G=Mv;u>ut)-jOq*=%AAK#y=b&5)A~^z+Ok?Pxv`PBbq|^#_|K^+Uqx4`V`_ zgWEs45GkaiB8j z>0lb*=8Ekr>;$J{ukD_Pg)v%8i@a zxqj6&e>ld#;TP5g`#z z4d(&VF~$deYR*`@7x{m}FX|2xmihic<~$(i_CXgU;7cC2H0E#YG;WjBX{9{WU+u@I zrCV7YHgWg8?sc~g=e=fptsB{-#ZhWnLx%^4myC(?0`y~i@3NCVM&Mr-eF=fT_G`^x zt3Um3g0R7-#80!bdTj|09S8-8f~Ks@o|N=z zHuMl==F0#kLuFE9m?yKNBc+3$(!o&ksx-y~D(^ejt}0G?E~H|dXkN^Wu=8l(Dud#2 z@G-!7*868Yb5L>rEexCy|L&f?ij!2mDAuSboS6yz1!JW(1@J^lH=o6I%fMLNf4~dW zV{uwapO#svUKDDU0MK{_Lw~ zjIs`Og_cu>DG*L3&7!B$t?RLdX{-l#u?v@u>Vf{>ug!Fv4fQ8qN);ECvRR;}SE)4d z5$gO%{&CjXnnp-M`g%h0890ptiiZ*AjuusG)n*s)le&JAWqjB=J3@|e z)9Jr3b&h$fQg!82urYl@OCqZR-J1tG7-c$~lq!`fNH95aVfq@=2!Nx}GS)p2Pd~Ok zk1AV0&kxOq+qje!uOmdgrUBpKPl9#I(%OCT%*Ah|T3x0DkLWvmqu}6#J&3&l76>a& zHXG~S?e|rdfu4Ec1=W}Z&T~b*zH*p77Qx5w7b^vIZvFV6{=Q#eWl^2vn6G4W5pIo% z(yo`bcdS&(_4`Vq!Ll`fWS?x!9@tL}cVzvf-{B^n)-9bZjd9$W^EO9X9xihV+=+Q= z+IslKvbhv41ZCX&6~hctR{Ez?)QL;0WBVnun5uU3^3gdw3~WrdIV{rrUelQ$CknBf zP)X8Lo>$sGIC317hhMr(xj+y&$FRLXwY{v$B?P|9Ah6XR|94@ezZ{0)Pebr7m=Yjt zEz)Ml1d<1wy48(#AM9Eb4&L<(G)#%Sa`DMYgUbzv+uMzj)-=szoX=nQdw=~ezVdM~ zC4TR#Z#;GT{oOzN)vvv#r=R@+ZC<%%gj>PR)`py8i^AR*N%NTpj`Q$m(5h~l6pKyS z>@1yAw&{3c(s|T7ajt1ZJcvt6cp#l+QydJ2N_qq3EzB{@z?6c64V3o{@$?&^Rd=bS z;@|TOkT4E3+!`uOTv>TmXf|>tHz0(jxk28LzKt{;kCc~lUAb~iaoV>?AlY=R?d#Xn z-`sMZ>p`kf5zY%k3P6EZnG$Eht9`hNH>}>DClCLQ|CV}j&|{2OQ1rN!s^DbJM;!ri z@yM~yAMl5y4D@}pb!gK$FVNw*84v!`p^tLQt zQ-Ma}c#1`b|Cao?KI`B)bu|qJ#;&zLR1zm}^P-b}oymown+R@?XAYCBF#Uw!W)-9L7n z0R(;20f_Hk&ht7lv!Vp>m$@Q*OeCSEO{jN{OTDw-=qMv3a8HTZKcR7yDW}hf#9{pp z;nI#f=0ATn20QC}>sMhFmXFh(brNItNHgECF=MN(%}aE|^eT&I~AxJhO0@{6a>bj_J^sHdG_8{xR;;2JYi17ET&K!Mu_e|dA{I+pEYfNK+B?)t*&Y13g^NGK18Q-)WQ#PlO zvcv`Ha~ofe(NJ^N*}iZ2wm6l$cKa~n#+Ko>&tMGO^Ob%2@ylNBq2{A%rQRp@xRqzC zWpU5@{_r?klBC8&JUSlxN0;Xd41uL6;R09kvTBzQ_-=y0%P)U6zV*j{^5^=2{tLy? zPti6IC_^~7=}1J_TfHhB&J~G;e*g9zLrl^zR@qdhDFI`G?^&2_UuF|Q1s5qQPWo`v zHEsUbZ~V&7?tPrF-0WTX_kQ=4&uNwidiql@YC6kIVv<-S18NRY7dv9byz9H#b`fVw z=}OvK>43GL^p@!`$3Mh;Zc=(9wvcRr$UvZ4%xhHqv7b&g*xWR!R#laXv45Rqs%Fly zo58dtm|XWbWYNJI2Xqd(^3EJl>+Sc3+9phB03sUd=wPhbEVpp36|N$YM)M?!RnA8m zAM7hhQ*B~O*8P8E0XFhS@UxhWP-|w3pJj7cz zn;W5ulRT&io5StxX5e(sO%TLRR>DxlE-EWpm70M4yQzvAdFeQ*cRT)@hrGwo=O^%QB z;%9zb$#AIgcx0Ll%&MRwgfZF{Ky5wu&$ll$^`~Y1433?)?+p98`^LBR`Zr$HAWc-{ zxpQJ@PDH7_TZH^~reQ^0+d1aTS(fnOuNE+~tbku+ejm_af@2E<(SJ zYsXMn?Opc1bqD(=(s1?|lfbv_;$7Ct4|}k_*wMi^x;62R9zSe3{`+o!SbOT0Xzu_7 zSh%*~^tN@V*=7Jy4lHes_%+{We%cuayX`alRTx7ErU%YTTNB~#obzdJhj7|w%qAOY z@Q}e-5stMCl+%j!>7J3`n`mWOX3nP)@A}|67;4ZE0MB&?rfhKR_oT5w!{8u|JaOu0q8drV z?M>}m-8QLi*u>g>u&;bJH%kv=B0?HSI-P4a8mm9(Yh!Cm zIi96askFH7g)yQMA`)~E)YBl;eWio5o%Z^<(|ukBk9A++q!EW?t-ljf-i7(rzUz=K zf444!CzA%^h_u{XleTjyj$++?e_x~HnXX(<_1t!&7j6#q=3c2J>}isfD(X~mWT>=N zWYPC6p}bl<^G4nxV!&j95T&8YIV#3PglQcIqVgWpMnnuY`g$g8lpW_t>g%iw)cAWT6yZ%Hd+tU=RXt^N=R6cz1En_Vo|do zs9_LC%JZ3-)_5ioW7GEkmA*fXA>oT|(3nhO&8Ji6%cqszv$V0tKL&VxmYm zzYyNeOplE_+5p7r$Gk z`C6<$gR^KUgy(!X$L8P)Z~Y*Stw(#m37E7n zK_UZ_qSiF7{_}3uAIJ3@?u<->+WKJhx2;gCw2nWN#KuHhAgd?0Vk3ibR*^og~ zM|Nt9euMUKhAD!Xh&LbcbsY?d$g$y^qBV_^daM+C^{tI<^#*-o zf|0i$Wvq$(hy#GR{W`UM@4uo`#D%y7UQg<9@N&6%BJgD1jG5)Qp=^)m!>qu8<)9Z^ z_{)2TrQW_j(qV>wj>KgBX;VNQJ7>2^Usae|6daYAhOGqLm*?B%*LCip7reyOzjvN< zw_Uv7z2|z}&&H3ZXwFl}sqZY|#XifyScCb^+RYw~AC>FZuIcK{n&g zMe7r4T@fBm-DkeU6VJjxx8HtO_uspt9!zT@binW|3Kf{o`N%Zgj8Uk;!BGtJcBc zuK97m1)@39^TZk?QB9n6q!VuG4A6BBVWfm+Hd7J*JdSnk##NOwr-g3zv;mp#c80y%@EwDH`mpE+Wh&l*k?QratA%iSqi6KA_LNu-(Vd+dHs?xDBV#}ma zK%9EU?x7<NHr$*9rc*wOh^l^!rt{T1j=RLbS;#~*2{$dJ2t zK=uR##k zc8?WCn@Z9R&2t{a7QWOm=3oP~17~G``SyF5cnu!P=2g;z0JAI@kWND>pU*TIAF0SE z#u&sItsU*W=Gr65ln-;FZU{5lSJ{M$<632rC{0q8dQ0`-`<1A#yqu~@6V>U!=4cca zHusXKGO0d3Y=XE@uc;Llfy%U2T{cSFG40yo7>A5}-+!yj3!m->Cu{9lN7ou?_1n|F z^Kj*P_nU6|Y2Pl>-FPk9NIuM8BPN#Mw()CgV^f(aA^EchF};wI+6u7I)BZ@hbC~IP z)~L{iOiE37TQ!>>Q|$sayw>bOuitu#+U z?G=f3-*`tG+ofg)nQr{x52z#zF6M6VCR@fD8gMYk%^wl#$YSh!hKkczf|-YpqAFvr zNL2@s3d#&B#dV=Um}vji*Q9)|+n%UT6qT)Nj&A}$X|4*&~ zj&tkMX^=*-)6R(!UD@2$WHePAC9PE728OL6@Wmb(*vk*FMT6Q4KQMec_wByZZQ)7m z#J{{eGrAY+=Q7!@{M=YccDe{QVWm29b82B?(VCW+U?GVW_hG0L1{aeG8tnEfuEW^* zA|ik00&B_YoUz(fI0<%wpvp5IsCCq+ibBIZz(epe!$L8SrLCICDm}x4SVtE=Dp+qk zo?uK3TSiVa(Xa1T7se0fBQ`!=J*}>U1!ehf`vIl|>C5$$(cBI`b7bt+Zq^6GRhau> zU{1{GuM&sn{hmgnOH+;$opC{LE*TRSv|}!-_1yu1mp|LY&y1$O9)!Wa>DSTKmLcgY zYNvW>5_zOAWn~g)HWO5>4-XD(VFp11VevPv z%L!cBuqcxajtvh2cCaxtq|t0OQAf^lV@mjMA9W_r8YCO_S|n6KsHD}FfM$Uh7>~!s zh#)We4uTYh0*FpFnVJ^FaBEY&L8{4Qrul5Hq}Nk#v+p8Uv`7kY@){Yosk524i1!N3 z_^4_xo})DXDCE??46?I8I(%a1>}`6n^EViSXtomm&TDpQXa!yV5MsOf=9>Esl6ac5 zjjxy&aSUq)jfr~U3j`z%X%GE^r7@jcwh3H&d>j<|Te691&%CbpY(!=KA3L z4RGcj%l7cS5p(VMh4|SRgnH)bO+|;5_76v99`x3`iH;uB`l08gAAfPE&7L%w%~i#< zcH^N?$moNdF}4_Uaic_mdbPBe1vtfQf$ip-Ljuw0c>m5l=bRJCFIpIF*iam{o^|+q z{Mja$;jWIj05U`rN_w$r6wM}MO~xY&n~1j3c@K}A`uADlP>Dy&CfJ4T&f< zlcx}bo@hC-3wP%j4ECkZ#>VL4=A0Mw*`mGY{D#*)$TxiF#@P7_a^);1R+2CW-MYgw zW8gK;{LJpFTv6IHCPH2~rf-^r>I2id(!2K?O|nAMDW)2Mnh-LJ^^WLIFugFt<2yIc z7HxIQxmA2wr}MYtv^Sw6yUYpyo@Yw<`zLj_HP6iTh_r;shMVsQ5+Lg4lR`;cs>p{r ze(#>Dv`|_`Du>d>_Kiiquj@w#7gy60&)YKmSVJp=a{bz0l{v;>noh>rKiD_I7s8(Y zU_T7w*ff)#2n;+z@c}dQbCt4VTNP&`d6QNyeI@51m4kyw~8?#L@22tlJ z@I}jjkmhd8!`N?4InZu{;o16?;Il42=lnZkr@;2o`HFC@@O~v$-&*vyF+kRr=I0oD z0lse-dzZ(>hrlIc;^OzwWeq=}5csSA+k>qu9BJf96c<7HS-@`9O>)Hs-P(t6vtolW5W{qfr`{KNnCFHJ8B=)U;HFDAe8 z%b)vCH*P+st!p?Xn2MU`oKc&MUjG}ze@vB78W-L^1q8#k^h8up#% z@|H2-oc%ewNiuJFP>-nKqaRa$cPw+HNDgp3f9+Bp{twa&TxmauF$ZP=j8Pay^qXmQ z(7UCKP9EhoH*qbl0ispY*4ROl0%3;ObGV(_boESMxQvIxjuDsL$BR^ zph>x*yol6bUeqFCzOIhJ^{}?Y8C5v>$og`LM8Sx|uL+14(N@AJ)#d=WM@p1x|0p%) z)7~W17rxa9`~DyKbgWNZ?Q4iHlv0}4g~~8cKaMSYaGf=pg)`F-NNUW9SW++nahfGm z2xb(TH}kC0g9m#W4mMpHNVJ(=xV|zNdc=CA?mY8wSv0bh{`zzn0+>1F`CQZKSkw8` zB&SSmoB$dmI)uq0pU#D?o4nYDK!B+MLk>p7&b4b6;uLKn%47ulb+%|K_0mL9>>@BY z7%-q+=Kj4-QQwhE4~y?a<`3t6k|eRQ-!djB-x%M19s>O&5!xg$5KStJbia{~=F)gF z*S+J!A|zRK4(2!JaJJr+=A0Mp8kiC${cVS}rG)ud7>WpFMSa#=fXPp;D~j# zjVD?NRb-k%?rVrZYbVRlayeU}IMIUn@g^&w!6GgmU|K3{p{ZrN8Ee^ITpZU1O8 zGl#fn>n)AZ9{!rV=|=OP!=S|cl2EnuaS*D9243MJkzpRgVK9Sr=AA=#7#$Cn;P$t5 z>1)$G)!j0V*1mH};(3`9uKuTF(vC?SM_WkLIDE*#q-Q>#lEa#02RCmbVK21f5y1`2 zpJknD^XI_c4nrSCn16PTskWxFqFWsmC|Feo=s-vXflX#66lCB-a~4EAq)rpIns@xdRs#k<{%N( z!N!;pRgUlZlTjml(e%NI17xek#6bw@pWYx*uh%mZ3^1$F;gKq&?*T}>i|B#Cs46ne zMkB>>sywg~R z-8@W9bfMzjed46@ND=)HgvOWGg^l@_z;Pb7#4X=rL6~&<`eg2pdFK(uM||dyf9hxB z#k5-@vjv~ebCvj@C^J31DLsEJF(wvKW174)4UulUD9YahyLIqeR~`S2N$xvi2tv{0 z&M+hEx=@|hrWNtbt-h|^z&A?fh{G_|x9$h}>?<>U{?$_VjzV2aN)0h*s$=0}6L>dq zZXPo;ZQFOKGkXG&`hsv8IT!?*PIDa{Pc+=vvdAA{f`Wcy3>#mub4mMv1sWUtD(A?O z{)YKDnT$;1%lVOU;}aEgo8m1~!o!hoy5q#k?)0;nEy0LvSo>;iZeCGfjz!)2X#LY7 z%+w_co%7QL@!DZ_o~FgUuK&7eHjY{%tDC;=+P7=nvk#L-z9;i`CK!%@b;K#xwntb* z5+||d8{op2;Fn=qhWdAvs~?p{MD8CqdULxYqMRiJqdLn1MU#B`dON|9Darbf>G z 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

91T_gv6;@5Bu4-XeAmM|3T9`J>wc&W8 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%0D@@BveO9vKH8ytU?>T_OPZBzgA z!aOs6z-Y6$FpKdHRyG`-cnQw7k(+y&GPanfuzO`&Bb~3jH!EOVRvTRw9IMym++D3H zTUb7x@!E9r)-Abv=e8W397+;%2nF+EDX}(KhHyR#p9dpfU7#@*`gMc(#9FUv1}k&T za9KjU^kW!3ajLJwV-1X9_tWvN8)d`0XKEO2!ur^)l>z+?6G@L=qDIQ&g&@V8-?<^t zWUNeRn9EvUrN694!%S$@RtU>yIzr7hmdSLgsvML9X4HH>cb@m4;0Ne8Q`H=*OFs;{ zg>e_+eiI)1>7V!AXpePpXfF=aLdJX-mv3H*x2ez2MeP#p9xe+5JI2IiVe%z}^IJdo zX!1Y&jrso?iTv|6K~T)4E2LOT+&gldhGwhx@yL;Y@fzRX* zrkoP70nrot8Y?2ho0ZLw&i7UG@Pr`Gh{n;MvNY92{}i+VB88J0)x+#X)$eahaik|hswc~dyj z55t<3^9QFVs-h^qJWH{Z0Kg?YUMEw6`tno!LvUqDXIN{fD)?a!uRdc4_9+AgYF?b+ zf#?2poy1N*?-%{PvF;vM+9u55-Y6|)-k9z>E9Flewa@sC;7ZvLImU2jf`Md5aCd!V zpf6l!(JwQvl{#N0;A?>OQkOkJ`i7YoqusI07L8Quks*@(ER%b8#~db0(z0$k2?zRD zl%xTjbPY&+X|izAiZ<3bxZ2;F$Xjo}Df5#O~f3iWx&0r85uR& zs>7wTdqQ80na>YrQm2U=yz#0;(~(NPP+mN8z}0X9XdDwJ65|T=@R>@Tji!5Q_;NCt zDAOO>jr`{`$Cwz})LZ$qkiCDQo6zu++R5lKenNa&f7x^o;hpz+U71gX`$LqFNdaBz zem%nNyoK1sKQ{(?WZ}8f?-IPk7q~ zPaaBAw_XIh>X;HP&G6<+0ih~@n3PV6j+<_I>ZB7)@+PWJcvBZL$wz98Cr>MR|AX6d zBdPw9!rcAa8UuIk-o4LS1VtEPZ;j;e7Ga*@)Ns_wF4t7nz8Jl?Rm%s^+ z?)yN4cTU%Ad|0sIgnU8zzzLsZ*SVuX%4ZvTI#T!IbE`!&&6`Y=YeCmFy=C|*0#fci2VD%s~-Iyb+g__>e5R?E_ zv^aI_kv49;j|k`yw}N3)8i|RzUPygBmuxhW8?WC}bq#Q;{n^v`F?J?UCxzKjmoh&* z)Po*WZLt>u4MhInh6Amtt{m;i0j9SlX$-IH?(5R7 z3ttCE!&P%|*$?gDgMN<$3F~GY*B!5FBdp!WOT)kbDR^nHcYt0n2CBIJS8bEvin7|= zO0;;(_t=+s^vS1k^z@mYPO`z|(l{M6V>y7=RjtMCR-ATv_TlD-iGv>#ARJ$e*hyAP zmQ8dLc>Rs3Ja~Km-~aZv?;oy%zY8D6KzuX%CLDOfu^RE|G$fa4!bPUvw)&0DziQIc3KbR?;zI2QUy4Z6PEKXF{^>w5r!ZBb30Yzc) zS5*$SsBEbHf*IndSLC&?hRba>Orgrji`lfU&I4;Jb%77y!4`LAM4+eauejrM5$0{q z1caZ?4Z*vmL&SPK8L2+AKhwMrVFUaZd2Q1-E?Pe7HdH^_!@jw;aXF}{`b9Ilf^^|Y zm5wE2Od>6X%3qebT+e7i#X;|c?h1bZel5r9o)4ZrbB+u0R9TbSJ~9ry63 zZGR4W!{Bvy-)~?H^H+Hr8qgeVn@CZ@^cG3mLT*oEnT{HX8ko|{@xwHsLZmA!3g@<19gq+ab)zaAOGq;ms4Q0veWOvjv1Zfb^`MqEo)^1%mpzvSzQHpt zH)->1GV0PMJk24fub`A(~@pvVfc+uT4b(to`4og|bUL&~F-@p4t=xK6n1+Uh#Xux(yL zW!*OIx_FlfGhBzl{0OJ-vk8USP&Q5)qLI1WnqY*_pAfe&zF138fpjb8(u8sdF?bG` zFhS_rN9uc-bzYm%1wS~+GGi2Z+AVhKnfLGBlyAKGsvI3Y7R-ZA(!9&%B6Hfh_UeFM z(nB||Kxfdfz76OP7?3nqmbza1b;#-i`LO8+V<9}~2#c%-BHnF!7;ewxVLuCFa^|qa z(Iqa_%x_W;jFc)f1!=>wkdwowB5@^ey!DFQ+#ks}j%2I{eu>r%by_5YkO^YlEoaA4 zEfz8vPo>4+d>qSkGVKn6*oe<&Gqnc=KFl2~CE9P7VW`bhE#X!)RSFo9~NrwrK6FDq$bA^)y&qzuT2S#d^ z;Q6DH2k+jIH{Lq@YX7;4AC1F{3{Em}Ry zTAz*kjmudWQ%FoyUTl2bLS*@9zx11WfQ5bZR7Pt9R;Myscu)y3iHWWsdV^HFYhEn6 ztUjKhW?8^w+xAkkf@>CU#{}9A(mGtNOU*b%C4wK%DuoIm;Z1XZ2m3jOl&NwpPYc$; zK6kjUzZt<*e5VNhVi?;=;uuWrF9EZtPvDs|5fsF@veD8PI&izTG=OXF+s0dy{JDd# zI{%@u(&ZU2huwS&!)JAzJa+{z831Dy4^U>KMCF$mo2gSzYt?um`qSQ%%bLE>7cIZ! zVqPh@uKlhwm#YOn)Gx0#$0hV|qk;4t;_Q@XQTx7ypk~s@-J38Ypo}mVi07JQ$^1g9 zVt{^G=JGXp3RF1yHBv?ew492wi+uRuJ0fi*MLCnktH)ShwY$N1k?n6~2=A}_!Y(V(vMO`pbKp-!TQd@zIPnZ1IbXsQef z)Htd_X2*weaBm{t{`vRhwfnc^-gF`dISdDP;;&2zGvHb`QXU>kRF^WD?hD5zsBuj9 zroI%S(h?`LnKBNrEyrbL>msdr;84si>kEoYR8oR<-r{h#cwyLeKGSw4spl9!OZU`- zw_e4#fg`lLt`!5}aJ|-ycbQ!s2EOypym#+-cA~^w!z8Dtj?0O|a%L05l3dJ7`Q+n| z1yO5s%peZaEK_>{7I&MwiNf22)1QQOqVj~Kap&VWmkduFAG{{zWbt2Zlg}>BDhB@I zZ~uNKvAk=1Bo-5GgMewYn&R@_LPwe-ykB7YIr%I8w&-1uDfamsH)^190OBJ(kPyvQ<~mG`D9Vr8q@q)wz;`o~uq%}?6)o0xB9= z4i_AQmzCuCP5J2KAIs6RW5Fl%C>zOqHj{bTNRs0BzI2u7jbB^K&?86kLiO0PToM)W zW0kK}`XY`O>K}MAx*>35r~6}x(^@2{^j;OuNKcNSZj8LK+!0&LAn9yO3*b3k?%>?N5ai0oumlQc0+9e}9euDAGI6)iiA; zQ3>bS8IwGjEoAT34PBJ8Gzmli)yk0Hbg$M>)io&ulx}K*bQR?vXVNCI#EI*_?0bs>2_uM=hF!Es z!b0r`R!%TNG6wRMyqpw5BvPQO%m&beFOg!1rB+z3EL21NlZ063`&7F~bcQWP(4u=62YYb{}QQI2njHc22lmaTb8>ypO_=}nA^i@>qpUE`eGfk*X-=?%n%x@9tgs>8D3BIk>_0S9EW$s#h>_oK#cY*6NzltqyKQ zw)%u+ch9SMyl8zwxFHPsFDiv8#b}&52evUJ&!ovSiTwhoYdK!UJfj5|+I9e?Kw7_n z)bSFpL783kyrD?QnnX|9%Mz(C;`sEooE8(W8fQBaP+#Z+%lHxRt49@+>apSzAioq%v(InMZ|0?O5t;F8Py3QhoAR zM*H_A-aC+Lwvf^7+bX?G{@8*zIyw<)nM*76s#cV9mAqZn`}7lYvq>8yjazpZd+Z6) zX)f_-q|88QFmSqLmVg^(pKyK+pIu%<>u0|ds~C1;g8pC!QAqA4Ni2)1Qo1#6TgjqS z>e&LKPgO;ebR>lwOB#=)UBog<8!4OA9hl)8cXwSY26hO)R&-xaX4O2oBNZD42BO>8 z!68PMpUDBKd6>C*K9*-spUI;~k96|}2X#K5>na7O+(gmBNxxqMJ=qF4?0hFa`S42+ zms1PBm5fH2)QvMJgL_bP><gyi>%n=jDcdgfYAo6= z{H=aH{ibbAt}v+Z39Ww4y0Y!tB<-cAPF8ma-(X#*pPctn21TG| z11>J>q7Q_>%Yu6zIO{eq=Yg>U&--M4jpi12ma48qml*_=?$x^AWL4AUg8<;LDvMcJ>u1l#368N*+g zDr8E8;eCb>W9YoURd~xc*S7ARXW&A=z4q#>O2e_Y$H=1du*UOpUJuhQAzuHJl}XF* z=?3P*beyTzIi-!2$-Zj$z;GDSChJPi+)aEq!d7pLUTWByL_;(ha7b@IOA1|~b2xIE zZ2U#s!Qt#g_7A4=_S8lwuB>W5yMU8Ly@!XJHpMD03h1~T!Zl~D9y1Wr;$p)4{L_c>?8_%! zJYA$JOE)>f%?$L$LTrW;feu_{KsdKRVLWF@D$@zGY72>Tw~#RzrWmAZMc#eyw!He< z&BOOzAAhuxcK5P129iAe_aIWjcClv&v!O$CmY(glcaFex#E}u3oU-~K6SujV@{BJt zC}r-ZHdUl8v3h)(sMdqzZfuTm7jE_Geyt|Q!UvXQ04W*STZHr%E%;Z%xYDy;t8Y5v*ciu&8S zkBA>_;B2=c{k4XGQJFr6AEm@$>Oc>J=TjXLcj6rUAo|frDypGK<%X zs;_)*zw{S>a5K)*pQj>5B=jpqczCT}E>9CWE9v}X-Vf82Fp8Y0Jqv8=j7km4(T9oQ zJA`8|f*0UwQ&iFkbA}uNM}U4Nfmx#g&EG!etB9(ygV7VVrb}AHp=; zT3X`R7_j(5cgu6=+eN}O|K15@M=)Ik;F)P?v(xQH-C;_oSQao~OfZr7KFD{4sT7O;z&VyYI+!I+FRxk)#oJCfHLWmf{X5!lA3oXc*Fg zG)0)(S@jO%Zu@L7El*b-m<~>=BhK7fl4zNlZqrIS7%*CIWnV1Ur;T|7*w1^+->g>+ z9>zAtV z-F*-PZk8MTvX;%~h7&IAPZaX44_=d3?(Ru5KmN}x-R^!q z415^x{hNsJVK>3JzAA0tbsT7e@UqQnKRk?ck!Rq+%+dvvjp!MdBeXCqgzbT);Y$lY zBl(%1&F#|=Jjyy$f3?Kyi46Ds>;W(YhrZ7OIP@(nc(_Q0;pcrur!#atdfxOK<9BXN zji_CX4SpejxErn`?^!_?7o@4uti#1wI9Y|RVl0|gjg|GJS}ea)Y0eRF?(&=i_LW7Y zkJ@jGObkzqP2asW)ur{npzSvm$I3yR@Oe|3{7mSCKp16T z{#d`=+`9}zIuF{4O)ExWH~hi@KUf#$gk>J&<>&~PC-`Ao#(hyP`ol|4uF+gIDomIWNF-nbD3M0WlbIB=Be{F`hP?gZTT(U)EoV_x z^5pnL`wgTvwtYyOC6P3<&EC9VSjmjJq3?Q<;vieUVbSO6 z8!WT*cBd~IV}daHlrmKU6(UHcRo057cK2|9W_{9_5@Ado51!Dlc;R=-!k=EMnzAX^ zFy;2oL;0SSnlzh!%9Jo5A>O?A5NM-KKTEp(eRav`(_XY6xI}%7yE17o2!=+Px-oM( z(Ld=&c4{=3Kg5YL+^~a}vuTu28YkHt9BF zOPsFF?~D&a_&X!X%4bV&I9K~DTh=kGivcw__I}xSEAM5)eO`E7y*Dr=o;Qzv`qQ}Z z^Zu6Y2fVJ_ec=9m)A!T)qfD^6%BhS5Mh^>4oyWR)zPXpm2*!lpl!RHk{Q9$67~^W6 ztxnvBe#(%bc;I+VoS}66uzoFuzJm)?1GvL~-aI_0r>gI^wBpNVD~&l7fwH@R3Ni zGW7f75ImSBFy6ztpR%QX?WehwsoYd@{Pc+=Z6y!henW2FJ-`pQep{ffQDD@Ve&M`v z0FMzlfA&n;c`4)3RO%#E4Q;&cl;u=Mu*gm>&wv5TrQrkU?0ft z{mL+~)1A38)V?^tt+aR4@MWE;1#^ju&Hv?_@1%car@}FW z)$PK5{^!4+jm8scSsWTTzmBnMDi4SNy3>|b?avkH0Ry9(!2JTk`|0I+CAC}7jX?4Y zE&4zQs~6o~^?Tc@TPn50Y9H3zDMx>KL50HtS$q0r#j6M6g?8Gmr$MYSy6Au_xA?5d za_eB~q6V*QGmgNpGCIx%5gLp-JND@q+SUO>LStO2D3~8B=dTcW; zmnp92$(76LC6goXD!pd|+ZRLitOqs^R!VKJ{sh6t4QVv(0MTkNzjF6AOo`{Mhm8Rn z6T|S9Z8-dWedu%b%QM;!rwet-X)taON770uxArm_CC;cIrE>M6^IYA0vcC4N&-2~z z?CxF)EtuZiY8)`oNpr>osvG2BTy$+{bF&|3>)ODDyRvb}gp|p9@4PL0<6O%5i6rA2 zehy|k$~?bbg{Y5%CEojAF7dtL^uHC!6N&Ro(s8ave;pG5y3`>UoSVd?`Sw!#Yys}p zmMWl^P~+f2iZH4hsW~(9wk-zJlRt-cNWEynB~7Dq7xOj-#ql0CE9B((P;Tz;$p;_2 zFG&vYLZSwv^7y@qWE4eGA}x_+($1mHD>-@cOz@a7old3oOr%LZmeDxtiUeb#SRert zNnIdq0mEUN%6A~T2kkR)DoLIO{>R*B*XCW+YkRP|+mdcaIUrJL{66YdK)k>1% zRt`H5PO_nx!41b)+U5%>3!7|oa|lxcK07YB2#DdnCc>${x~6L@IXKvp_rCGqH+M{l z&A2`5>tgXmgh499e;41lyf3>f+SjFu6?>#E2*BU{v{yxuy>ZM;36; z#IO>fi|O)o+1#vV17>MEXG5W1)H9WLBG6IZtijLAc*zk&(A?GOMC0wba_?2a!8c- zd2zR?&hDErBu@8LCxy9PHC_9khOu4h^|63U|F4i9jZ;Y_lIb{=Bt|MURX5jaq}#hE zUYYpUgT1sbef-+H-O0%CynMDWT~0Tah0}X3>jwtc-i@zo;hTV^qg*$w_wL=1>E2Wh zpB(F{eg{8tC-qm=mYd4f|7L4WlBFs^kfoW7M{LH&8Wk!fixcPS+U7{LCxBY1>xbA% zI?Gms;f?$%7!h6t1VxdsH*aE2D89Vvv!${20Y1zE-m9jTrdY_qEBo^1H(pn!3PL|B zgeQl`v&K2w$vHYF-`$Bak5T#%X|Ev__C<6xZNEsr`-e%>8bw!|({ zuq(zcm!FjG({g*eB2EE-HbrNZpMb|oq+8BNFX`A46~;Uqh3|U-q!~)Y(1_PNs>$jp;R17Cm&}JlL;-3TdC7Vl4vYZ zJC~%HOWMTp-S6K1s~>(CJ$o_O`TFGgPd*gMZr@ZN;}b8YT}G8(2rz)eq)IC~k$IZZ zR6H<_#O0a7Yms8A0?SDqU*F5<2@(nD<3%DxRmzQq=S(L1kRA z>^Z}i&BCF)qqiO!#vA9WyU)c^Mg6#)nf1Pbw^9=p1- zC>FTB^~?qq7&gx-eH{<=S?>H=a>nCrLey2I>L*xZrhL?sx`99XGRrl1(35|!k!t5e zEgo->qKs3iVE)0dLu$ZNe#X#ogvWB)Or>Mh_5vnB3bOp`?5P2qW|7l&IIJ&I&! z%{$nfgv3A}ri1L58d2>^NtiXYdfC8mu8Y`hYQcF^HZo$qKmrB}G8v76zje+hMIvlW zWVuT9ura^@BW;V#8*vLoF2qNiA`Ns#z{^9ZQ@!{m|t} zrSWQLfQ&ghQl)eZTY#6A1uXlfk*ev>u&pgZTRJ+k*FAfs}_ZzcEZKj#=1LW6Uiq# z%``MnB?wGl>t@7BxNBN>;^}*AZ(M=X^IlfgP3ije-xPP~+Y(RitBFbL+e%k*bq-;K zRU&F1Rv35ryaIF?+&!(wlY_rLA15`rxxcQ%m*Ki&NcM`MuSjQFrIj}hz2nsZeK>}U ziz<^6b=CSdg~Lnj12gMy4uqW_^=+lNHbPJ=RFu;CARZ_d`%{U8h#@!6A-w z%if6htgiE^Eob?FKg_$} zmi3H#TBlOBh1AJHjaJ9di=|V=gR(nefH7_4sNiA`O62CP19|`bcja&WpMO{GEaoZ^ zr}I8%&W%Wlv_P7;LotNoJY%2f*d*YreL2CmE9?uv;oag{oc^8lm-)dRaDYS923wG%B5q z@mFIlP1i8iySAt#g#l)B66>J4_;ieguzpsr2F6K}szkA~ZQ<&ywo&1d@x%ZCAOJ~3 zK~y57AQEYlTC#F3^DjP?EH32DZ@nou-?$^~qLe&N1;}h-is3%?~Nr-M^dn+wvjyj@|mO!lDD;t(_Ci7LcNzDK^v|i*h1iX8`QVc99 zvYxxwGCw#t^%wMuhwypoR@m^H*E@OVB z>;~te^{uN$s**nMFp;FO8UbW)uQspx8zbWBpjw^7F9VMlsq6~k0h$CL(`~tM5(g4z z!p<30T8#6719aXI*KbNTuC=7O^SBU2dm?ouMa5>?Nk@?f;~v$EMROvldZKU)3K-}O zuH>6c>pzQ6B#lOrHha<@JBD#GN+rrg7BJQeXB0i=01A|F*ddvG^IIRt-~WIAKRG&l zCdsXRNz##IxLDLPa;MH)l~t$4cM<$q+i#Or*C4msReW(U5~s0@(o{y1k?ie_WV|<( z(I}C8gu8lYRe&Xfsj@6z<+1=_I}Hvo=oiW`R63?|oWbWU%r5=b7}zl;wno)g zBVv26`sI4o=mtP17sRm;11oCT+n>tghmYj*&mKw6Nv9X1ce>i^>u2^N!Wh6rHG>7v zF(Q^s3Bs1YRMKQ7X*`j*7WvlCy>k5B@9upT!rDDw3|_y!cHc0qYiStM5RW6;AjMm;oH} z+$LEFV(8hJ6Drv-6d`EKq0ib*z8>I+(>y(V(tkrKPKW6nLvNve?6y?`!s0E7CWU_) zl{U~X_`cFFtuI`#Ob}+Avcd%9WR1;&^-H^75cH)ab7gQ0J~iBHn=ATPpquT8ckOhS zlJ8d;2&aHQ%hz%>SjB?dJ44k_u_B?RRa#`3)BHBuL6riLz7BXmQv`J->IW4+L2TzB8zz@Kb^Hw7LjhO>k8>J zZ*&;12uUoXL}ZkU9PH(Ca~jKDjyuUlqGlm=QHV@ZwJVmii6lAd2bI)KDOHiE7n4a; z>U?3FRf(rlIECn+srOmJUVotL}{h^~45M8phmJNC!2X0DIAzQ?Hs_T1RO+gu#tM#GXu z@~D-=<71f@$MVj559GZM-qm&nYJsz&K*WGeE#>91F{0j5?tsk_LvRV8dWD5fd?l^jBxC2E5 zEovh9_ca>#Ck?>Sn_vCY+CGr_OAXl`4~}I|1M% z!i!h?N#8&dp9Pves*A&hzDHcQK)Qv)%HzB=pq7Dp2P7vDmz`AO4T*xHH|qPo!Lo93 zCqEr4Y;=`+_4hE6)rb1|jrI_%l_bWL2m_U=5C-&~9rfG=nzY1fUduXn5rYR6WAyLK z^Bt`~C*I5Fm2W=2irEg7TNN;Ds-R;H#34-ebFmwRI!=ey8 zH5PXW4s6y%k;zyD6Nh_oEw?9;+`kdYYqw*$cXK3rlUVA7V?^LFDUDL6F4dH}22P_` zYNQgGraDkI|lH*VjM55N7seDuRlr7Guw8_F7W87z$DnN;(+q;alH(Xc(7RNQbY zS{tuo>Wnwf2yonZR;EaBQiin1IFDujU?R6}Pv!QVJvrDP$z+TWYtgKg%uN+YnIxlOC1lUeduYM>Q3h(KbLUpO5xQiqP(X>La! zJBGdD*V9Vc51qbhvySug92E{gFwT#`TxcI$s8-6D*crbJ(RLlr zJI2IyVELNzxOw~Vm&!U;Jv&6`O+S-?IT=mm$rn%L(PxiTzrHO^PtFhApo}^pc>=#L zEx|;HEn)30!gYW4rRXlL38hF}CWCA`C`94e#MMW4fS!sT)>wfRT;> z2fA6L*L$va?HC`1mk>5#{8nItGmp10?l#YAU(P=aCrM5v|#aoWH5-WP(18&o%Z+j+YtX_D&c4upWUKO~gl zE^MdpnR18kmOo*nb!4}NUe7%&PuPd9C--G8+Alm)S@G&WS)Z|fLoo9(BHd24%5A(} zmQ61GTE&`S#4v7EzuQ&D@EhWsFa39ow`o`~K5cy4SoQdN(KoB(+2!yQ^w|-=mNELX z&k)`S3%fz35;$zsTebHy8o9%ix;x%`CoKdtNFbQN{-4*Hs^J{6^%Q85b?|dj>>WC z1P2zF+Q{=*CevJQ-3XlJ(Jsart*#V-_pYvmNc#tlX=K@!j8kF-QxIvO$@Q~j}IJ+9S4u=rf7`d$3%I5lhK31Nv3>r6> z-yO3Erjpt~b?b)Nw}8GhbyE+_=pE{)2YxX8B3Ko>>pC%TdS`i^x$pA2R1A#U>|I3u z;w)FaG7Qbt$g9h|Nxw;g>;248_-GJ{37tEC!<~?yRsf8Dl0<@oF zN+3#zp`lpHlS1D6x!ZsGmwxH)-`z<|gcy6y=MO&cV(yMmchV8q6>$cf`h=Y27H(Mj zn@ZxW_J@AsdnkVLClAE?bPKMAr`VUfoGA~o3>bs7qh4SGk;T0(F^$;I&%?KDAUh}| z8(j|Pn?~yg(KTNzoF8utZ~G0J_CIzxoHqIX8PI6cww9q zIAI=qhgj0VV2v;&Ssab08Nl4C5pwBGizygSCrY95OFWt3&b!?3T(v$eyf z>L}s5WxrK88rLy{5F2Lv*sRU{vWUk`W#077wXYi_P1LBdPE-upTyXVq(ti(O+uUMd z`fkh!3w+7${dr@3@yvVC`WTn>W&1KMbEF+Fl5PoM^ONf#%Q)NSh0OqI5SO1z5~ng9 zxs5ER%Z+DBU?7_EyT0g{cB`|{GT)0nQC|JQlnB;~vTS9Xry^?9m)RCWh$ER5B8SJN z{KIFteDTGReD?XF%x0-HQ6_OVQbUzZGnc9=^wb|FBWi?PSPO78n5fDwf*~HHP~|`+A$`c19>l7(pKc(U{cV57;H)ygojU` z%Hv00I^B0BAx^9tY$*>9*nZvm1DAI;esF$OEKL`87A_bQsEN3HR3~!dp#ITs{%ha* zJHOcnx_iGA3?MC#snh@)!bVyaJl)VcS5sjo^aX2iot*u`5ym;sGce54hZ+-O@$g11 z=_B+o&4=~Z>-BMZ#X=52VBh+As^<$WtCiLbWCIma)l0?X>8kPTz+a=oVwzq1#O9hWs=WVF}4U4KOIeI7^I#p%;G! zA6CX8=0qQ|<-dZ8l^1^s$musS4YUI`COpFe&nQmlw&Pdzv*@hhL&Qv1_Fe5KdeTjAVpA3)zRzA8QFX^Sj#M>fHO=x3 zxXZVT)WdKP-g&n7ah3_2;If*jx12T^$&&G%>tQ9I>v)XYVOp5>+#GBd@G>FEPMSM4cncQu)Py>KEmo{G&gTM-RW08fl49F2{%& zz%Ia>4(tDlA>}0&DQCaWEWe)r30P^C$`~~cm=gO_xpiwQw{Pt!bK>SfDtB*9WPh3~ zjf!oL7&@d%Wi-bqY9djBYE2}Ic_Ve%$Po;h3Ofw7-c_v-1b7t%4)?GM3eAI%$Bs66?`%x; zuy^&ZJI2J-jS>OBVh>xBlS6@QGt=~%`47!o{{ILMiH_y6M)J_*Z$Cz-U=+5of zqFBiOBv%nrPK&Tg&c%X_d%?0Ol~A!f+y?hFe(XDU#bdaE@kB@%r~gcy;KjJH;=bw_ z&=cPtv7)C6eF$sbjX@E74#{L2!}^)Fhvw9Q7$n&8k#u3T&q_8F7uuNeX+P@$2rYCg zj`^;*?M3_LI0lW>n{QBb(7^KfQ+a$ z#^*~=ycbf0^Ulf7Q^~QLU^8nTvA#mB@a{7iK@p5szRltI(qyV2=ZF8c{Z;T zL6WT>)dobslmORN+3H$_lxve_^2wK_{Na!0^23L<92H|3OD#>sCRC(El>%ljFA4UW zVrg)3t!t_~6rwQL@llC2>Zltnk+{wzL4>h@VG#+QELpb?N2NTP#d7?^Mn3_dlN&dua$|oiH}(^~Psd}G$Rcji z!kB<*!vR~06LKlbSdNb|D%!{wGhC25iA|)qoC|hm>e}W{yr;Nv<0^X=ouTQJrg73U zt}b4Dfo0L=zbKO9`LWbRB{%LJ$Qy6I<~&`fnkuY_Sf0*~<*+WKP@8V#&o(@gdS1!X zPrp!g5$uq08J&hIhkA1>OR4Hcik{(1RnJ5+HAVH$F-nH;-4CN){84|M6TIR5e!S;- zSGd7k(|_;7rYv|@=^ufx=5j!$`yVd}q~1t8eWq(NG!f&(d{_5@@7}Kr13SjVm7(_f z03Y2v`qj9RKd1VVMI~`ntLStAS6gyv%36N>$3K*uO=J?u?BrOo@kpu`Gjwj^VPbWv z0Iu9_qIF_tJSSeZR#oZpOyV?`N{!@jI*jY7g`}#NNSDG*6x+0^+&XwH-}~;L`UlsC zjh~&IK9CRfqy$?ZWd*?zOPXZPC!u9_v8sum&M*u+l#fh8|3D;4!5-~NwXvX%oqO9-;XT=MZq zYKS!asY6Uek?f7}KP`^9uuU;`9yqZ{6WxG8z)96$j$9cCIpu*lhl|@75m<;;L_0?k zVH_cjq^wJ~xYiI4{K$?z?a=3N#UWH8vjrzs6&~PKastATa11A%b>RxEf4OrNC&sQr zDu_UA%R30xGBZXEk2Etn!3JI1eISRg^ zk%!@3jJZ{%MCiCC89h!t1Yw1KftU7(wuOO|E&b6aw0))S-ctH!Tgb_5E=4nwX?7DT zTMfQtnG-uzTEY`Ur^?@})FAHqiO%uf$Lm?}SI5@b88PNabzXF1)0Z~3>|+7wj5H4DvU#x5@(Ujt4x0Uc`SeUlURQAuvYh<@F17BUf-9!`b3T;m!eJ8YX^EG&7#tA)g+YZM1Jkpe?>m~?4kVOKl)>7kDkhS zye~x>%d9~)B$J|HYv}AMsAK_BaICSYp{&`wnpVHsE9zD;S7={5ePP|EKR}bP4#apI ziDDUzGC8<;AbX=$_QsLy?`3iu`x28>^0ZOO4%ZJ8Nh+s)0Gy(zRo!QAB62jUWj_~b zP)CjvwdsLdPTJRLNHZ&s+2!@oT^0ZjU!y=Qqh-8|!l4rQQ zY-J&deDdXEdGzp!6nj&NqD;m$MqovvNiJEQNYj=gc`MmTEVF00jD=QcRMNTRFf+@f z=&9OvbbzO?XaH>s*4`wRqADeuOl7jS*Ns7Cll11>Zv6L#4)APVaV>rN|GMvCIPiJb zFr=f{izKj|VC*H@UZ}{{>ifR)GcZJ_NF?BYI z-9!+@lI2d^ElEa7bf}12lIrI1{SV%h=`{K8H)ON>bWsd^xH+M=-)S0D6D>DLjsol2 z6WS>d?YA6^DZx8&t#8;rHL?E}>xLbbeQNV8kSS*wo!cN9tj?3>> zI;za3gnX78E{o~PX=UZkpNmTzN7Ano9bZCmPhGm_+@KiTkSSqd+uW72zfHso#0hcR zPY$ud_mvCj5wETj8U@2RY8w^0c>r(xLCax;OxvSrRlM@ztM!w_^-8fkT7h;|bCH;xG*0xcUOOlRM3_prF9bQOP z;XNRe7=3#z&Fe`ihGyL9u}XxXO%2zq+o7+?_=N|*Tm>||UnN??_I>Vrn0owAne6Z; z{Es!x**kLc6SNT>BH)Xh%KozI-}U!+Bvpm}ek>`QTx=s(sYuOMeWCQ&Q8|`Bc~r?C z{P3B4`eiGUOk|R#GMgPq6_33n8*3Rh4V*-(3Msan2KzOTI@=ng&#ul{jGYI^w#Di5U z)9G0LxnKKLdGzRseE#TACdpW`(L|_bqudzB5P`{FDQ&^l-qj;)fUf*upf<0vHF}}J zE6DIa3`*wXOh)5e@^LJAo=Ki2`eQ?m4TcQcXVjUsKjxk(j;m27<6LAkZe#?EoC7xw zEtVcDR0BvmoD)+!Rc2iampg90ck81{x;S^H*xmqlWXzxSJLbO_2@S%_N{*jBk?}Z@ z*B-nfZH{e^5`!U9L?WNfj^!AyA^uQmQHVTh<}xd4dHC_Cs_L5EzVGZ=s7IAj4c{X{ zq2*Ra3{n$ITXTf#Zv&kdVBS6YG%$xb3{kuq4Y_HsodR^V0mj_#atUw`qZett@UnVH zz4OWu;^jJ?*KAv^BkNrrmw|z{ZKI}c{{se*PBwnQVdKYXCwg)}{pcquh6lmMPhIz6 zn8+_=mM$!hO_YSGKAWF>l6rzojG<9iNYkn#LQa7@g7lIzeE4&WXHt3wDNAj#1%OCvcMECCx^NG=+m+MKR*`v;U|S)q;rxZT!oxl zBXNe*EK+WuwvrD&d{2J)Pyf>rXR#EE6XkN?r32{&)(+NI=5{ZjqU(c7_-w@CQchKVGg2? z|Ly+c7Xw#+V$xJ|v+sq}X z3ixzNC`K3yI+pS1Kk&J%*~(;dAig zwt)}=OQ8=vMbf%%o1S)sz*-YO#NnDK8Vr8={h|L(M2M13oU;$GgW)?2r(;sd$Xoda z-$+d0p+kun&q(|K*?X^N+qOHu>pSyWYlo9=zE`?IS8A!%Nv&4sR<~reJ3!mzasgGq zE06pS6!sJEJo=3nKQvW#Q9wUn%EnN}Hed|cSS_r+3OAg5&Q2@LOnrW1jJ4)od+l(- zKDxKH=Q(T7ImaA1{Kjwmq9J7d@BmT+l32HmMn$0_PfYD>du!W?^`jt@kQ!nKhf>Ex zT(8Pm@0;3sR{YQYH%OMABNyS;t})_75P`mE`-b!3N&9dZf0)m(Y~loCxTeBklbZF| zs;O!nO+nQ0E|r;>F$WL~{K0u{tIn*`qisk&%u`drFeA_IAVFCWCzv;OvG1L6C>qx7 z>iKed;Iz50skC9-;d~-)_{N=I1W+{tjlqr)@13cOafAw&fe(M63}Mf54=Nm?KIG+K z6!ofASEvXAvpV%rp=l}o%a3|}c&F9FgHG57L#krlHLBUDyHtI6fF)%w~ueqA5myQly2U;aSlbYDByUs7K>!;mei zlt^b7CwKysKB2xwurrl)`q$&5CSe8Pts7uzms#7Zyh9IM5hg-U zdU zi~(1k69EAAz%*A4-vgTtYu_x41@dbNde5*l-yFWs0t=4ch9riI6u4vp6A>)9wRt zdgEdbNDJ#WB~Hs?J>1&w16_YO8y&RcGB3s>zyZn$?YHwEL)92RUm*w) zNJStClc9raI?KIASz-pqkgD05q}G0WL9aW38L0P+-#8}?PG?^9&+nM&fO z0fzsaVLU2t_CqeY6~n#`ML~E3`LjBh^o+B~0%0PkAcnYU#)+WQ(X`Uz$F)XjFPMPa z<5)@FDX9~+PtEOP1*kmpGXsd_Vc+ zIfbl-+hu3~iAN-GnD21FnIFKILTT){robWB=FJDoWq)k`e4_FJq=)u~yU`)gac_`b z&7`!Iie8WRTYdC#q<{6{TyX>5l$rO7vg_3*i6fx5N7}xInwv8?X*j z%WXF5z@esW4&vPFE;IQFaKfg>6BfoDTYE<8qJ}qYTz^asV1EN3-l~l%!y9W&bZ6RY z_R~^_U97LXHPH?>2FlXxh+(G;RXq0d@phr#`|fY+_PvMt$xlDg&d#nfq?@wX_G73t zNIRjz03n2nHiW*i_w{*1;|KfeiH;uz7~zo#;iP5Cy49j;RF$>a*D32-MMXb_vBxF_ zo=(6?8k5SSk1C|}TGvO`H@+`jJx$EQRHGf0X;^`i&tMjK$*2QC6qoAWh7L?WY*Cm; zFQmQ9Mg}QbEoMh5rw4lF+O|IT-sgpFi@s_Vcd7R0b3NEQP*wKYDl)_8tHu$OpeOXx zO7*Q$NzPXXtQ6D7H~6$Ks2kL57W z;q!)^URaQgcjwlQd6V-cBhk_!RR{z@ip6;sxgt!wu#s^ET@fZ;aECvy;{Nnc`($2} z|Ev1GV6j692JmnIU_oUu+{U@~?mt$M72Y7C6S)G|!Z|_(0A2j$H8{fr0OIoYn;^#P zD9bNe_pMW&7Q)D3QKUwV?YgPndG{r~{@P^kZ~d*mwK~}?3%YuEUOnI}@JA-@81f8b z$3_~S`4*_cAs+X$4z8p>bMXA3cUXp%GniALAA@OSMKk~Knh`F_ahtvqqa!>JL#VT7 zS1h>;4YIIEKbSi*pNlVqd{_haolRy?mr$OYw+?v&c}=kYho$m7_Z(F+1HoCZdC0-t ztC&~Vr5hlnAO}d%;6ZIP%8j$%w3WX6>%XL1 zw_Y-2jqljAaeCs|7RZiC)~wg{>YW~79tE{KBqp5Hgd$8xnp*jp-Lz?Lkl@(3pP9q? zAK@w^sT7Q@1uq=TGi;Ku&buyEQ)QZ$jyo%5$`UN*7q;KQxpM{(5y7R+NJ6G#oJq!uj@lcY%pm6zwcm2)9Py*HGiC; zW{e8cbIHhsv6pcGZ@bj`#Ow;RGS{Be0RxIXhMsEzNhxWtW|NpnV>{u={YI4dFf&GIYj-K+OV)N(@hT7}xCWH*X@9Ri{N2slYQN0t*X}Q(t%09P;eLsEhlS!JS23#?VZ%mTxS_x z;^vuWDEe6r4qw+Z&8LTEGiUtT8_I9q)U53^#>jc!=>Bx3htmaA6(KFLz{N5~IpO%X zk!Jf-b@N8;wH?K%>tKtd?}S_R@p$a(7ptr)P3H?iz(w-KNrNy(P8yLu?YyeVuu-nw zw$SVh!C^j%6GdsP7&}t*E3kHuXqjdZ_Pigh%r$rev6{=^h@V3kJ7@el7_>-Hq@GyA zc)~aX=HRx<#GP1D$lzREFR}-&2oo=|x1VEKhdW3AS<>pOcor~%1b&uTlpUgAZZ+Py zeOq-^8ATgz6c@-nK!Od^T`Taxf;@3hHID=s$~D=PBEm2C;%%a?ug+lh(E14WGp;R`jOY((?pC?4~GZEmu-fF_6_GYbDgz-ekC4ch?|+w z#i#2N>KxiStj~p?HxMOGO*_Pv2a!(p7#|5YRX=6K(GzoRMx*zX> zFuq}Kw!I?=+SmrH?Rb(G_D0=UldM@J{=yz*W9!##+rq{59Aw+KB2|lCGmuE&z@!v& zhSLTFdE6;$b>hV!$}h~LTTACRH_WB;V;+xTb8P^JkAJ&)mO^Udret{rZlcP$`F&|i2zhRXRFsJS?H*71~RE%Aki4X&iAK@st-sv7AGurq+=2P_j@7UcoGhc zS*#*+d+B(mS6ks4Q)(6*(w&=3>TZY4q!bVP%0crz=|$2K(q|KVGCq!lx`3W~XDE zrAl6ZMYqejc5)kA|+L)`Ta+Vn_ltuws{*fdrn=i zaWOLWSNaW_?P5kbr4cpo83IlerVjIHg}qsGPW@x~(FmkrjKJa4CxFMHZKo!F#t)&- z*Rvs#)dv_P#y5!fFBsT3>7Je=dcNm-?9>3u9I)jshkCL&?8S2K*xc+LEY9F!Y=1F0)m8jcJ)Yj6X zl*$@nVXL@Fgkf6L4f?b+iH;xLZB$lMeevxbeers3DtJv(N!WwwY9&dn-}%lrb-2H; zfB4USpdud|Cq1KT4NxE4!%5aHiATp9aq^A9^KfGL(am4iBgWXqwo%<_QP#@ljSdd6 zSConKa*DJ}-)fO3Dhh`$lfJ4NJMbSum^dtTbX4hZTI%3%ZqgJhBi+m~XB5)xU|D^J zwK@4bKyQpt5!L}?0g)bwWpHSdXyKVXvs|dIYVD3PwL262_~CuM7T?r%l4@Em^r$YC zjJBmYR=^uo%mK!?sT412mHP)u`dH}}Hn?2g7$`+z0>hWC&w4Eu3xlgm{LL6ePFmIG z@^GS^Y}&C9#+3aXgRU$q@^lQ+rJ>~RFB6CJ&raMGp)L*<1Va5xmWJy<2+UAY(kjW=G~FR1(L!JS z>bshZTJ>di6!N~hUtSMz&^PL~w;=5{m6b?+C>g+ORC-g;aN}<2LWH$@*ud6;kGUf+1pPwojNZsWP)UkgKh0MHvVW9MjH_MGmMoCqdTzrr1WcSq;y!k*cQD z&Nx$hbf~Cq)n$d++8ts!fPg?55@EXK=(RG>5vN6bosF`Pa$Hs>CI*QBXre-OH&cSI z_Z~^0)O3?^JxDwFS$f1I?NH}7UE0kze9=tnO1PWqqf8xj=YQXsZfP|*cm(b&$imW= z#9#xY|4yiGu+b0V7(z2R%b1UPkG$g9o;4aSiyJyJ1g_oJ&OK{i8HN?%XSi8Im@wi5 zd^|&Xu}9){lo561JADVT1VIz^n!+^mvbzhe64c775=`6d5%(*y1q`7g%=lys&2?FZoaW0cG@@1PEb>Nw; z_J={y8y}Z-8GIdVFMe$!ChQMf=)m`#iagiR;l4N(A%c!La03xDPLv8g_(t0)^9fyX zX_Af9=WJxyCmHMGyHm~Esa}6$TazME!rFt}i1Y+RdQMwCt`1qPxk**fcg#Cs$dAic z^yGX9l7)jt9eaEVoOJ*b2F&hbxrP@!0}QXV>7njisTWs2H#T9uxHU_@0VcUJPPPTu zH@w#S2l(Tza398Yl6%XL!PE}(8kilfjXBU@f2bzjuzb`QJ3E9stBy#E!Vyj5T2-5> zYR1aiUR7Et>l1BfQ^m=a<`^ARt+Xu^*}MYEF~5%I@9O2&2<6g;$A}YDIFD7$7G}R9 zL0!VU5XEM5!8{Q46DzAvD&3!L>!1Bh`rznD#a5#1DA6K*sO`x}+uI`*qgZWhW(uw7 z6gQT5Df00B82t4UfgR|?HIRQQ1$MvUcHvM%ZA>brmNZ9RB6)xZAHkF;~` zmLjMFy;PurH)|Ak)XllB43b>d7C+|p?AyK!_l*tnAnjPfEgUj+MXU->9qjcBRE%34 zL6q35)kmf3w$rTYbZu*Fc8us4Y-!XL(iOE1k6P^=w0ih>p~w3RRaK|yJkhL!zW8;;`L4<;(#LlePF2Fx)W)ih@Ve3{ZyFuNxh72^%$Uv|f1t(DW9_{3rs8f} zG5A&N_SwnS#8iHyeI8HD7+YsBd6l3rAAGiUvoJi>RFRSvqy4Sf`sjKrCr66v zx#B2SmBh+m*mkX&+`*%?M@0r(WiuuHc)4nZ`CmO>UJq=5YL{2oRnE`e1OMnB_36)= z!~YcHe*ifSVh)abadd!8-RSZC2e#2Xdx^pDl6RW~Dr=UZq00BlvcxvKzDM7!*5}{6 zVS0vLw?J&r$q_z}N?hgfL_H9Yne!5HfaD5@Vu2ahDJN3e}y1GX6s z`s?w-JLy9Gxf@pxak_5!M16_hK#Z316w-S=V~|&Wh^@9?vm9Uzm-Pf9^rtS_hj<`76K<(+b8;1R}V- z8NW1L*Cf)>>_FfB&adjd_uo|8&NZ2g%I#l-p+p#oV;)wf4^LTjiP~f8^wXi*Vx;gy{Z|L)^V;%h z{eH4d?f||i{L|WoQ|onNyxaj2m7cnWQsD^Bmi`>rd1@JFeBiK-0Yxsv!;OK%l!4I2 zdTSCRtxfAfKmDZC!$&hyO==p9SeDwkwxukKlo#Mpju^O3tP1Pu*jn~=g6Ozu979u& z5k4=vu?^bWn`l0UF$aPEk#g@mdaSnFmUeUP<|#*Y)%Dzn|MAw2zW4jTt-a~Ke){1( zz5LqSY8%#htfD|QWbP$GoXGvK1S@VhwxL05#3|Cy|7LX2JkNpl_69dfBQ`K5%!5{S zld4=SG@Di`(#+O<2eGqp_9SNWRtE>A_6|!O9?dnIm#Q(Y>!mv>%WxM6@6>Hjr(xZP z&m7os=Z(5`7(deT3*(9kc9b~WquigWoX%8iZ!5pCYYY@@B4CrNHACG5F~NX~u>g;5Qj{*O+!c8LFjV*06TV*z4aC3x33VwN0-g z%hgmf zh96FO1}<}jWw#MLp(*XmK%YBpQw#;KjJIZatb{FFU~ zJ;IFenS@to2S_~70M$)GN1c+TG?^oEpE?fV^m2iAqMk@UvZm|@cUq|$Y`HMbeWxYgw1miHSCMPpK>GiEB9z!d~Fv z|E4LuDJw+uQ>3qeAtr_8@+}vs9?n{`rSZzR*UOVc1)g*oj9qqm@4eUb$A9!){r$iH zKkD)Q`?~qk>pDD|*|>neE&0bi6pjOG!mGAckE_kL*7Wg1)m5wAH(ytJW7iqk1ZM(nGl%JaBTzU( z293)Q5;3nLrKS(|)yAntTieH~lVqtGzBF}i)F7Mo7-7O-;IS0`B`|zWd~-Mx<6-y| z(jc7QX``320bdvbyY;aw=^bOTZfUOC*J=gvAqA`8_p>7=gHbWv-L=-$=!LVMtf zF!4gW``HU?+xEXeWSV0TVq$QUd4`e;W(uMH;oS$S<_m45g&I%YWf6wo5Gf5va6piU zqTp6r4sN)wvIBstKL97FeUK+03NIi#HzxZ0d%J4dx#>AdJv-3Vby+>|mL%_tH6S1q z#YPdvXIOL?<6+ovvoJtC{P+ydBB0E~KoSV^oBV?4AvHLwjpnM-{98k9TM^_Cfo#{r zsL6Mj*QR=}htcO@jjexszVE)Xo-|WCkX`(w$gwBYr5jYGf z^l&7KHOf+@Nvo=z>-)d|9liC|H62Xvsu*o)yajhW!laJDqQ>i0Kj~OJY1f<=|9P&L z^U6ByJAH7GdJqp7ZpU!H7l3IG(}#S9`@?DFo)$jLZy3j|_hE>8MqXjoqRYLaVN(zC zF^@xDEZT@Eaih@)sqI8_EX|u27q6@+S((e(tmsUXyTeXj zjGi@TCpc#7b3e2mRCR5=heOf@PjjI^m#y9aPnO>{J%sW$eY-%ID?ha70twcloT&fW z_fNyC3A)%>k8w0(69)a+4~N|c9A^GIa7SF!eeA61o56TLd0&BdIo!ypuaOyqFF4f@ zO*wczJc{&#kB;yQ8Fd-{8S?;q%B@3AJ^*L5(Pnis4dbq;^72FmD4n5 zv6>JdQY;Xw!7~?LJF2pE-aE=xi!xHx#^!0n zaBGMX9Jpye#P+CDXN2BiXPtZo?j>n#1bGL4S8-^MdBE_t-}?DN^TU0md9Iz8U)3T{ zrOMe5p`OfPBqSWI${(yDjCGBj1G>dR)&5lD$(EGo>K3iiBvTvVDmPV5n5oS=4@jtS z4Cl-6c~#4kPebgIRm1$vG1Tb|SChh2M1A{~<90HuOA85ehc-d{GWnRkaX4M?)O@41 zQBsV(9S&C&mV+Y!VdtgOoxMY4+ta5+t}d;4f9W&6B20XShWPLQ&(${%X3d{;NoPPD zl?_C|fbCFblQ>hesPy>WeWy3Z60=P&+*d$|y-y9LC|f5-0* zjg;pcRD09;UE!qIxbX1GL`GML_cJx%f{CBk8VUXMyz)C)eJ8StjZlc#T-ZN33F%iU zPa`6%Vx0YSTASFTHs#$`5Gp$}mWEo75ix@l1IJCXLxYVB)HXWhBgh#t-RlZ&8o&GU9kbgxRyfri||icRq8(2wJ!D_;Ye?9Xs)E z=!%VF`6NV%^A3v}%3KfHScmmUe;M8bKv)tdJTYlWh~RLGCm%cSu*{Y{<_VUZN*;UK5E4(E~n{Kp5n{kT+G>>4F^cT(uaONpwUgFL$sGUjeY zk_SH5&WP0LD6z0faz<$WFg!CZg#XaC67>h|uoj%Ew9Yk;Z) z>IyKlS?dnF^im$avg_@#deTpMtOySk-pwO>ta%<`Z^!dQg+WfKX%fv-q$_$AX=4O# z*H$N8v#6a4SxNjBDXUhfOCx<@V*)(FEoZYb=Df+3=6e4DQH&^tBmuaZ$59}nFdld# zikK^^RnGQQFQzJPURQeknoxQ{vWE0FC(K3|APxiIj?a@~XQ!!^Pa@6t_SKcGCa+#s zYtmmUD4!RF5hlVMK&7Se#NZG{-Ot5QmQqKnmQp`dY1qe^ZGm~QigEc*VSWtTGAz~l z54g&F>QQB>)b&m>Zy1mC*mW_6SJ&v_;arowz4O>F!z`|zpFb)?jNeiGBfCdksa3KX$y8$_Z1Kei=1y5 zEJ8$*LnYyy1;TgADIoIA34N^Sr zaN)jDG@Gh(59so>I;_yQ5U+sbpeZ>2_)ZR5h^MQJ+N*a&dAh37DOq;J)T_0lir z{Yl2+a%ymXu3;|IH;9f$*i!KDn);h05r{I2=#nn#u;~y#>_063Gu9TD_#Gnmj`Iz1 zz&O%|CMLGF+4G7-DhdqMMv4~3z%(xd@WnVNL8OS`lVMb@+R`VtJMA4ddg)f8-RrnY zgfQydkPhqOW;HW=IO|WY39D=9vo(T)<+r{#LfjK~gF44UpEFV7c>6ZN{gdqr6{4N% z>BG0@bq{^HUQT!q-%l&gu}j<$F?4%mW6Ru$4F14#CLd$403VImHJqA^cSt=f3B%3q z-KMht6nc!I!q%driMs==(W#?M33ys7{l(ozAKq!qNN1WZRHTJ=c1KFmO8vqgdTnoG zK018LN%;jBw>lH8kB567*7xLd=s)^1JQHixzo9iJ(-N}63jKG8o5l`b#Yc^Rur|uI zkFDzcMqOPi-icLgU01uP)Rwir@r|!)HapV)@=yMSsyX{`Dy4AzBh}V+XE@q1GLF}G zRhoMW5}{F=nvDsF@a72_CJ00*GbzxktDS4l2IGzxIZQguIp8DBVuS)u_fS>}Gzh4ZTaA#LCmmBu>LTgM7sm@PgsoTbB8p9@g{bJ&aQ*!pWvMPql1$ z>?7bM5bKQy-Lqqu(-xBgB|dvs)kb=BI9n~kkm1$+QhVTvFmb8f`}{KR-hA_O)n27h zvSr8`RBH5O@q5fxYvM<3rw6z1s;?U<&P4Pr*77h9AEf2y>tuU6)DeRGrVLWj7(&?@N5r!6Wgc4te$KClg+5v<{)t~Nl26A% zqaGfA42X#zX21Opiw2eSk^P#t`kzLe7$$vA&y=^SffIqXtWiD7Qqu`WG#{Pie3Yqa z7RvHo-~8sU=>0Fero-t2*Mr{#cWI-*7U}Y9zm?i$`d0v5VXoNL~T1e^(7|W&RBC4 zfwPFUcV<_sJd4aVHWu?2a}GbfvJvh@aYbAzM*Mk{tE&?o9YO4BG+V?b)t8Q70N2Xk zc!$NcTra4Y0YX*>5$Yf2*KpmQ0s2mBvJW4wkaMD5;^$#oj^PEDSmyK0+SbV6^c)UO z5VTOIz&nc(tC%}J-m=X$?xzzao~E8=j4*aYiH8pt`q9rKO`BACCXL6Pb|#&<11%S; zgE#84MnW+a-2qW-FfYU0vo*U8_%2Yq{KhK9`^BAEq{BMV7otw13_*ISFH3#*dtcYQsr1kP#lKNLzV0MN*cY&)V6h-h za4f_%CkJ8IAJm&)sJE4E`$=YY4G1@(6N?Vh!r=i4wm%xFjv-KBEFJ9aWCsR^yQ}ft$w~u%V(rJgcKpf!d8h9 zCOm_N@d)@9^9kdk3EqABt8?&0Z6~ZQm(Ro<{pTZybTcGaL3~3fPzjJ7gSj` zVT=MkeE7%?F&zGeKHN_LoeS0o-L&E2hYB0sIp85uk87YWy#JQ++yOd6AQQylqQAIc zF;~%^q6glvZR+@D5)Q7z?80~r!@@IjD(KX4=bfKF#fNC8-_O9z!<^&JybTu!K=>BI z&Z;9^)bQO|nGUH=-q-V8j}fe26HZ)L7kBtSmNuOHeFmZY_56;dS^xMcd0($1qVnN) zRu$LNofY@AZ}i(R9|)=tClLEY>IF{A^x#16z5ABF`+MKee6g=AkCdgkxppL92ovMU z#E^FmrAwPPgE@6t`Og}D+PFV!z9Bt*Gwh!b&OHz)hG9?pOglJe2Sj{RKBv`VQ{3kj zhSU;!6^9D=-qeA*A`(vswnZRP;O-ZqL>lLgNN0u((X&3#8?SBajW@0<&06CeI*KKn z)Uo<}t~j4bd8@X|^x$5s5B_4V`*#;=4A>!MtL996bzRph$>CW$) z6)Zd!_bKM{WzWxJ_4|~*ggN8pxPv!{;TsWqaJUb|YHP-(z8=QCU|TVqNcrGG%XwmI zM$(;o4|V?tpR}n)X{uY-$J*YmRn{~7QaD=;rl!Q<*GZ)YFB+jOXH~=I8z>6iMqH} zF^cqizxQo@;k|b>pU(}JBf*HL3GSwz7e|gzX+7%p=1|SB#;kuJFmMR=^#WcZ6~RS3 z{sHd{Uv66SR)_j?RX3`uN)$t6ay^^~b-Bph?2Lqd^K&kc zp2#!LGm~1I&t@tYbEV^4`L%7cqSRH5ne=clXi%ErQ`EIrTeT(`J4ZF6oU53O)f&?h zSIXWSNF19Q2RUGuhkjW~sSUE-_!via*1)(rza?H6a74z)d&^=>XcJ7a@Vqh4pKG9l zz2JSO0_ewvDw%BI00x+(I3`6l`sDq&HsUXR;cgZGrElhEzk!PbUB@+Nqspw1CvBpt zT_A*}wyCt0Pjvs|yXqE=i3`G!EPE`MBPxd%0>>evCjdXfkZeig6lMxG>9a&S*8XZ&%V=idf+x++S)~Cz%GhY zrFo&c#6{o=nd(89qC|bmK^#$Vj4&n+kt8NunmV<4&U{r=*?J&uKoF@H{l`DdbLPHguI6LVJg(-O?94fjI#!Rf{eq@w|BY0I%90) zXZo>tzhL!q2eV+Vm?8yrb+Q%Vm}E#42)30qu;DPQkbe$ysO zYs-%CPRtj$9)2b@g&T_~QBz0C;)&_kI*TtzvM?`N+aI6|80WT66dQMxC492&r`6-M zaKx(Xwl$Y|NcSPNLH}XEmbJJzdaNwQ7#nLZQI-{|YDeIP2wt~|q6GU8Gv!&UvMbf3 zwW4ICl%1?gwUdEV8)-P&AgB(mY<3U8j;YoUp?>tN6eKkXM79*l=l4Gh6*m>w^>FbnEixIJ+mr ze@-Mi9uQ#uaDHx@yTiG5tdy!N?04p)ajZ7(lqok@Tg08B7ByJxlEn7ySf3aX%9S7f z8Vtj(0^C$D%5Q`$e@IPJr*2fMRnr8Re>BoDu{_*`=>Z-@u-Hr9q%M&G0uByT? zWMX(#-xUVu(2j^>jAgnX@Ym)U7?*j#I77A2)~bW+w&4ukZPyyShwp?he@3v}ybrmt z=ira+04K)pm=>@wSQXTFWNHw-aoC)Z=upmuRXG;Rel%~oiTS}wM_CuTd z5L~cPgEWM-i+ZzfvZuLy&(t$aZG%I)1BZ+!k`j$`CStghox(d{qEk8S+FGbxaM@fO z>>ptbf=3T=X{!UaeF{{}9R2|QOnhv6V9TH_Y135Gy$@`mj9&eM7NcwGYKX3LBbKyn zXI@2+MB&Ff^<_?041HNEySuNVO_l8IsB0tD2{wfw#&#MNg?4s!Y-7L}CT>&@_K%F{ zVfYez95~E!uNx3y1ODJ-SZuM-gJX4#cW_%cR^31ldMhW&m{QL^*$@*^q z6O1CQ?+7cdis7xi;Lsc#C!eWpI{RCT4YQLePeH7-V)&yF;nMEaAz_J?}w zt=BZ4Pc<5k9rEeN#K9m(d|{kSljjM=X@_o`;C#l_tjM6u2EYT z8s*!nyV`W$N7s5?zkZ}VYL(Pb`(iEnUH#<4R6o02>fX^@i>Q=x4uhFebhObmFENTo z{pdS?sOUL{&eg?-wqBO&hC|>*E*4GrT_pZf#(9#tG90I;Ebix%>o0a z)jl<^>tH3#Doy)He|~47AAYh>9PJpP@cK@wKl+pJ>Q~->3(J&>nnX!DQkOtjs?_$S zCR@2v6BtP8($E;!niz~Ur1WIdpJd*jOnp4WtRbNmG=M)L#zo4(4d@a+c%p`-W3MI8 zq|?y>MlVa{lWk>NTShdZj2;^tetLvF!adZ%3{O;*<_AYce9MuzNOH@Yu^_(n6`ns# z3QZ;{LilO@x6J#T2ijpoKD_p=twX+1#-?jXNZ9oKNy08P2EJ}V9ff+Cs-S1$h4O}~ zjv*|?O>U+uRgTahFX(>3o%99O=Bk)edmu^TukaCFI9p&|ygdMz#nDuc9zHZ+U;qQC zgr3>puyGoo2!+}rH}1OwC?-}XL=mA+pp$1N(1j)H6r(#`qFc98z4`i0cbFTnLH?8N z?LQCsUfnOJ2aXQb^bI)p`^{iD?vx(h&zl41)s#6h{GAm))P?v+5O4(|!&&Ku-f^ZD5e2(bjbjk^4X{v77w!xe~mY1(X=nLG4HI36nCVwP^Mk8Day1Irtc^ucq z9OmkuO<(kQcxeCe(2Ko=vO`@rr3!KQHjKCI2cO8kT@wBqHW2C(eo!jtLN@xi%as=+ zEt*nEhClgMlgUKtD)seL-~at@>eqhbb7n7~ZENLby&Mr&I7v<~9Ihc_gE+CXFW|UV zoBHHMhlMr|$KplSVNm{`gzDZjAQTRk7l9SF^g* z-t0(yTkLet3WZ?*>|1A4jgQSr(Z(IH7ex;w??v(buws#7X@`@9PB+eUE z$UYG3!}~?aNSe!xv#B0NoZ$3H|KI{TPE|%bdN7^n-a)Eq#eUxEm0M%|JAd#E zeeSgzs`1bfvsX-%CXpuNSamsbumc91sT4SgD^!@xyOSqagz*pe=h)Fd|@aShlw{BaI2 zA}>-avr3DDBgMe?3`w%cJcs~yxlr#Y^4y-O!_m=^5rl_r2+!eekvIGahxg$p)V)!! zByC8)sZWM!o+okQSiTo^-SJ7e4rUR^J=2d+B& zg?9JT7SBn~ zR$n(itpnjru^8_maNiVX8Rj>I<@*4U3rLu=g>vz!fhqTNg$sftce??dF=YNSEs&l*^qmsP%eZ*xFfZ_j;UAhbO&n$|r<{ zJ9&onyPiLU7mpvhPiyrI#G>_d%lEbT%kWbk%pD|f0K~|P>?1(S*aIulWMr1X+j_43 z#~t=Z&Ja@$uAz^zp+=AKZ&IYcgFM=Ne7mxS~+d z2o*H&q%eP(F&Di)tz$)-@T{|x#`AkAE#rr!GgNHGqg;!&*AMT_^yB?r2engydGn23 zeeb(p(>w3Kthz1DQ%4+)%t&Q{TVQW@V%cYS*6@UhXkb(_e7|Ua4&$wl`S2Ty}7rJ6SW9vKh$*jxno8)0GP2RwWa z2qc>WSIC1qqOu?c?ipp!#;o?^o&hnt;pNOaxsWig!}m>_pp^qg<#$u|BJ;`aeJHNy zL0+4P6QPXDx^Jonb>DP_@b&vJE-5#s_OZy@=N||^r`-*?HUfytG1L`x7=C%tsA=Yk z+Emxa+h&>l@q-WfDn+vZ03ZNKL_t*bt#5oufAS~aQdU50I#Q8g2-8bQBygs^HF#t9 zcSg_vCNUpE8N)U`?X%5+^#k$KX7(vax866vZgj4h5W_tYO#TU4pKk#Do+j8tbsC^y80P-9Jo~Z{^zBhHKubk9(o~!v&$;)+lT8 z6d3*~>&gpP$F@?oJhYx?eA`E|YV z`os>5X}WF3K{?cO;HAH?H)0Y9s13j{^J*M?TZefUuJBsKFi*mr&xU8$Cvldwq$ggf zcb2S}Dxr?%z7tqz1eZwD{fFw?TG{S(#k;#Q`7DzP#b_t05*(OM{=&TMnp*YaeIv|H zc6RLmZZ_p`r{1-Svcx15=`Z#I48qQ)Q+E(wtM#zmd^*nTS&JNA8H)^8q5dH65A>nE zA=+ugiSYfh?kjs-zJ%Tpxtp#sX_jDfY*YC(sZgga#5b?57uo|?gozj0-A`WFpZ;l| z^j-f?4QTXc#?I-)o8Mh$p?-RJr2WTx%Hzze?sAaB&=Fk9P1iA?5sV`lTINKtK=|Sm zAtp8jWPy>Ca5`!Dp2li%o^^Wj^=;j}H8$g$m=7~STi{a{J=j$4RoL_HftNRC$RToh z`SA@#+KiI!{k#XAyJg%B4`Bn`@W};*`Qr_6_Hd5|VZ(If6$om~LCYIYGm%uo$@Mn8 z+%alNFK`@qxUQbCfy6}DVX$bWB4X=fSQyWy0|_PH8LYGU+&f`#W5xEdnjtCO4m<7; zVb;v4(1y#?G3?96ayO(oHE4~vvL0`^R)^2Tv;NzF+=e<05sMIZ@>nw{(I2t~A?H2@ z!**~MOf<4bqQyx~;J>}kAu1#okWzPaq{pB9TYcrdTlx?Gqd(SY(rYo>Q;}oburS?P zU{7cl$W%}x#)}7YXHk|8{+ZpI&Es=!r7tnU`WRhCQKyx0S~zuJ)=ws5bJX4jqEAp@ zzKlu^@?<<&tGH(iS6R)~G|t#8VW$yFtxXuqY$~&5V($S7R-~P*R@p8z>r2(mLPZ)W z$|BW^O0Ou^?|yBhuYIY|&3vJ*nwoz4bdl)(y&Bg6dh?B3ufMXZ-O)%|RO;%5*_mmS z>+YjYAADHp&b?my2eB3nhS754ghK2|Qde)QyI(uT*)&NB58u2e594%N3z*-0bHC6Z z=iS$d5@C&mb$wp?;rENCIcq)*^ZP73U!=c6zl8gyb~!0L2X~0qVN^Mi=1rrI4?5j` z#9otYXD3oNYHV+_{5YT+KE>XQ92sa*Fw%JO!!>!GRliMjzRWP%VZXsX6bKaD#~7T( z1{!9Mi%j|0slR-(U+dr8mmXG`_UcBTd-oN6_ji9?Z@zk6QBy0=3Nxx{LLLv z7Fs-fDBPH&FW*!@njiwLxbI9tGk6%GY;Yvz-ib2HQmAofS*|!Mgp4yPkPtpPjAG`w z##@smd@UCXE#?a+!QuB>@;?p!+7>ZDCqqBjJ&w#HUyR{P)`B08fMZxY2MK;2#EH;f zf%!$9Fl36y6Vx~$dM~fRGk6HsC`+}wHNGNDEIaANJbd~vyBE{$&rB)p_1UYvx&pu! z78$@R07k;hwnXJ9@D0{=y`i1~9=L4pIe(=<-*c3JAx!)5gVV`N-Ot{w+jRg>o(1Z*8tYpQBQCd^v_E9{Jw>;0$DdN zG2rXCQ!Gm(q8stb!v-rAVk7TfriV6|5$ASA)UbFaGTp0c6OD?Aq7J)9BlTEQPfKl0 zGS!EflCsy=e^vVaH^zExl1SA|<4LP1jdc6Yp+5O!rtv7%`|pkQ_M2PU%3~!BB+On} z(Q483y8n2gpME^m?N2IAr${BD-VqxigpCmbFNEJEavz8k=3>;rJ!_M1=lU8vtG69N z;y9Y-(i3(({H%PQ^jjFWCr$Ul;}7S~hQf#Kuze$p!J5q2`j~|A3KB6vS|St?zBi12 z)av1Wqn~^d>!^ygJ!v#58uck?kRwF7v2tS;c4>3n88SQr7Kgfp`yk1u=8-mqKCw!9 zE<=SX4BUJ5s_W8J2$DEcTugK@ul19My&fImVJ_B}zW90l?r(otuiV0wYN>oQHn-BK zL~uw?)65Rw*fR)+;LGlSx@pum4j(Xv$N|<>njG?Jf=|^6HM-W?{xKLDV?lv1!zOw|~5ZtGCZ?4|rrMaQM9It>A*|BJE;cnHcv|Y=CU2 zHm~s)k9BM#8Ze2?vIxjyUEf~5CR?q`Nk){wuoz5}DBgzc6L7uS*pPl4SKt!T{xB^Fr`H&zE z4M7o(+zV!ZmB%%H11Mi#J)m& z8NxjtV0IcMNvZO2qjz74_5I%&>5bQ7)pepcPnB)edhjUG-8+>QQ|aZGVtwJgNVi_9 z%-vyIj?|?Kb!n%%iM6*U-Tru?yPqsHpS8*oXHYJzMFDKMyCU7QmjGU$4R07d9n?Y~pEdLgZh03ZD?HWo{h9(T>b_iR)4@tyk^wJZPiATFb z9-+_H)4!;9h}tkb!WHTTj7I7k8KzAa^$v9}(oCbgSRtC55?qBn_a1mr_{npx_%BL^ zsq$MK_|d1&5FPF2&VRItgQaTkEwuN^fs%Y;)_n0tj34d3=@q3;>cN20KzBDRJnkI& zjB4l&JaH(%Wg;6VOv*GyLc+OGL@Bw8N_Fj2zx1WIG|3w^eP+m5+v8gv8$2D-7C-z& z8K0kLJKsKfglNJNz=lHzb+R!=@7g25!+PT0%v_vpQZhFQ8E?E0PQ6pm@nZVU7?9cU z!j2bi!@Wd9m{XKv^UZUnFnZT#sY=teg<&}pPQaMcZH&hkNBD5MfUcJAIW}MOof%+_ z)a6n;JyMazs>Z3BKEd9TwUhn7tt(}oP(k@@K8fjPGQY76;oQ1eyAi51E<~rp#bZ0D zAn_A*iL$&@>JJrVCm7VMpD&tXP6^ttS)WMKyIAj;l5HZ^Sv*`EI0zy2+K`KzDT zqACr>Bx!3#zv2{Ah#;ZV&$)*UR=$BfT~jD6N^M;$H9IP7Jn`lbB`XvuARRU?t~YJ` z-HclO4Rdo9a=A}ooVY*J<&z_Mz!iv07#0mbxcnfj{2~tMxWZLxuBFoyDTPLHzoRHR z6gJ77Xsw%9u5QeAj8ifWu^9tnE}!+=)TYqK>@6*>Ihju_`LVCWDi^ip^O-WgUJy}6 za)P~!3+X7cF~WDRj_3%I=mWKmDc3hPSGIJhw5WBI6iWJqb`+~ka-~sj-bk`&q9W;( zwFmm#ZmsWqb);W@vsT~EH0^gZ*-dm*wdUUO{=G`0B+{2Yzojp|SLmgio#JMqu1tiA zS{Egn)xAD?G}ljVFZAI9jPSDmWr~q71g>_CA^klR&^A>QHR{Z8wCe`5XV)AJnGl->RM3gz)V985SUn_J`y$=ur}>e@zW zkIj?JyiFu=tG~EE(*JXBq=UZI)?}fbaidW>Qa|6ZeaPDA7benS)^<;<7`A(zSV3Fd zd3JT!Th;GkPvpPpXLA)*5)Ug+yPsc*>!+~40Xf3scuTuAcskAgd9AXV0WWI zAa1+T{kGSS_D1^2UZJwj^wlrFt#5qoeQg)Lx)j5Tk+#PZW!bixC{pRnqWnSbuQ9E}pCI(U!?oH@(_4R$o2VNR^uWC8r`Y@a~c&Sle^9 z%|=PATiau`ZFNPM2p#`|?pGcDf;#$Xi>d0x^_0U(=MZ+=ggJ_Wd`6KTKHjr$P+*NB z8xBze{V|v3Vl^1X<+(*C4q(!C%G0qxxUS!r==zPZWr+T`Ap<`9IO;x3y2anUSZPhnGKQcanW0Ie6fFqU}BUFf`}Xu%(U^%4XCfwQfkN{sWzuQQG;#* z!6l4#tzUIpn-pK#PmEym`mU7y^0sy+t$y&qBki@Tpr$)t57EZS{KR zl}b0R71}?X>)>EvQWGh2H{aE~DYbulPmkk7H*Sn|^G2$C!ok-W`h#*5Azj!O>Ka-G zLeBvingm3JQbt^ha@THOcf5Hx(xE3k4Uq9++d^BzefVwo{QTGdF!zf;pI6U|=k(+; zDVu(1yf}M!cXe8u`1C)Ma(SVq6RT+;h;`;B9oL{Hny*@q=DBX)KhhymJ4L3Q?L=|h z7)+G+XtvDi7yN;BYD808{ce7z1V)+aKGsK%r&^S)-g)hszVPKQXi?SrC;!{OQk#vW zWNh7;8DS?DDm0b1#b9v5kMT(eaCWEL9PmsOM%|?R*!Pj6JdGv^Y9avnX}#<+8RQU9iU9gWJTs*RnG{Bes7GRB41rEvyW`l=$FA$FE&TZ@h6sH*TdSxlz~DtNHCWU%mOi8;;0|zPes$4>*MW_?B#A zya7?CVj##Tt_?xNfg9ki;jp?xfNgN6AkL(*P2U(AZqo|X`D2^-hV*=AmV>&006Ik7 z5yyOGOjq9W4*`SwY2k2J*1u6FJM{W`aB$ppei;T6HjVjurcdxr`}iShTV$!Kx-qFPIEBCs(6+jsD{3C<5C7ew-E(Aj7Qt1pPypP+oWdvoZK)zRwc7R(c8FGRjIy1pLRGmpP=HuAW_5kgyz~< z!2ui01Hvxr3VTeLdwo}%L{r_=n$4!Bs)NLh5iQJ=2zuP8{~$es$T!}mR(jcRWH+@5 z_AJd{9ou)0OyZ6YxRGwBYRgtJbo-`N9(Q_UE7#=RM6XS@^$-8QMpc=qPseJrO7{*A zG+h+>{3~OS*g0lP)4q-7^~|_Jv^wiKb>nbPIcpYuB{zZ zj%u~-Tyd2vN>W=9fEaA;06SPW3HzznEh9KSwsoGpzAtm^p7)&idDhj4K^*qlU`xo& z`Q^OaM9>Pv2@Y_OMe)4R&ydAY-@-v<6YW(uoql{z`taUDiz?QQ>)YBYBBgOF{FF8E z(|f)N>*ra=;jGz$CA_S{(<@6c zT1-W1HKsbvyo$6a7it=8noJD#(R8HEU{D75GMP-Q1rRJ|i<#!LxiNPbcWdi8?IX@m z5;sIQX^IRY-0I8_=9<~WSmHn-#pT?s4X2DbbB?iTAWE{5kzDIK)kwnd4H5LgwOkWO z!Ft@rY?wy)d%C(_WDgu4nHO2|RaqD6fh0}84zNSa9AwL2pV_aMj*g}}Iyf-5L?C8B zXalNPLiTDJNLz$!sBaa**mrF~`U50@#(-(pAujC%1XnF6X|jVJ2a7;p2)Va3UK+t~n3{ zV7@8FFw8a(++caG)$m(*4jh&69_}1-sj=gDd7=m^3WPpE9YTKY&PL@7lOevzyl1n@ zv&=ZGtS1i5!PWuobZw=>2K{$D)2DtL_WLlC%_TW8%wfFCdOlvS6<6BAjZ4)UGKE_* ze5xaYIvU5S%Bk9Vq3`_e7xcZq@*C>gQnT5ScHj=x3)2^d5xyjn4TuspR|d$2NpnVt zMk8R;+_X-xGto34Vyl)jKF903`WBwn^A6!J>i(k3xBfuI07MKVGC?iD>pQc6jb^x- zW#{$ZdOr<)zw^z;fK1tryx6)6clIt23oe_=WdmoBN#HHrkG2ZizpAPd8x7_tVym~8 z$_wKQoD1X5-e?C;KlWbam^ouvn-p@RB#q3iT~)Sf=dHGK>6hNgq*1E>`_C8p;6WvA zXWF^8t@?1Gk8U4nG0%1LR;{8Kt9S{Ch)$D(S_iXMvw5v*UMeb5bzP#eLPaH3S@znQ zHQL&hc@WqtIMgCV;o3}HvD4IdIX0}N$m^1?*-U}3XZ}|5`+4csRq19ac3 zDlux=nLU69k7E7s<64jBiPAjRs35<_N$|ullaP}+`&w_O+hfj7^O^eUZOWjgLffGE z7|oEmtk?()XkY@9;vC6|9ew!tK+R&VFTHVH-}%mO>+$rT>L;J1fIdv&JbOVEou@P3v*}Z1{&V2AN4C<5N0E1+k#s;Yg^B4sfqfH!Y@%9iT zIFQI}A~jL3Hg45-3)M&as^&*3c6XHByspTM61%!{;J0~6KcSB8)sJ9Irbu0=*JP4w zyY6)`pW65FWY;+VfJMrMs6t(~Mupj!pb6kQ^Z8t5U0MFFEv~(TCZ2eNG=~a`T|R%; zqmj*dR4%D+=;c6^IFZp)25jo{kk$IyAw0wnaAmnaaVCnfFI1VN3KJ1S{+7pDH@Lk6 zj~%UzZGtPptLugKK-k`2XrWhyU9boGK8lm{Zvr3zSlEoP!s8f zU;l0Ro%l$EG+5#H2LLDV0~ZFa!%4IF%#hjO1s z{+s3_`G+f%#kw;!r7RO-!OU~GNyBTHZW#Wg&vr-%+<$)xp-O}s(V;#r$%j-_lBSxB z#>x;?Hr?UX9Jg_14`fZ+QO_gq7<%&rtYCFM)HNJ_y1G_jM2^S~K~aWB0IbNjYWqsR z{F?Nguci9Z8?`j8q(vdPjBOI>?tZRM?n!%xu`rb}9!ob~O7-^Z6TS6PrW-}0rff_+ zIEQikGmc+vMjTw2ffqVJpQdePLMvUq_&;iq{J#H?Vp#dzA9n~j)J zUMS74>)|5T4?a3lKfa}Jedjmz+AD3 zfF^Chnu=jC!f&jE#fW^I>gJ7!-g^0#CRw8S!^g^tEho8Upqz7pBRW%`(bmLZKF`c0 z2otTrer9H1w2;4pwQjzz!b6*SJY)^lxI2r)N{Y-$X!wW_nTPR)&mpg;y+6}hh;Ua6 z-q|av8YGFu)9I>qZ&=3F^NZ_&vT(->L##Mh+u_&U?A3UQa( z4I#ka*XMnh?|f!Yh70D1afo6buX`ZUSv%MIA+&2*+<;)P3_Irml;Eu2F!|81C9)9M&fiEyoYm)c>^h zZf@K0(9p)?p_lh|8Rf0#$+`iqv+l6aJ{}h*h=aDDZ0O4;ZTWiN57%9sq-JFw0u`6- zFM|TcqmhcDutNsHNGd^8wD!c2YERT0B(brE>k7=OFoqhql*}nlc$tjwkbnWzOm!DK zZDCU(;#e_JT{e3ACFu`;Yoc#|N!rp><)TxZOiUeV?=aOT_ZGVQurg!2MH(s3YTew8 z^~LwDF8iNI001BWNkl&-W}bZv);w@_DC_~}#EWtz<*J=$;d;q6*??l*e0FU>0? zosfJ44@S7S_H+n$7+{RhE$0WZ;@BGX1Pj_9;Ldt~5BugK&+BvLB56*IGdQ@M8fWdp zv(|qtyHj5&XNcPnG0c@=qM<}-s2jXzq+Pl;k@`#=W~x5ZhYvb^aJw=!oh*x#VURK9 z$G9ctEiLU)=y>ugl>Ou>Po{XTV|+6Eb3;5$+{GKfLP`I)V?< zgDBZ*ip{aR$woKO1=Muw4rkc2Is2YEcc>BQ=G|52?kRT;D>GNFTqC%1y1Qp} z0UmXQ3EkY`j%UF2p7HBCa4qP8`9k0M!{e$UEUz+-(XhDa=kwn@56jtn=gZ~HK53=V zL0QnCMP>Z~vzTL(PPS(~$H`1N@SJ;nyjBRD-MPHhqOS|P3<6nG|L<^bnS_pL>4~*Q zS}d13dU9k^T{dhs30Isx?5f;%mz6Pm4??9ZKk3)kYyx6UM~Qyv-Lc{bhnQn$f)@lo z9_Dd<{nAqhE3yVQ1~#de{9~O z`|o(~^I)Tc=W8E*!>9LWOWWVrX1|vN4Bz`}e}))cE|)8Y3F>~PA%rTf*FK^S1HyY% zpN;%|p4-~w-#ypaG@;JIe>0zLoAk{z+`mZO>|4*2SVd#$3|?as7uKrFnZEnoFYDj_ zyZ=^ud!0#?VVcHaYi2T`5;eWX1CpT24r5I8>gtpqCy`0rO=IS=kN*L`2Uh$TtKfB% zfTz=`#*>M8={FDZD+SzF2Po$!0&|~GWm%{w3)8e=Lt%E@X4(*GJf7Gl5A7u*6m1jZ z)+1_%1QYym-T}dB2Mh_vOXDl44pgC`5ux!A$O2ATWQ9&>-or2{j!GS5g?{VXsebbt zk?xLLrFE+~g4vd8xomX&1iSD~b?F@M)j_FF3%zx#(_6Pvy>TPac!Fjj^;{~5TV;8m zMU&|MVWppZw9rQ%H99@Y)ie|H@=vq^hf9p#c7{p8b2KO*_&w2Y?eh$Z9`_7!(YEXJ z;PqKQxAwiJN&r9RfRFS;*?w*~#W81M;IB=Z?3B!;0NN^0+c-zyUEJxx<3K<7u-20* z6dGXTk(6bPTKtLx;VL>BUbvp+7{X+D{VaKGOG{fn>tn?v7%(TOQwE!Xmtn3j&dg^- zR~5#PjpeheNVsgtKZa4+A3Za8s%eE#(?YvZ2e|?s3CckHgCe2dmo}4 zlMH`srt{Bj93jZDC}8+oKpSgKgTY{M-1Saf)2KW-QCk)o?e9qkH(YcL)-_nQ77@wC zP=VbV#+@e9L^p3vb>sG~COf%Cd8}e~s)wK4QywN7O{a!8s1J4Fhvr2PN7~!lbJYwT zjdO~#Of*)B+=uzgIrNKf+eK&A4|BwciS4$07;>Neu(LJ8?`vpJ*C6C@{;-6`gg?xx zanRq^r%t;!>;`e^efsP3D}}(iCthhW*O@;v1pbdM3ghrAhVUZ1KzHWp8N>sDR?G_( zr%Tg{Fq>iU0Bq#`fKY=uanV6u976=gJY)y>v#2mk(} zGOpjfItY~Wqbs5QVV@3b;~=r)3QL&x;cI|lK67sZkFE8pOxkPX3_(dO_A1hw;2?{jwRmdnG>)%81nMZiMR z1QEU*YPHKsQ4?wsh042yDO{(Mv5GQMR5kj}`?-GO>m%JhKpNgD3KtsXq1r0cr}s{D z?~|q4CRUo~s=`K1Q7KPby?Hy=FTI`X=FLuNR;g|Z6-$EV7Jb<6v5t=u{q!eGef*P! zW+zgbOby4e5nlfs-t+gq9pFF1f&Kw!KRJfaK1bKSe>bai-t*0LFYDg=ABHOaRXoG{ z+>P0qhN67;E!q+=_bPKj{>j5mKl`LrIL?GOaC}STBeYXJ zxifpt4~Ofy&!V2s6)8~>#44LmQ4$NSqzH4rs8%%2^<*ji%}+kn8@F%h*S`HFC0(sz zUaL!-#NM|J69a$vXa4@Yvv(BFd-|F=#`#$eOOMdRnD!QE+2%9%guV?UXF5@rr55v< zX<|+H_7&~!s&>xf*)b~(VVowW)i&LmYX8QbZr{178#njN@h42OAZjht^6|q*=4?7k ziOU9aXN~8>UTXt<@7n_2Eep>GUAND_Kd-$AiMAfB8#tWn;YL2R*Z(fdcWa(6@!`7s z(9Gahnz(3|n}7=%(!p)0*|%8**PbTZe13iZY9Vl~qVj6t``o$zucLce-Hp_xiEWV5 z#(1bI@haPPy8qEVWk``Cr>az=epZ*lDeOvp;r%x>ram=Bl$De(bX3)U`rM7Y{_uq$@IIt=zXXIfOaPPe;EP41JYI-aMDlmNV-Io3PpsittwT5`;Ry8*cSh^j#WiS zJ~JhldvuMdM+Qx2(ir5LY;tHLrXIkkr7YTRiz;6EnL~-Xpj6w2I=GSPryobk$AQYq z%@61L+p!v4Xe^j4s9z>(!&o(HsYqy%u37x@Pyvy1ynl=hV#oIdAvRrY9AV@j>HgxW z+;1ueG}kbR`J3>YxB!Dx->!Zo2BOBe^iHZg0TDT8pNtObvXV0QgN5*B9Kjr}g)0bQM$=acRn=h~+2Xozajsv{5a>D_GvbW#Sb3J2S91I-n2Ey$S_l-u zIM`N4U*^!y$B@9|nl#MIrYcl7IEy?{&brc8rh$}%soCnY;b{66v3W#diBu0XMKmaB zS3z^4tnD-pQMZYecA;A4EW)gc4MnD<0%b@Y!xrNoWi~g_=wVefn;?a~9{^LbC$dHu zS;?qY!=Pks`|`V?c6TTG!QXwT|M2(kDT$vb83*d>JslngT2!U(-jWW+sR|q+Hl2dH z)Fi1jek0PsbXSia7dkpV*1SA$J(U8BT4i16;k?mtooaLv==P1J;lvEva-7QnHE}Z8p;^?Iql_GfMDjR4BpWU?i3GSjSah zd#SK&ROE>=;qS(+Id1>u;0BC645}tqk~J#k#~O|I_2Wb7&+nb8N=HhYxpsG?G>%M@ zhIxiL0vpJ>!?XyEpR@SG=j)qAiNhZ7@2#({fO{AN7anJeUnO;8Vckw%YthJ#Mn3-9oPpVesNvpSh=_~ruajozD<)3RD zWhzEHYK|6)`IqI!I11~^qIp#bnosenFFkCnay?wokVGiK+DZEhB3)oI%DBQrI_en} zE9ARw8tFZF5#)6EzJk`^DeHO^Xk15{;jA-@R6e|?#p$OSz44aX8#ipOw~7?ifzc*a z+$v5x?N4(}rnyGrOnDS&UMv;2p=k?(JEQwYY918Q?YGp8LbYX0E{fX3+6v9JI~^+x znPtu_w^~*z7Nt@me3+>UJ~ZkT{k3kD9}{jvAK)0Ay#&!glElm|h*UG0Of1p}FkNXR zKyxr}(Wdm{61aIF4GUr16Q!ts=Et5-a;C2aV{`Sszp!);wcC^7baNp=8$~5POftMo zsHtaayF$wLoc083MiM&vxxj^pO%nJJq3W_x4eU{?yFOkk1g-)8TETtw!t(0ws2d$S zq-ntxAm}=!ajetB6CIx%3!8H!$J^$;A;&8g2V!x^g%6yB7(`(%3s^}4nMC0B8#_ki z;e3w(JZhu=<*RQToLsS(>trt(0?Q2l?iU~15WXKTAaxr({=p!tA*XyZk3q64UE24Q zv4zlLA=y&AEm|bEaG^a>z$VEyJV<5xP=eIoEk^4N8tvLbN1R(%(l?Fme2pN%TmUD0 zZQFayKljVe{)J~sJa0`d>syGlJkQKOfH5!4zfG$w$yFAmb|!=>E46$m>JclD(& z-`2^=p@kNP*#lut8NM8MUiY|veqQ|{8o^EMpJ^*v6DD=XUjY5gAn7+T=jHJa`MJ$; z1Cf&$r~;ckVT&6;Y(+;?(A{v0>-1>ofh$#>{O7{I{+y=WN(8K^sWRofa3SMv<~O(E{dYk!gP# z=-Xd^U*WXU_y0E5qoZ8uZlgGzsakY;{5V%pv^uz%s*4Z`1geYNnEInptJ`-*+T9)N z{_#@9qEb;b3cAP`HM9Zzb#jWLRz;&E&vdkuKD>t}3^x3QIg!QG2SE-v=*;*X;Jl}6cl~4&0`!re z>%(&xrNZyTPMm2rU+B}M)f->_Wqq+O^rOH1fzoNCZbWp2SY3gGmQH4`)pm+1N4sv8 zb>2PY@`C|xhvAvC^Jv?*R^Qk;uJrFsgh762FEp}95Y=p9zQ6LFsj|sf%RW*B%nZg^ z9bg6~Ef&xn3-fN_ZziMM7)o`G4NJ zwevp@vbw(foIqf>lzK$#7hT8AcSP5)x;-msnr{G0b+}zhSy88>el&Hao@Xf+Xcu6++l6lpuZs&R_%d+L0A^J5T@9+Cn*d% zB+D*jXw??BHQTJ;#rM7jXH#vqbz8g7e)0TwChgf!u>dbzWPj`Hvw}}wJZkktu~0h7 z?MVULHiXss`m<$D zm|%6=w0A_yx|+{%1&hibZZ06b4ODfl76rZ}P&exR2U)o2A&ziki!tS38kn|U*F@^_ zP#->?>F@6WcOow=6{eW?xj%6gHJ<%Q!`YzIz>xmD-@x!Fbn9w&Offu$bxa-UIXRknD_Im{rzD@JVk@(uIwM<+hN^jf;df zU(C%<5BP)n84B8LOn(nN(8S~L<_;FM%rqD~g*Y8eVu!=G%wznIeO`_RL5hWzcg{f( zYQR8*K?6Oq)}4L2#x^eOF?x2_$LoZ^HDls+Li-uY3WIvmwIDlUo;&1%QybLaAKias zlPdtpnBDf%gr*^%E0kwQG>iuvQ74sxuNXzKnTCW>qqpAPQ9ed8gd?#4d$|88_&i~t zE41|&Ey>ZIbOSZwexpzOSSQ?);#xZ#2VRTDKV#u!@#XMmTO{45?zySW3?B5CK99|v zA0-i*OCe2jbHR4P%YHBo~#(rkro zF)|64(+a{lURl=4a)%DR6Drh6x2(HQ)z-J^sTUM^4)bMO+L!SRxDJnt>NZTbdF{s( z5OA7|cuh|ghq2*>G-?!fOYQDUzw^8QjlT8G+nO)#E9^o|#(U;0E==f_ej^DH&^s&J zEbF3s_Mt{Z5FR#^Fe^sVz9?GdBh&pgsn9Qq*2K#gFK)iLk?ZnmHkfMNw%o&h+*7 zD(z*h{>u+C{rGX9I+lX0RlRKW>4T+~Wu%*o`)Q*zic}Rbn%s)QO5-e69wnNjk!G__ z$Fo}VB_Tuc`X4FG@w?ILq^z~911-ux`KdIXL>i4E?dG9rWMDQ19bhmpgQnDoYG>-Q zYL#uMxbrIhsCdJ40am`vE_DxQ|LK;q_3f7DFY?G3QWqgrkH0*(WraVtcdB#a=LW4C z4=^8`7L^H%(UR!f58RtBH}!Ti5$jU5*xT8FSu@Lg`^c{|hIOJ(XN~^;exswMGb+Mh<)_n`Y7{0#r+Ra}-KKdH#_8#ff~PE{qHuu7vmn5`&6nbr-$ zMU;`d*35KE=`pzdem+ zeMAmFE*Y_A_IE*>cxCCqyD(`Cew}HPT3BbaC;a-}=L6m`jk-(nwb$f#`2agNCqGtP zz0OUxe$h1+wwwnzDRtT->&Q7UU;KRKY(E4dcsz~`PdPkOV)&ZH#>T?n;pVs*yjorQ zJXa5{aKSg&j&p2oo-g{G`jH;b&!#aH_hYqJ?KVw-eoU|Pg{(MBD6Zd~Ese#wu50sG zz+&Z8`y6p%li?B@{Ij_|edl52&rheg_z48lMaQNohrwf`6DixsbLRKPJD>M(9B}RF z1tie8kcc5n+RoJ7!+_`;C%W}UuHXH=5A?OK+*Z>p%+8gtpfGxH_!Y#c)}lE9LUGdE zVL7hs^V{cO*4gHnM3+@#;Yv?uoknS<#iUR^PR-d&fYM1X%v`1{-@y0PBEZnYN|JNV9wkxkC^DG5!j_0d>OWWN% z!j}$_5fYU}qXuSB$e01gJ5_(yMvoRL&;6K7lop!5l8+u1x_=a_0v~p@@@%B(7@jEO z&PDZb<@NMcFFE(mu3GQcoo-k^59{GGzYd&NFaOPX@2~otGRbRIc2Bo-VW)=9i6iro zkTX}~T&HaE_jmN(SHG&i{`2oEM1(d9RW3`7;#5spX~|fp0zH$!=k5B};XUXIFbaYW z93MG0o@=!!4P1gAS#QxQU{j0M0={ibdjT9~j&~Pj#Mys8ST8?bR>)!a^7{IfLf~??`715{I`i`&Px~ew&vC1fQmxK8V7-Y7ZRD);RE+Jg``2(WgJ!64&_WN(#8tLFhZqgdOCQ_j!%C9(P0uGm>T9ye#LFS--W`x5!8G#MqNgn+;@$XG*;5@ZrldAXg z9CI$)```lt(+PZ`;oHPHXj6xFLZmwfOa1y+YyIOdMS5$D#suqdqtO^CXP{5+NuS&c zRMoMPI1uf^nJ(*is9H%}Ycg(ia1iN@o4M}X8fkX~Ui@EYRHpY=L(uZQ#4O+*S>Cc#nf@9$8QIBUijQQI;UWKgy zy~P-Sp_-u$cKSpov&U*CnUY&K72;@~fe5V)qs15-zRWdagZ2|f6b4C@B?_xn^@9_o zajIlG@obl#?Pvqgt;6H7MLF`}nCJ7kO!LBgH5rmL=bS4%dBNIA8sI@)XcuiogN1#< zaKr93v@V04FY{U8yP5VXc?{Fkzz;|9gljDp25%gBf--5>@bFBf;WHZ)XCGYOyrwzRk+T68w4s98Iv3djvd5XUoQ3J@X%ty6M4fCW9!YI&&MMN`~Cu?!~1Zum+fP zpl=FD{k-3^ww8SSIP{AJ_Ylnfo;=S(M7|y@Dwq-REej$}5Aj*S;kA3b28fO8E64+U z`JBnh;+J=wIeR2}K_9NbrJ9nq*_g=rt{L!r=QK+^zUCvlf(H<7;k<*|P2J5zme zcd3rBS7D_vsV$u8$x*7qN3qZ@Z-b?xs8h_^$;JgrxULlkmG-8Q?%vAv&Ye`Z_G6`S zpa5rmO{^%)6ye~)!ULw76|L?+IMs(A9qZ#y7kY9mElZ*eIIT$lXbcJ#?w&E^`)zop z_2Avr(O(Z?xqA1KF8n&QnH}rRaLw6#|Gf8@Xqe1ofXi%Dph?pNs(M8_m=+s;@A@Jg zQ^LV5P!*NBe(?Yd=bpDEKOf%>al-Rld$_G( z*Tb=A9LBcEXJP3Sk1{opTlX!RPAAP;>CP9vsGXbpYL}%F1bM`xOJxFa96Syq2W^9@ z^)*aHd=YdKCeyU#D)WLgM6H0iz)0|Tk9h{I+?JIVPYx|C@#yvq1-reb1I9mQrntsc z{#%>(rc+icC~GxsZH!Z#XVynEO(zqzY3j5@z?bIKwOg4@PNq{A!Ncg9RYUiUbjJH{mk0eYgAjCXlsg7>)!tc&iA)6f0+vdT(i#dwO>(Jv_}x=;$s4z zA90i#1Nx%M*xIyi+gT3AMITgh17`DXQg6Dt;h2IG?kVQ>S)X z5-#k;yN`VN`Eq<&{yxhS-M+nR4#99{r#6@!9i9GfFSD)Jc|9Kla&!SNIeb5I_6G!^ zEygTdJ%Q-&IdgD+9UH&1>=9o>ckUx?y7~~-bU;ZW;jlUzV}dz?3irB=XLCCL4h9F~ znr0K31JzvA-H|Lijg0fZy~-O8Ptw9Xc-4o&gf6prWbc&_J`wduHUQmFWHl^$y)oqJaBL1!t*+Vo`IzHE zJvGwNlM_=>U8NaZ3}HTa{0n<|5&Rg>!^3Q$`v=2K>bZFsm%7(J@={>V{yE)z&bTH| zRH|((cFumAqDh~RCTuy}?tzCJa~I;7&7-dudHDJ7`qofnw&$=>JS&fb5`QB~mcR$GV=AC^7b)u>WHQmjXfXJD9(-Er@#8ffw=Ok&j_JZ04|;rH#T#C5VSsVPqRRB<~D{EF~P@Oi8aM{r2rs z9ZV)toBpR|TmAmQ&G_aQzHsp58JlyR{1ri9h`8x@kTHuL*ZgWW1nQ*-s5~2&93tNR zz|9Un<3qqpk=#b#tR`*jurRrw*StUu>#P(BtBEIjxYFe6Sq<)NOpq|pa=A3yXcDpT zTV3%e-`B*G5Ije6X=Y4pOi*QPq0JKoO`$4FG*_gsohd0@IIN^&;civOp?P1An?^B< zGGX^tln3g3Zh^H8h`|XH_mS#usrf8cf<^$Q3(>KHxKP*TZb62iL4yEQ^`2m$JApmU z=WGLo+H{5Hh4Zd$>b;wrLNk+EZyLyhc}+gUer!874_8CYq~d2d0DE&s?byCC9Mm_& z*ejTI-UX^!CBip-)(X_A?^9jQE8=qvBu(!crFUs2sYP}pY5 zvXS|dKw=!FnAOl}vBDT9S=Fj-!!{a&(`xN%&jw*tA1dWHZ>ENw*_dtHxk-B3QktU1 z8bzATkzR)8L@aJ&6-}T9C5;weIIT+hr;h}4CV!+L{^y`@<-fii{(R*RpEIE^hmAVd z9K#WGrd@!}7;P?vT^kPp9}F;eQccFVVk=dbOQnQ!HO(Ujf1JcRVs70ZZk9W99E;{* zmeQy^J7fVtjmmHUv5F}_qXp-Yb!`~pbaAS>GgTVXI$-|q?;R+D5zwpIyG9X0)0u)8 zQO)?Im?o0qT1nlgu8)a2uc+=+1(BMzGzq7oTFYgwWr;m;p`@#v?SH>%^f1ED1%X^p zkM=*t2S1*(JI<5reZ)7*}fJOv`R$PCdi0(#~G3x9>`K@3flcOEc4;Z<2Ob zL6MrNi0LDzp$Y|hc--ix_m}$7PYQkdIMAX>)Zuf2gXmp#sHjcUwy8QL{R&X1ZWs36 z#I;T0{46jR3AaegZ43}Oq)}&%AzhaKFO06?&lV5Ahz!sD2gYDx#BLD$FcF+`xL=9R zo>6G$cdp49_^R!cgq7iSw6l7bg^Jq9v`QyQqc&<4x4Bf+g2_;^F=;D>ZK@_|6c&lv zC{Piikyj{fD+NuYsv`2nTz_}GtH1f^P!@?&L;`AbFip%SL6Jmalm`*Gk}!>!8X`TX zEqHHPM~-3)`f=!CIXtu8@f#j6Qw(k!up^Df3v2icVKuxS=D7WuQu(ni^RxTTIgMt` zv$EKnhOycpQH`U;Fts0UPoh?eF*gPlXbIrlmN2UZ2igD)iY9Kn`uS(zphU5vHdNe2 z_T%1|K8(q>QI;f9S!vWsBZA)4ON9~ZJG8H~C`;ux_w@d+d`n%PY4+eqJ7H#d)OnyL zcHwukAW~u~JkHs-`GDv;RVDMnIe0{yiwG{XnR&n2XDe8E8YYSrW<;rQjw~6~Q9M!? zqR~`oKKrqnMX7M_wt}1cLdPj%UUq1%;fJDCS=Z*glJMG1)tD*i&aJTy-W+NFR<2uj z#(L{kCOvtqah$3fk0kJTU6^BU>cnbZL+ORB_HXW6sL?1$Rh69{KYC(5Fz8Fu>#(&S z+6&qZT<;2b%#MFj9GSiOX;zYhZan}z! zgWZ7EF~79^kl&mi27eogZmg5VW*VMZ9)owJ88Thdwon5Oj3=t*hiVouuBIx2M6sD3 zx^*>(oH-yqy9gaksCe3xWiW(2b-I22Tt9vJ5I9ey_3}%)&heQb5Cu_K+RSznvnmRm zp1AnMJ|oo5`t5~(bmg-{u*9}!5$h*Ei%KJ9@yM7M5K(vDys0FQ{>MAF#{cJ)Grvyw zS|Cs^!yw7m>VvGgJ)U2cPd{^PF0lTYf4}^`j#_TlWb&W?{pF1eI>*sF=ObcTO_0nDl2vdy@13mb3 zp(xEYO_46coWXe+?iT5c$Tlv|U-B>Bm-NMp_6Of@j#&se)S!_ZVs63gBSh$IHnZn3 zOfEv_;o~A3DK+NTn%DzH!T8*!TTk9BgGjr~&qTi_ZuX8bx6H2s;|^)zSxu46^xSW@ zgJ+xVbNB9RHePHu8IK;*=AraYzPY0}_ACA8znSaf8O~xeg;l3?8S25qQx)?}H*Tbw zjK$RXaFR#yxM0 z`OF@KA;w;MQKh=~v%;7Zj_H7zADe48c3_OG54V|J-@n=`+Wn$)nHu^vaI?0|VGcBi z7$dI#YRA}vfzg-W7z5ko18a*JVhbeW%KXl_arIPP`+`efi9Y(0pMRcVs4%s5uIfp4 zm~?rDBC?6PQ(d;oCp-GeH@~UB{N8`n<0psO-QQEaD9kjg4H^{%j7*qWXj)+&hI&-* z=z0SHz}FNmRs|0d3~&$(e3!O2r2tfQX^fMiD%8%FYU4<|ZycDzMPt}nh+mKYVEC-_ zhOxuOc$DRuPBKOKm58MJ$*CIZk10i#TC|ujhC#+)?eUg6+en)qA)Hi(p=M=if(Gj7 zOZ27j?7YMKA2Xa6!N_%GVCrUl)Zd?0HN$PEo-L zK6~lyGgQYO*ylX0TEZy)IPP5ocbP|S7G*93u`9ckG| z+1tjH7*@mjykCgUL-fP+{(4*5Awu_K%BSai=Gm4qH}hmuX==5eV=>HZaP3(aEZ!V7 zp|t$_z%kh<+vv<*JAkq6WOKwDCovlxRv{bpj;K(e#j;RQwHl?^xrCZd$BL4ZGu(Gy z6mkde;od*v>`X~Kbevc2XEEP^TYpteiFLVa%87PENZ3Ie`vZ7Ghhar$A;4h^_&AQC%#^n>&xFfZ}$J@ z`{6x;7?aS_E|?TzbBifJte^bdsk(z3dS@(Q7!bFmf(GfZkx?$H!{yZ(7Wd58eyl%B zo1VFl3qJ7WUy#IJxpXgQGqYJ%*f~d!5W+}Ly?Mpy$&tm7$I)fgIq6p(O|`$br$7DCQh)u^nbc(3pGd$x&bJl!mcPG@MNOXEa_C52@M(Gnscb$lm2F_&Fu+XXE>g|9 z5tM3`>eItWAKjm;Xx!#APCAXpIR0ydvx+p#)u`+lRqIL*Q1ANT1y^n?K8>i(j8R~F z2H4yJ#izf!pr|Xo8U|MY$5R4K2l|ffTnGc$lsP)hypE(XEZv%lUao0annnP?-E#C} z1&KBXV=f4shA_B+mVrlVGap_v4{UwIyn)?35htppMGB9)NI{%x|L$9QcRAPJ{l%ZF zo^?7H9q4cgb3Id&Md}I{4Wn#o1#zgla!d{rHyDi9bu~WV#z6IbV)X^z^^6JgPXWUf zpEInrO{J!lP!y-|3r#x(n1VN1p-m9ebt)}*MnVfnph$Unj`%ZHL>S_gV!TM9sGJ z+n$-)Kg56kW3gjw`SG>wo8dFYmZfDwF{lI25LWfv0{4kgvF?&pza$a zgL3ToVDa+fnjC#P&i>jz$DE>oSch6Sj=40Rq)HOMmAA(>Paxp^K|YjW)gF|~`(fEW z{blFI)GD|4sPn`@WFbDcwYGB$n&eMEZ zl;Q`$jC2!w=qSrgV*>kLBmOpqy071`E{<$OW1>+}mS;&r&y;A{NW&a~ydTcbb=!TO zlrij=vt_zvj%WV2f?pq5hAjkpA{Z3>qM&xZW9m}x?6vymU(NMTe>v5DzSMC&Qy5MZ zM!AY6(I=0k2TwXxeZ-Hh&egS*?J11-Z(0j?*pv$;QEQqL`_o8ozA@HYZ%(woA1h2S z<-{xwBZ5$2jF177y;jS*GpCz}N7B7dTm9stN>5H=oh)LNHBw^q?p>(N2$Q-dR9!n$ zmbP=7LQjm_Cdn2MHX;4b1JUql&)^+A+j=>`-~RnZxBJJ>d0yAe_a*J*+6i5l01oC= zDJ=^(M%uPEK5C=dX-p7_g@_%dK+$SeHu~_BM)M+7M^u)s)hI)?8wR)Y5nyHy8^qO` zDZyBJak9y`$$+!5#yls$&V1&_xjQ??gAt6LaKxiA4q^uyNFA!~;MgG6C~Ae)P!@FN z4}q|mtucHOHH7WNvL8+e(IP@c1=9k4L6F$yov@(eNE#7|De9C2 zjnbe}qEc~(@0yY*qRP=CP^^-u3t_BxzWgQKedjHm93LtyYYQJ*sm8cdVd`;DKMJ9v z2bwQ#6YJ=OA)WweXZoVwxJGegy$lWJ8U92BQCsQs@k6y$rSa`siVmiIy0v+Tr=`f3 zvRqhOOsOlKoX)j4Ua0O$bw#1$pWIVZG)ngO6h)~5OlNJ=?HDw^-sbqS*HFWm_sPl0 z%4x7~kEa(Yf7{`;C9KV~%NUiNf;ckm6JOtL-#+zhMaTibEx)HeIQsxir;C1PQ@cCg zPVV^DL{m+vVm?#QMG6!1Mogf1`@s7y^8M@j!Z|PX`TyY`{-M9TKEDPCTx(3c1|UCA z5!eLBaQW3KSDh)N&qz;W<)R4nrn=MYv`Y2N7Zmbd1ynqJ=PS zJY(}$>7BQB6eZ1v&r|>FZ(cnFs$v#|5oR|mZ2iIsCz$KL--nwI|I8y`YPjwF@Y%2x zYocrT^x|t5Ez;TVk9=S1X~XxIk;HxsmA zNo*1^;U}kUm4e@1v;r^iy@&A&WO3zB-MHOOXl`c0+~9Y~G~E1b>%9$Md^3chNu*L7 z17i2RIJHo*5n(fnO2m&HWn;zINcWxMRPWb}1PU-5_4E{TrW`OjY*W0Yovkb+UJxLS z^xg@!r1NW`pLhNJI$tU`s1uvPo&jl6O*RAlw{C8yN+(iL)v9NWZYQDs@t0EVOltkr zM+^PrL8dsa6~+kJ6FoTz%%*&QFVGIs_jc*Vw811)664DTt)JHH&Dk_%aj1AVRF+HW ztkdkY(_)Ega;py8f7?7b^8+*a=sNSap;G!;gIP_X(J0XFB-UgUD@y_eO|7P`dK+!# zFG7jNB+-7{J~gKL1;9c8TTg8K@i4t$1HHXRHu8C)+n(_pqTS*$0)McX#y3J$JAsV3 zNMW6@jSGH$Fi(NO#W%4Y&su%-s8St_6*jfuIW$PwL$@_%OI%>*;LC8KSl!(##5(pLBKu;G%@W7&**dY zWteyzREHyDQo^WQFOM)YEs@%GVf7%-1T~@v<`F(D8U;-!m;gb=s@yo5Hi=c&rQZL_ zmsA`d>%oKjy7kUGS{8G|3kdmOQs4(iwToYfQe$DaTj4ws2cE0B1un)LN$-@B_l&Qm=u|9g?d+zi zpUiah$s=WHuF=k}!45qZHq;D1a0IL)==te%YUd^df7GTifzO%q_6X}1K7Bv$7dgXV19C7CG?S!s!Puv9Us!HX2W&<-$@=G11pUKzbwO8Jn z>jFFkt{D>^5}&hki#uMpxh$wvqxtcPP?0mFZfZ!Vem#GsApo5hUl$^&ig4Olw?M_$#SM?c zQD{D^w0{%(*^qsdLR30>QyIr$c$(n!WdIY;gh1jDY}s6SCgB+d1ru&?4D<8-HhBHa zmn+7{wl8f1;gE=FJEY=H>>i} z@1Lt}FTEB|XZY0ke>%xCKk>{<&Je-I5bSfQtIC)Z8KyqYho!PCRfT!qj zEn$^5Mg?Dxa~%?H)Y&a#LA0nkA&~pVJ0rcl-|9d7u+{yCrH3FzhT;m}_&lxuY(LAU+G*A~)+Esl@UKBs6}pz5BRnL`9OwKSUj}NO z*2r-Y>1U5hJt5>P{o5_ImxY>SxJ4y&qjUD>OmTYXtcKasYlN@gwlnQreYz!qhsT*$ zH0~MTa^~BuxZ2@w(0_<_n#~R1-@Av*mcUHKxqiPVI;KX z*m9+XWBEF!1dIrpV9YUF&FLvLGhr$>s%kWmTAj41-7{YruMuVTgD@!qh1H3I7zdin z!AQ%pFs-@C^gzG-&2Q^3{^S3v$B!Rsv^ODMg*o94(S)oq@C;O1B(C+i^c&kvnE89) z;PDPj1plR(al%|c>!Yc(IC-L=sg%ESSLuyC&EbUAXdR?RUwfPeeQz8Y@L7-3?A&x( z&TG|GtmVDOIz2qq4-E*Urw4<->Zus46WMj(lg1l8(IT zS?f<^}2LW1zJ#u}W1%*_!}4r@!EK>r3F# z3%{r^ZRh8hWsX_-$AA3C7fsX8yq&*j6}V%cYJFPt5bNZN_>8 zzvc>_-w4}l^iv9iWXp=#mO9CSIW|%#3(F)zo290zdh6Cy2m8eI*6jS;uit!@5UAoX zK-YzZW4MqE>vZ1cmT#_d3^xwLGW>I6Fl=OG3t7L=^2*Z$^UHu@Jy>}?T zq4$Jv$%50*1u{Ex-L54X7qyke8ipSP`Eo&+OF~~l#J0-EiB1=_5rHNd8P=Gc1TYNF z)?t`rvrfJqoXE z`|rM{J8$f&D(4pe8EFCK}dv&y(ScOdHx3wfUK6?BFZo`oq z>@a+wV1n4|E!o&LCcVpsjizG`QikU!ZY^T)&~3ClBVzr+KX>(jeF#&9;|v^M1TKbr@#H_Qb#2cco+w<%A(cd2a7Z?hyVZ}07*naRE?q= ziG`m`QC14kVyIPjmEsUnvecqTxP2HV1+6hD@+4Na7i)hf*70$zlX;<;Me7P}lg5Ur zY$}!2TxmwM3JddXW*&>hQio}$=@gBqSd-iW+?WX$cKdBmx{VSWd;CxMX>Bckdd+aY zDb`T)SFR5MmXp>#{iRR2K3|3l)+yIlt}m=pY|S7Ko}rE76zkmhWL(s>G-tC1f6LQQ zO{@~50z$JlVEImukEM_A^E6h|Ej3Q1$tW|E5Oct4+HI)Nw+5e8TL=1CW(5N#yh_9S zHFDjm^_AxVJ(bT(S{o?I;MMg}+N|H*GgxnCD@q$WBEu0j7pXt~4e+lJXn&L&?Kp}f zWyXvkx=o{u_aW=5V*spMG^;co$12!xqDfcQihJN% z|81d%-1ENX{bm(<1f~qk7_^Q_gOP}7ADiQdPQ_xb6C!A2k;d=dRg*^Mdj}j-!vq9} zG1knM)#VQ#&Tz9aV4Ue2ey`>yjShc$-?S~$-5q1PWYjx?A&d@?Tj9ual8-c*Ow4qH zdcl;yFAs;crEkh*%$Gjd`a2>Sg^`6+Hs5s6Otk%qV|$q2^IQ+>&i5Wq`13`1!r)|m zf?3p-g;V9RG2>a-^oLtfe11k}z;t#_$*jCT_=7*VsF>?_FBt;YjER>F(3h26+yv-K z8$wwk%{@I;Otb+!38&5(lOdSF#_Xc9Hzzmu{NR8xahZ%w09U$J8l~FXn<~xC+wpa1 z(2D^38NUOW(vO@?Qom83At%@n^jcrir94A;ZhYL|ZjPN{Dqr^S+2*y?ZLsj4SZukDwAl3gRm?M^Xw`B` zE;{8gDx@>Tab`4qly+)rLZiJ}>V(ZL*MF)^VDgWk8cm!Ry;?g81>^gMawkwsTo$?Neyt8EwqEuD4qc?MD^2?dVlStqHQLTHAr637yb4S_- z4@ymUbM5bD%JM)#jK&tkH@+V{3nns$y)fEntqY`8Dhz7fyd7z}h;@3B>G(9zV&1AL zTVrg*Sz_=9MPahm8h;|vq6@Vkz}IQ3H?k+nMu{dV61w%HV!;8eLYl&%>u_uhAQUoo*V8 zXmT!Do!y!NoVEt^d@S? z?pWh(UiGipA}YZ--J-Tw<)#XY*$_H*6{?#9f@Sp;WjG=x3TuURu30lTHPb9eR78=g zWTb-{>e?+fWeYJL_95RIg{cdDX|c$?wL~A692;?G!irCoTxC61lIEJvW~!ST3Zj|9 zcvne+%3rTy*>7-YI}4UE*)1Oz%?2_I?mSW@9Md_`t?7I8@bO?;!^xfu=5H_i=o9vR z;Q@Izm(|^{1V`GqS1vC{SR&T5NF?-KujUP5MOz$hsMH0uVq%o5R#=64^VV4Z>i2F- zWu`PiSG`pfA$@hWysYbvQQ%4zwXg2$|Ni%fdZ(eV9A99@@HtNb!dpD(I%;qE(!6JfoVZIE!Y!Bf9WgvCMw}gU3 zaV?EfDLv>k*+Kog)yb^Yd={u!bZS!uKU!Tb46^y}LDQ_G-(o#E$rUbJouY9xsWcjO z8s(v>;S+rV2c7sEU>8N37!BY!7#-9nz)r->}r}eYU5I$*0HK!q`kV-B5KTRZ=6Z9 z6Z~)_`uMog_kXrjkdGA=sNQ$RtSwQS?^+8riS_{a6z7k0gXsWla0r}+!w|b|ZG~w7 z(WeHhjXY@DP*cKQz8GRn!lkBJ zq??mS2YIMz+KF$%5OWzA#?F+_%wov1?=IhRn0XuyPQC`TjGv<=(1zl_wa;MS@tLhg zmM0q(3~6wJxtDb6Cd`FQKQ3e4n2mLOT4_t9>XV;* zsDo*&9B0=!I~BeLN;Bt)gGMz>Me`HkOlh5sVGm+7^n#iGm_hl-8=l zM>>A;1BF4W?7gok%Ey8UQQ)XM?2M)cebz8+0D*<#3{{uV@+d+?>Z;o4m@btTKfb3Y z4-R$f)*Yo0{xhUy9ICAY?G&LgZO}|9no?uTRWckvx0ZHxd}3fW=bkpk0JAeu0QRQ) z(T@Y_#?khsrI3G&$r#@~os^`B8ukuWWwaKlV`?g&E}tGB_I>KdYTGk1)-%8FXDiLf zivDW*$ul+$4_i05dahC%5Lb8o7(z&dMn~`4EE%gTKU7m3DxSV+&Ui5Qw6zP?653RZ z8_a5;OG`)dApow;dkImFcGeAC7k7R2iXd>!n0Q5iebH>=Fi5eRUCfrYVS?k22-p+t zY=q$6`iXm9d0uifBmkJ?>mNg)Q5Z!EyTlOi{{C3wJnJ3KRsZ$8ysw{swh$oR{fi#9 zsMuC#Bd5XUW8;k>e_JT}MaaE((liz%zbN_dhWAJ$F7$h_v9S4adil$08*2;f>du$s z7Sr|JmMf?0?Oyb4qzo7&WmTDkA#qfasi-0)VD3S%_;&aWf=Pj1>T-1s5x%7v{?U*b z;h%Y!aX-A?yysgO4Ou)=nnG;ifIU=_mHN%!{y+x@H>GZ2rZnVZKk_sp#@%n`>Fe+! z=b_{Zm{*mH9AFzEs5gj_K)P|`hVtmK7N-m4`x6y)rPD>I@g%WW_eN-}=onzTx>;3^ zHu-+tgw-n1&+&z|udhGtv|q1@_ae>mzG-lPiU|PB?y4$WC|MNZJ2a3Q<&#}oM_@S_ z_>nT&Ud2K{IbRC)Vm+SDt=9$-3NEo;H3lIBw{^Su_9u^5)t{SV2AJBM@ahx{vwmE) zV@wD_HSFs74JH*?Ds)lbPzIaIK0dw>4pgxxzK}g8fh}_RF;8G=8=l3fuAFoeCG68FjiqQEY0Sf{+P`= z&1X(~Y-iGHGL1DFg-Vmc;0UgOY3R*Ijim&?qHzoehZCHsjjLs8PMD$keYe5Pxaio{ zU;f*RzB}(7`NeTBh+zZL`!B#>fv*duVhy0qLoJ(7pFU{K+=GpcMV-hJi#B2Ae#Q*x z+rTagRT*-@KfwIDL9e@xmVt zsDoqrx_E60{6hG;qK#m*2ynr-(eX^>tW>%?(f;jQ_@BM-z?y?O4P%IM@S}kSM9iG7 zYb}o*V-GVp2ZP?HiwTaLP{bH!actTW&@pHs5!qw8Ts~E{Z^KhB2Kdsqmo&7~%;%!m z_6UA5`?VM$*9sPcOjonwk_ikS;Id;|{+E5@-y?W{!CjY?6V9a0rwkE)TeQV5s2_M0 zp$>Fjq+j(}UY}nB1g;qquK~!fJp0ejQ~&F4UOfcRm`HFk@gj#gk8_KQUjRI^_UCQc zJHp`nRmHyTkv`WTcb`A>DWldl6$8S=bUeJ|WUx?L`2$9Y<vO@vXZ7*~m=`r6wHUOOd@nlAYvbyhp)HFsWn4cXWq}b9g|sI%N1`|`D`zwP+CP3< zAAInxsnB<9X22OCl3=G1g1Uh(*PmDAy}*U#)x!fCjny|E$4Gp<#J`lflBsdJTXu1WV`9mkf=5Eejk-NiBR(;2uBxGo2ngvWvyc?cLdgUA6R$qtB4~NfJ*Q>egG=Izc|f$v=#wNNv%os2iOu zT8h@ezH_vP_E?%Q{{y2DnvUA=&MiQO3T+<2lp<0=-?J;2IGleG95>%x<=*#`PYYaz z&xk+*zH*vDfoTv`gh-A1ff3beia_x+(8I${AAb_4VXvBWs>9ZpoS3T_BLjti0Mih+ z4zMBpydP)b;c!3RU7Xnl_#Xx#8a|ckiaw9b1mVs&(m^JT5^yd)1{!0cv5D^EZa7Aj z@8=#6L#D)4VPj+YoWy8nxT9ZNSM-YW@igvA)nTW}G%$zlv;A0y^G=VB@V(Mlw48+k zrMK?r%`bgTPyX~%%^y9`PIg02>dI+yFt>9sh0l{^d$C!saKT7=_E)^_~n zKnq}k(iAElJ+bv__x3G~-Z)U%dW}+_oAamP$#$5Im=zcd%&f`btRTXSqtNWpq0%H# zoaI&?G&wWNc%Xe`J^aq4X=?r@j8+L_Ef+J*XKTj9a89gia`_eIfX(70wumAg1Dh#_ zr*Ss2@o6?5KiBPWZ1^_#^Hnn>0ugkLX$4`5%KA{Fp<-%KPi5ot$G-~W0@I!8=;vUv zKh=_--v`%>iO*@@wQakD*VyH3p=Mr~9UsvGIz0OZNS&}vV^KM~5U-l!@%ie3yReDg zBQ&lde}Vv&QP2r7r7OMp=0s^4sVa-Rw{PD(-pJzm_8$NQJaWFMsg~xPapu26(!@eP z%x`$@(=ir#&Z4`SC5xly^n0HfrnP|Ni*JmX;c~Kk`b^1ds6yz=I&*G&59^&wW1=om zJ59~;Q3hiI9|x!klhM!yrr*%Q1Q~9oAlx_tB%DvvBxj0tH)lz?Ayb0cdCuCu%4ZW+ zs~1}?Y*XPkHKvZ++p>1f9HuK8+Z6rAZ+=B1981m%$DBce15*MaAshrEH~oWLiXjSNyxJIn zIkDdCZq~q$zu|MfdlvW(zuk7dt&DByUi8_p9J}r_WFA7e8cXh+{@W~jm>2J0MxZUh z*&oc>vP42RQ($IJk$G+(k0+)A%$&9Kj6JA-GYeRM@AL8F)87xzd^e23V-tfq_NJY9G&KiP6duSTf(|x&)s7!UNMiivny6#Jokm~S9}G*{-SgP z{L=O$0M8XMTUPq%{Z5Zg@Trj7u!_c=vQcVl0GdJmz+?nGXgJ9~Jm>7k!a1*B!ea*f z#?iNlr^-+6`md zX$!crJ>%DvwNamEyrq8Ye9o?q#!$i6O3#pMgR$C%v0Dq}kT~l!jU(O4q_XVv$&vJ6 z*65@xb^GmKQuC$n=&!%`pLB4LC?Dmjm$0zGBWoICv${aoukp;82)f%d&be-Jo+?%4 zLgkYq;p<`dtv6K?nxw2(Yq*gQ!#QB|Nnl}2=`t8b1!L9BtXp;SnTn&ib|yPY^30|R zpVJ302J4_RQ#J5J?i{*ab1p*S#xS%Onz z4jb2K-WfN?-SZsNjmwUgHYWx+n=*&(vg>}mZ|g$k0)HZ*l;#FO@FjTCe37ks$TBf& z4!-Y9ON{^ktv*bDczMGvYxwp1D?{L#F>z&3z2<~re49<(@_26H)zZ#wvCO~FYC>*c zxxR`Xsc_3Rh}9-4;gtqV3H#c#A|Tj11x=vIZmb(OaRn9p=+^D&C$G8H*Tp>p1kxDA z%8L)baGaNFh|D+B@NPJkHs7CjZ%Can$`3y$4gLWf0ky5dn+ugE1cr6<-%}>(;n?Gd z%+mCmZPQd>Vf0cn&Nlith#NA2$=9ptg*a6tbXn61X<8ucW-Hs2Tiu%0#Vj}G-MZEG z&M(p|&^_(yiI{cDt6h1fgsFx)1y9q8y4u&zkg8`&KwvUHg0N7QP1Tl_e*HJTsJnN@ zYN|?MR9hqtn&v&+ugo}1dU#gi4Ln}@VSVlT9CI`zmpEEORh1$2&fOdOFMs{FYSEdE zLsOl7G^;etQzN>Ow9~na6HMcrPXi~>UP*QPN?U)faO+EN$t%xrTm9V}avMgj9b>{M z?K6bj^HvTMKr|D|VxeZ~oXWwRV=RxyJ2n?h%g@hSq)ZxWcx- z|G=O7wT*FXd0MX12aiwuuBMG?qu^fVRpZ^UhwTOO{Za>vL>wWz3&^+Qufow zV1PXRa_bZ8zy1xr5Lkqo4hC{alt`7PdE+GGINlGlSdUIB{q#YjvL!+hj5KL?7bm5x zA8Ms(KnK=jyYR{}6bltW!{#l#lA?r$;Z zc=SS9ocVZj46!I&xGT}#8soB2R83mIzfTP0~|cAN9r+`jbXaN~&o zNX;-H9lkGi+u1WC{JZluX8!%No{fMs81V<9nuu92D0|z{I8hklMf{1r`2HLE z^OJ# zjk8dTz9A+(i%YG)&%X9mdG0fL4#&uI zXVib_$K+M=Bn|N748!Iu(SLDG_-3271P)NEqE@k-o0CK~!)*S{S!L?Qu5JJtlhpd6 z*P0;W1`LIsp+{SMdwgy9hAyDKNV|sz3=qEwVzbER0V1+vzz)XE@SF3lH{rKgkMq7W z`DO1^7l&#vCm6rR!0SR4Ee<$CVNn3%lE@+8m81=Y>DZfjsNH{*Xm>x>_kLLE-eVUc zJdQgpmvcQVV~wY|c6VdtfYbf~5H^}@s@6Er`pC2>sY9=A)n;b!Ny%AKSp=fVIM!m) zsal45a*DPKj6SKYz@2C*@oi=PtP=Q6Xcx3-tOTlySnRj(Nr9H-{+=@jh-g!SW;<=i z&b>G1Xi|s7nb%&^%I4HyV)Zy=*augIKk58;!)xDP?5EgXv01@q1e&I0)fuCLxd2U6 zDblBht&UF%)qoCd)R^##xiKYt{ytCF4%Q^b_3G(`7u)J~;RiNl)@{2i?RoDhm!&T; zjW@@Xz$geD2oA?o;?3#*&)%E-NRr)oeqY;tizWBWs$!8;A znTr6ObQB=y9}rsSxd~bzNC!bW2$;)Aqk~!yFn|O|1B`T-(ezC3%_dnSt8$Ia-EBAF z^LzH(Ej&CTBQhhis+wVmNHc%-?5)4|-f#a!dhb@Gy%8Zb8Z&nR+l*OHF)k+aN-fB6XsyqMQfoxYrAg;35+FL z5I&72(jNS+R;8AQ&(tK+=)qm3_>Gl#{OLQ z@7bEiNn-VS-47T!jE%=t{9Ii|Tf&#io$p=-A1`}9EN|O0{i&*@%H>i?L~P{D%;E9J z<20YvUjgUT2VO~}DR(&r=JMp(8qn9D+&sOZ5x8MYyrF@8{bIX+i_K+uJU2CJkU|y= zix~vWHV{)|9h?GND&1VzY=X8S_8b$ zt_Re~pJ!SO`(@AOXMrcDF##53{e@PlJ1rNvntI2w5)N)Qo9gi3zz90p;LG>r`roWa zyyXu$hB&hFA;f(C%ienhikYY%5*)Yl45s=-Fh7o&Ead?PFcz2MMq8FpJP^ih@|von6NbG7jFlet(AHFw?J5 zn*-2X(*Rh{#c-TVBcf+E4Clw|j6tweHAEGR7gxsc`)z%@zVWxs%&J&1C+t_NC<#^N zF1kpZM2ahzeNga$az5*vR>MbkBaNa&|KDHc`uIhmx=WO4q@oPfoHXj%Lgge>nsrLd zJi$pbdk>S&=G?mN7y=&Z;}9PeL_sQzVH8Gq?C+G!0=45#vz?Ka%T_1Hm5%2)nx!sh zBANuLii*&$E`kSl7d1z!%#mcLPoLudB~X@y8jm84Go0rpN|Ka-0~TV_XP+Bsdet=?kekIHP3yg`PQEy=F~UpRQD#ZW!;$%jjl^!4XPMp^SGu>GX@3k+yHtsGV1&cZ*lv zpD&wd#(a1U*E@K?Bu?DAua?GC1D8d+DhM;FiG><}f&<5<)%~4R^CH)Kcke3tJHMkp z{Ga}J9ag0hqD#b~;Uw@h(E{NgcsB50Z3O3zB4YwD7WU2jmPZNd~0IY=`cuGg}pE^r>d&M4(H z+zkr6hDQ%4{!WqBrs3W(sK?`rxcF^~Ty0q>o!wH404ivdny-|>2mW!uyeEk*x^5U_ zV=en!H}^L@0;gB~8?Nl8_{)vJfBTOPZ?|nXogbf=N_7(92f{6TAAZMiD_J&|yKIj& zhj)(1@a6F}8Wa#}#ES<}iKF&74CDXiawXs7`m9EvUVDbRmL{<24>$f{p+k5XreEe6 z)!qSpxcw8b*mEx0H01Wv7T+Gj8wbCA5$E;8zdv>F33pVei^4_b;5|sncsw@5oI{y1 zhjkCjFi8jp878Oa9G1iU{+Tj;TfGFrzk>|8>@_TB^Ba@M^od6N_2XrIv586bm9IS1 z*S~R3byJuJf9g)6Y&FiCWxkc)#(-MSwO1!?jDT=sgOv8+z1u1mOOr}>EvQJK!{bf` zdfJz`{PlZ4EUn9QJ9!9RSzhzY_U(AIHaTG^l{E;forZbb+;he>5=|MfiG(bv? z^ElG4a(PC^@EhMp7%m`?Z4F_)UaP~rZ|eEn@x&~mk&uU%zx&&Xe(Qs=W?`nHnJ7v}Dyu-xUM%$D;7C;of#irU=W_!Tj@8YAk;hWhPrz%(sT;rw^Lh5qiklO zc#)FUZKa}Js_b%ATB-^0K{GOEz*Q|B9annxywH=!rJjCT>B-~T<^o~}#*vMa!GO~? zV9q>DuIAN9%{OSYQHPY zyb1(s9L#B<(TB_9UmMM`pXb8OCHl3kylrX2@pYPtFs?dfNg{kGedA87S<$B@OQutGh>b~8~36UJG=h{BTz$brs;a~_y)uR#2 z>q2ptTU#eMb&Yamqf|{DS-A3994K5q*LT19u739i-*6^@f%CBhvy`^8f0=VfKMy@j z+WQUDup~^3!FqCdsJd8a_rYCF@88Bh+qsO0;kbY+tj=ffr2fpW^GeD~O~w<2S)!&N zXol7Bi=Kc6wsB0GW!Vakz|67Ci`DO8eV2Xq>k8(Bnd|i$r;h34$VTdh9y!a}xNI#9 z@Js&ADayC+oY$5N>@!w%U0DcsH>YkNGA8Sak?CLz;jgX99w+n9>{B1-$2YX{MT33K z?`||Eu6aOTr?{@`g8%$~IrCnx$Z*&Bb z63o|0HT_2I??^>>-hQmFo8{qUopSnV+xt^#D~8#S`M@6T4h7UkD-@VPYLKSJX&+?) ztx(kV2Y^;PuYbBuuoJ*A`xHl5l1=noJ5)4@L4=wsW|6rg|RY zsT~0uL_QKwdfauUUfl$h>bg;^NcHOQ^YvMErw6(J*7G5T3<|GO=;zg(YW827#G=Ov z*7@8^pFgYisY8>5qT* zb1j#R!ek~Q)#PQMUo30g&4^8(nxx6J>;s$#;#Zz9uy{*z^FdjD%$$_b@ORVZS@&ht zto6f6181Fdl_%=Fu>8I-lmI*tu!bZ@YymfhtYQPtzdqUpQav|AwbUhUug6Hw!cG?o z1L6&@%_Ato!yawoH;e`(isq}OCpfCEG?njklxqI?sg&pDe2w*mr*l(dHg$NUmXL!z zW0B!DZ3cW0G-gVI5=4ke0&BRTwXuaC?J(QGthcNbj6l2}X4{2Z- zHVW%hlM%>gsDm!m-MCO%MXCb4#W*-&oG}H1uJB9W&G*Fw)NpQw&udtLm^nS;@jx_M zbG|m6;$B0`Nv=DkU8uB4RSFyb$edbh*=Rpb^xY3)?WLvu`s1hi*GG3W8AS@4k&1b( zUlon+-R-nL3zfiNfN)6JsVX%sQ3hZtLeqbKoRWdJql3v-ZrTo48LTZ6F7&2jh8EK>OcF;bnp~K?n#mYvK^UoQYW?oN{R92!U;nj!{>c-C zvj>Xs!lM|vN)yAL)17eN%KR?#qDQ43Pgy=ID(a6wvv$Y2*l|~9isWEC= z+gtkRNchd+9PQ26+_&I>4j{lye3~!Y68iriMt#=jY!FgXlj)GFX_(D@Q*2WKaD+F{QiVuTzt z2bhlOhZ-Xi1DGh_p&&QIKKSzd{i1h1&v|#g#YE+zi#+}?H$;9LQadQXA*<{Y`1oMm zgIM=vm^%GZ?|=EO-uu!6GnF88FyZmquGA<&l6(GK4yrlxcoB@8$^425zK+Rstm!ON zxhyrx#;QAFmOFnTFS1TM;|TtP+Nx3jLn(9-9N1f(y6$ElnFEhnZ{KHMvB_IM^ZnTR z@+FB^{T2x_7fghUAN%s-qPLVQ_d4o}pLM30qHA-F(p2v}OtrInSK&_&^vh>~4(n9Ocp|u=&z_v9TtwQt8*3CpOTm~$TAV7z zk3t`Lg%E$$Ak^^+R*b;zJ8mWky}tl3gE-P8Oq9lZs&`tA7m+#ZTrLZWY0|lGZsgoQeBtoqLH2*wmMwcsiP_=HBDt&14voD zcG>nCwzmg({H!j2WZFFU%rRJVXqXXB5+X7vm%23#b?465+1STxc{hv*zI~I|n=0SK z_U0X28e-W{13CsH&tRjrFu8yG_kW~+{7?Qj75QB0bfh?effp)n&=zDr0ou(`iJ}-y zr8UV!nPFKeKf#|vqdSl8DVvVfB(Z|7vHj>}&_Gjyrc)B8Dq#XAk-EIpV!70KG&APM z&>WQh`9Hb?yp1OlnPw1CGg`MVvj=!an9p~adG%Us9*)^VETn8-7yAsCZ^LH)NFQFC zzlZOJ&%QoGH#Q3$X58{j9elqkqi-L@)K#e}cjh!PLRp;un|~$nMdwW0oggOpaLjn% zrD5(HJvlxy#&}#1^X2AxTO+VuWpAs-n|jV2fuIY&j{Z0t?B#r6>d8LyaN!LXpnt#Z zZVT2V5N;ze^(EWbpx@l;Cr_+IO;u=re@E}Vr*-h-ZH3;XeQrjeiCcqSCxvqQMgaY&_bgzPUm7RmPK#UK}P4}pbTo$T4F5t8(xM? zT+)`$eaxW}bvJv(vn)b@FMc zd-oGflFYPPkeD{LW5&QlEh_dbhvJ=S`=BofEle#R`8nefMoObVQ5Pv0NwYFizD$&t zIOLRyqE%VdYGBqza2Kc}R!gYZsx~c(vaE$Pdpzzm$^wIl5s~^J*wEeTIu(_a&`>u# ztGyi6nhfD&q2=+hf-KUVcOR)qV{@R&0n=E7kc%}! zSO;;3i;GBkT`LP>m4^qambq@f^T0&|^YhzB>~PFAI^lY`x3{M#cBV#ERqFWoSanHM zt=J;?Y>oxLO|XOW;oi%HA2-I6KmQws7Q{SD!L+V=vZ!nmWZ zQy0Lzk#y?)@CW?fm#gTjIPC{XC|F>3w#W9blk%gM+~&6B~yLTy~SP zc}G&7sNinM9{{?R-1r`$TuK-|56c!;+BEx}9VqEd2{)Y6k|P$x)VLNrUj718L9*JS zEfHwBK-C`=*20()Sr(f!DV)5~53A2%f>sCZ@NFak<#@vxi~!jfjEh=jrZ?0uD11x) z(Hy&Zk?C7`CnEhAyJ&lOkS!)&+}S)g)|)# z_RQJD)(|j+uD9Y)170&~hs^>B9nRjH>YuOkZIo|_CacYd!tj-E+=pwLS1>0ydk7_o zBr(sIn&)$aRBW=bYZl0Rny5o^XDZQnj(4!^q?D&CAq^zoU-WJNB$>I=eoT&(%zUohc7B6IEjtWdU9&e>-KGo zuMz(ct%0y=VjZ9fL*xqlfN(`oV-7sQ6L#8I_>x%6D=p@w@~Y9YShzhLQz1f{6VgIHU^-DrUl6!}gtS$?0FKI!`BG z_=~b%I#XNqBF53 zoKK&ZZLFuqwT`P!A?nOvfTjT;7e&Q4&X^S&1MS~^f$p2*Z!j=m9HQND(X|OrNXZ}+ zSu2cZoP?&euvi?MG!AAD7fi$?9VyAirUnc0Zp^QXDjU8V&hs$6fA)^)kOX@FIlN*6 zv_2Y99;h&%1O~X*=zwoagRYol2(UG{U+eT2!2qh}=4H_lmiVH8U`#dANSWHMQrfn9 zcR$pRz7^}YKJ0WWtJUO=+1un39UnBBA7lT{9I!9qSEY7RaMsKPf0*X5+nApL_A$Z; zM-bb2DG?!mR^BPU4=$mC3x}PatR-?T;Eg*iSTpD^%4AVi(TR*YDc^L&7m7 zE~xB^uYB28{On5EeLwt1r|WcDB&4w~d5J$72KVmm>)-i%e@DAJndXb{G#9l z(}mYIvxwgG55^UKWV)u%;`q7c{n7_tk|v2U_^997(rfC1c1a^_or!W+c z4^YdYIim*NA+34Vs!J4ElWIcWWe%IL zhOb_k6Ho+~;4=Jq9H+-^JYKi@;EE4^To6f}6-!;QutD}APTG_Ub9@=0`eosQTU!h4 zk1d*$hC#2%V0J^y0tuy!!_g`pX@M`DV*&}^TyJXxZU*~pjr2?E`G^1gC(|GZzd^R5 zD0Omlq}UGPvs_8Ppto&0XR7I)+xU&xh^aoFIOV`$4dX`l?vJ&%mp(u9{Y}E>b_C{8 zehrKXwt(~hUIt^EOb9<%q}yL_8%{b%F9$4eXZ|Jn%#jb2KO1Th_}Ak8q|Aye3@9ZwIzVLgHhPgL&gxLvE_DC?u0HzOLq&n}4S+9=wr$Ko zE-LdN=UgkIs_&~WdsvT8<4(H&8>YX`^Qx}F-bHz+i??N~*(lWgTM!<#X{?xYOhZ5e z9p;suEn6*2MIuy$l*R-<8++>|m}9GUyiR8>`1VbdZ?N6Ngq;J-kNJtX7-HA!(lwa2 zfdE(eLPd_m)vakGMj?vFE<%I(Ei#itXV2@`9_y9A;k7Nzzqd7J(kx5{94yvFX={~t zj+9?B7tKVcBr1n1VYB_D4v|)0&t>ngHaC86WgRizG_L={zeDXbq+k*T_@N}bNpn$^ zjx|YAW0qF+(g@4%zn|(yA7y&~PNS}xEAAo{i$c#2=6Z3s(7c3U5jzK%s5fl8j485a zhT2#%o;?H0!eQd*E^=W)apFsOXPj#`ZJ{WxG|n2$CPc)U=;6be9zC4s_MJqNaibtC z)wa3nB1iQ=L5%rNq##OFRe=r)8kJqyi-x20TrtYAcl}&qRr{n z=tXy!6sz|`Z3%|5MS}x(x2BdNB(!R>7T{Haus97oEcK$9#sW-Ss^=Gy-;gnsV* z-484EUe~o*_T|g%0e--caBU}{RaX_donXR|Xqq|_)YRGsd$q62m=b;8ecE;1U7Jp? z|LZDySdOoUyT^Ooea(C~Ch!Cq|e;j%QG9s#F^P40ee51V56iwR)doN&%FW?bll;8O$U z1eZZrzi+JaY{33-+=qF5JA9hYX9W-bTVrc3(SJ9{a`y2Y0TkczS1;z~XgSNqCa|Ia z80~0=tyZq_UHX30C%)_7HZZ!wSf7mY8|#9zqyNTIZU*~}4eiwm-rt-4yCsUPU8kxj zbaK2f$&g<@n~QYw_qN*D0BrH~x>UK;QijPMxd-F)`azccBEFl?q?{2Qqcl8q>FHlg7AF%B-%R^R;kmvw6|HR342 z{2@e59=q&VXrd$_vFLbn^$5$wwO#*P+q39*Ki>Q{lC-x&N6KoR?Q7}&-LXC~!j*k3 zP|#N9OQUQ5(6OP5go*`Uu3d`7qX{O0&VqWISk0!v7`8Z@q@H~9y+hI%! z)-BA7ehWA??{%x9D0(xL-pQ?Bzbr8P77z{+nXw_JpwnxF(~W_z?P_=b?QmSLR>Jn& zEny53m;f+TDz$`JVy0Roca^##Rg|JB(5fk0jiN|je=pYFEY?qU3jO7iLi0tfW!~vY z(`sHux_v7%hp#C_>9%SIuxk?H`iuYoAOJ~3K~z2{dcuW$2dH4w7iJ1w(XqcpOJ zI$0VhMPd!{IEWfEgazL%zgPNqKHc4sEEB=UX^oUbEr}#Twf^i$u1}62-Y^BMG|OND zIff;1d(f_5X~dl_^mFygwb8-2Zx}G@Xh@6=0!@=b5B5^s!?P!9>a5Q=RA|os+_yvc z9+u;uKfm`iQ)YV`PvZfDZP4Hx%|P}Vv>$%(gYW4lfAw?y?3XVTr($YGsg~X%t|%$k@wDeUe=(S_t!E4J=S?GW!)6=iX-p` zf6#?Z*ZvoL4rjA0OBH!;T+&TWrzdpC>lfce)vh*>o>1HT2Aku({h4mxn&2qvZP2+F zHTUM-6-J<*UUHYeLYe1f-GrOXe5VNS!AtwjW3qj^9fbYC`qFYe;jw{YBLM;X!XBD3 zSSQ?l*>*o?c${X0YYg8&*qW5LFQcj&@y9!=Ax5|z(EWkTq0J%fH_z1?^Nf>0|F8P! z5$&sfcV2#oN8|cqmI9)0>e8*UG|~qjzNfG!7|>*)k4}XZVk0qP;=FP{FX={f<6EGR zc4o18pLYZ}5-uZA)r66mavUvjx(AVt8ZMy}bXyy}Q$f7N<3GT~vu6O^*dpCh7u8@J$+NEEO+2k&`V|Uy4lFl5>_Sb(p>EGY zjgk5{L?U8c62|njT=KL>osDu{@#nU=d7VCPHiPp0-{w32`=a*_=3zQCy0tsg@BR2k z#;7W*QfWpMjzC1zHUCoFEwm~=2`ZKI6YbvF)ra5ssyU7yk69PqnX5B>@NGEnj(-VT z(`Y!h$`}$sgFTmLzaK+85WUFSv1KnmuO0M@Yq&+?Rsk(a zE{|XNvD}=)&ENLXW`V;!dzInz1N>;}c%5tYJ(>^8!n7lzBo+)uW9ygz%hj>U+gE6~ zQV&x;8VY0D7@O*KT6Od7RYu_S&UBS8Z}MK-2t4}j;~$rm9wy01VH4=^$qVO)g#}di zNLF8)cYeuF+mKjagYy%{1w@e4 zYE^`Ji&`Z}!{bZ^Ve7g|wb?~FqJ{FC00*$n;h~8Kd(~ggWjB7YF$T-LQW&O2$Yzs; zvT>^72ua`4NU@+DtJ6YB0|6YVMM8o4dW+Y2Bn&u#cebF^%NT6RFWtBfI%{j1-)n*b z^>i+uYsgfw7yiFKAH!@a_I=pYwy8wOuQuC}{5J>mNMQgLjUlI#V1&1cBUu zw1TiA-NY^#OWL)xeFz7>+LztkUUPn~p}ESoT-btgF=uGOtY9nb%p^lysxEcW8Kz0B zhqFQ-FKd-yBFtE@F-^0Hsz!QzT$@UBHpZr%LIbJtD(!0o7YAwd)l^+CK$2`c2Egju zM$!J+d|Fr!uKu4NZ(r8cOW=z}5uWB3Qa3>x0d0nf+AcA34y47K8X~|d=L`%0vsg!} zln{RPSY>`>j*`)oKt;X_5_6uoGn?_t!s`+8uB;n{Fe=d2=$Vk)+K*-c?@j9ohJ!6c zT;5h@_iS?racuQWR4+dlhzNtafGIX6R2U+ZG-1ompvV8Oo%^$ll^ zdA8Ys7_>q2^J~pG``>E(+^ZFw`1BP)c$)b_ZeZ`+{hrf=c|zUa`8HQf+wdI}Kv1Io z7b|TRdbGczoe9h@Olwlb@faXe5G@q;7{vMYobA$8Qnsxh-#6|TY_FH9=4Elo{5of> zR)6eAoR9cZsW_M2c~`Z$KKk01^n>60w*J{a|ChSGcVG2rq%IDXHk~3gfOb>OPYzTc zzmS&C_5N>tThrTPbxEt8RGN)jJ*x|aqnV1F-4lN=Knm*y9Z_%*)*Bjqo#7`qsvJd~ z!ufOO%=^y!YSW2Q98x1NKwHDYJG*e8NtT(FNf(A1?~crICVNIvRysL2Q5F$V%+;|u zh%5N(U%)`FVAit-yKUaWjMn&=nT=OM8+_2v3xi2;Obbs8Zn9n-Hok)j`F(~tx-sE+ z!WmwS$>|m6+{uu~@W?*1uPbb0)p4ze^Tr%TB+7$U<3uVSKURJ6sk(GWT{>18Ic*_A zfx`SLZA)`ek&3WT(#8tgk@EV9IfpHxiJ5-6GpfDVIn%HcH_xv<0;i$kwTrtc;Ho3g zbzRUk!GC89%?_5<9N16}X)nFbLHaoN{MmP^jNX>5KUS5cp(c~m7#D3|ie;y=-~9OE zi~#WBWQprG13?%4t#iKoX~>lDxk=lW&U?~1z&!Q=%=v@O-^q6#@?vH56>*?*a3U@Q zakjpi+XOfOsG7Tse$DjwUjOyWZ?wUGOYTKk7<0i$VkC&YzXje|dj|w5Y3JF1zP#p( zbI>jScM3;}MB<#;Q43D>!X{BV>h$Fg?`bj`t>(kG;-b0mdEVyzGVNK- zTO&z#S5;nhQ&@fY@`r8hzAXIsZ~fiZ=B1cE zojrzU_Xl&OQxiqHzb}37D}lcM8?#f%E7nOoCi-6-MKTG6|FPY*B?301W)Z6;b4C#u?|(l}I< zh0cL-fG-SlV`t|DngqsZHLVFLFIyFPsR}2!QKvMEl%-Ba2mFFKnMR)V?#=(_;l$6g zuhFOb-f)Zm?u#R<6M?Jv>t7eFXXM$$OdWviUAk)_Hjd2h3&6 zTkv1|Ys`ED$EHoyC^k*LHGb#E^t>`jM@!J|jbp+roL$XDpWM8=#u3SUVuB_6@QP6EZjrfs>QD>Mk*g zi9iNZSnww8Kt$*cEz~EiJsxo%NDoNI0psgl!@0X`S$YiJy~a*EZ$?(;ECrw3#)$A3{DZWGnk6~|_yW1cBNGOSKafR_1O z%OYRFwDqkqcA>`OnW_G>EX=7`Z_2^&|0e*ju|X4t^~BvnQD@-yPr7@Cnf@fALFW4V9_X5wLShvR!ClK&nBgNVbp)g=tv|XV# zC>14*#uI68Kh*s@iQauM(R+_3W@eCO5Qq)PPajDnQipa&n5b$S<#lIFmKR5rp1mmb zz5)7sEZ)db&Zm+RmS#>eSce->OD^H&}S9G=Dd?kW(^)dm@hPce4r#A zD;rIWp;4PA*_tuo;e$IG5wqD?lkvpLq#uVzN2+QUX$5URV4wPYo!jP`ced91J;&or zMCbB2mDOvw#Cl)aR@SyOP^ydmeEa;}&yBxtD|48}InISCs_!Q&7qggreqz2pFiXYk z1^mEYXajCCTvqRFUAVJ@F+}sKE=%Ia-&}8L1g>}IeM^o08&yr+{`>4qcJPOxs$!|d zV(FYvaY$bA0;l%JjcvLtT-*5qL%@9+j(K=Bn+2LpQ$r{#xFR>#7iI(&Q4#F+&eCW! zgq5HB*XhKHKr`YFb?xn?I;Fdw2R(WYVn5T0fbNi8)e?p=caiCy-Ml#XDfew(R_EE~SToo+G0R|9)DX@vRE!xw?`^*p464dV42Y7$ zD%8`Zga+(R)Jqxr4*9Mbg46f)Dt)%S^#Wq=b;iw&!Fmv`QkO^AxO_xiZp4zk#ssR*P326tw%XipR(OrSFWbj$Rr2i`*4EF) zSX@aOFpDFsCMI-_ArsVvI?WuTO`YDqwbbq1Sae1hpipu0PfMj4E% zTBTw$d5bZVJLiI6SY81ALU{1nrVObeV8piFL((~Ke)Xy~0udiVvZ0tBc%-l@o5cDKp z*g5}$-}(*x@t^#W{`5~i(Y>9iItw4$Dk&=E2hTJbCHn9?-_&S-rjufBjIl0Fl?Ab8 zyQxmfTn%CJW+A5(CpzO)6Ph6zzRGPF${(Vb88wgYdmAN zvtt?`<`+TI@$s?k?`W%;2^?qo6@(*r=u}J+L=S4$1jHISAp--c?bK(aB{Bl z+&f_A5Hi0UMBQj>6^j#@nM|75{)m4SH0vDWdwtM3P1N)Z-Z~{Vn1zIjZ04tL|`vuJ1KM!kko5nEZ>@#`% zpMQ(QnTs-ab|PgXHoXRK%{R_3{UCh-?z%nuidyw_n&DoQe`qo9&+XAODfH=O)T3j`L z@BnH!{DYi3udRd6PCeQ@56047BH^H&1TTp~iz?F9jdpiaed8PNDhvyg2|9j+>yP)X z!1w3%XLI~cHRLV)INPpPIH}^#q=%AH#sV93e1G)JT^m!J`GtuNicT-)wVDVUS_h9n zBHQr_UVFliE?uS1XWRGY2IVSst@8FrGQYR=3nbW>6unw3$me{1th`vb@Onn9Iu&DF zA(+~66sa}P!on3IZ-@dV;nWCoBpHng3qN>w zoai^+OZ5BS8tFR^0?ndEPoG!%`IA8Nd8Q*qrlo=wQ!F$9T!aaj zIcL0C1I7eLnO0xf|X&>*K`vV1sFkbRFy@PCEVm@Bc{CaikZ|A8VRoYSd`{ z{HeM+*X{QnX?p*Go>Z-#<(*#Sjh-GZ^?aVI=n{4DNOkC$r_P^*gPDF)vvY;D5K2X^ z#giwBf=JoUEtMQ!TexCg!<2H^XLomY44#nw!>nB{mqv*59vq8)UIo6$Z|r0Qr72!_ z9eKEIul6$x_Jj!$_icYZpTA$FJ^q`E?q2i67&l}@6Ov}be9dttjER@SldT-{LxF}x zkH4D9)0zwh2e9$$D@6;7zp%qG%gyz+M&L$c;%$xemU{lv|MJQ7&ZEo#o};s?I~^Sz znHm>MWpfb^2~9SU&1^K z=DLcR1y+VIVMu-NYv8gyIm49L^5Lcq&k!cb&U-s-k+lJ%1NB7{L7BR@BODxjui@Cf zr4W$YzHWnGSRg&T^G!q8PR@56G~o=bSIKvuVvFex_HFCI^1$fp%X0^~BTji|Z3?8K zu1$S-Z)Zd-F-@njvMkYJ=_STU@A`hw-kvyK>7e)Rf886aa@*x)U7O=iUK=ykvqk!1 zENgXbEclM^ymLQ^(!&JumnQ(LETEg=>-?r9WK5bae zu#Ph&*nDjp3)*5}w(575&}Zh@l|mh+qK${~NLp5{o-bQXC$XkM4GD90{UDtJfTA_5 z4%>RBeS?HyzE_}K1|^+-q}&U~=ydkgFZ-^C3qpnZayI=yY%9C0axE7NbA%a!v>PV} z!Y?r7csv;isUM61f6h?8ISyQ{;#E^#{$Ss_Y^+Tt7bza+6+~lGRZbGwm*mK-e*X)R zeoA%aGz!>H97+1}YOgzoALEymyKT&e-#GAd3^Nlbuy?h7ZAu!4s+VY3;wxdKWt|#B zm4Hp(x}E6$MEa9Yr9b+((v#y-zk-Ol1yMtkhE~Cd$BI9}gYzPxK=;bDZxIHZ{pQO~;{%od^Xe&5uSF{;()((~dA_;Ox_c zO*E6hl*w0F)T+x$^LZysLuRu?qY-{6*dcKS**H^;2127%95zaEn4G}$0RO3l<9#E- zj91M;1q7Y#x9|UT-08!%Yc-x*Ub=7GcL8l~OSf0UoP|LVcA8~@?oDLGH0NPs2w!0O zmF$hM{Lmo#tgm7JU$z#mtF69H>O+Da#DS{3RvM)?Ucg6@7y8CWU)A@2@Gbq*|MQ<~ zy0fb^lsSJSe<{~UuDj&lDBW}OK+6vaUkd#cV>XH)hd@KilSIi99#Hs_8-%j zU`&ni!}=avJp+^TW@Yt3#HXOuvNNCSgUmONZ*l}~7!z-DbYD{TSKdh<9CKK^b3$cR z>F~voL;4LTbCRc*6l1R`V%ssp#^N_(Cx3Fk4ViB{?d+ze>Rh*k7z&OqQ`b$N&&LR0 zF1*bQ)`(emroFVGaE`g4!M4)C=O9kQf`ZN{bcybH` zSF-z`cf&P9s@IZQ=X3i;g6(`!8KDaIam`3&4Z3xRzc)-&to`OKcU_8qa_#y2!?kZO zcQnR)e}@{6ICx8N{D^n@I#7fe<#*=vqX1xWBu8$O8xBdLce^{s;nlu zvyVsr#@7Gl91QEWXBZT|0fU#UIDdIU*Uu>g1CAvr8+dCxP%&E^01-mjUJ%(wX@Uui z1_QnyAggC-r=ph10zW5#$`U^SA<7oE<_WKA1eFmep~|vWQ8b#*D|1*po29A<*#yyI zCMKAZw2I?EJCn$1s}YUJOaXh%RIJ)eZGPQ1-^bUvzif0-g-AOl zh=;)>J_zsI(i~P`{HHTA7i<%=PCY)k?zgTNv)!)~6@UXc#mW(~-ZA5ASR*7WA z{rkWB8~XD<{fS;YeX0>!1Wm2c?WvMG`+8P3TGUHrBQ$eDBY-g^#MB713e6@U$VHl9 zPwF+v3|3tyc-I^psV;JjA3TyG%;Gq^Dy6pM*7!S&3EQ{TX*?b&9c8w*2<^LAEKHLO z{D*vHOH?t05tp1}^7R@|X8MWd+s3sO_BQfd>8HWF!_oYA{v7hZFMnsBaSU?cx@l@v z%cVtzf_Z1`3v6=Fw_LNT+#2m{&cN?HUMV#${LkeZbd&QnM&K;;y+&a-pI&VQ=0Wqo zh#T*~t7=R-Ruf?hl^=$b4&GYAb z1mcibho_gYhX>zsFE#eRU+2CJO*4XTOQD9tnzYk7V1iO;poy@Q=!x~0!MP!vee?j} z8&yUQVN@?sWo$oPChGt7!KjSO+| zANxM=o9~CeeV*&MZ9&vy{W$R<-5j+Ow30A zENf%f4>v!X5H)PU^*&RdLkuo1cUwLXax+`$I*l_4BDO;16~6=>1{!9BV~8c+=dJW? zA$>H3Vc}&iYuLQF1@7&(c3kGWx1Gn@Nu@o~%HwdHhtI>dk-k_ijA_Ao!xRYVwuP|m zI*rCIstfE=J@^0sAOJ~3K~(tykUpgG_z}QcY=2SrWiG!@ZOc#j{6pKrW{NPT9dhvX z<-dp4ve_Q2jdd=!R^Jpo_A2l&9Q$p3Kh<{Y+d75(BSNBvQjJy=a{}=rsYn8qqfTsL zqxeK$yB+G*c%<2ESAX)$T#t`S9WNSv`Ag2Ho3;I%fmyW?CZ=()*KP1mj_E+nj?nO9 zL1YMUV$mJ^kSy{$DygI?y;x zG<$Gg<2$#tXj`H0j5%}?gOf}xEcMf8hbqg$G&?QM@;Qw*USHFyK0a1gSBldNb7~X1 zv^CK`LUU2Us=&n5GbVr$_E>LrMDYvEI4UPF@yut33z_=QIW6#T;LI>$&R@W#cWCSJ zJqIhUh~e|Og+fDa+Oi0xR|kwh&A-n9#aW)fAef6FO<7xHaOoD17eNnZYY$ zW@i5BDx=I5L&x@0Oua(9h2LCnX#`GFHE*fXn`+z$v|X?Vc4eqU-Koqgb!B6=W*yQGZ$^S;@<{H6;E5OpJkVWXxg6{m?poK7{FA&}GErIKlK zAZlP{IaOJwUTlX1_$P!!51&!hm@k8db~TN~lSkr*Q$l=9kW4wK&tX;ok_v(ec4_5x zxnc}fqEKC2o72LtKbWdYN_|phdit+IwZ+^dU`>NW1AkMknmAH2PgI4}j{{E*8%OwJ z#(~kwF@Nyst;lm^L7w?o3?2urrfF)(E53eJaQ4AD%qJ&%SAr*!(->*4l*U z`6yGqJkmQ4AL*U@Q;ourg_NtiBaMQQA+@HQPdsyLm8*m2ZHNf-;^%kU`_nCa*{{>% zvq{G`J^YeRdwjiCY8R>rGX-U?y)4zdFfqM$6KOwdb+o|5rZIJ0jHTs{42GXym>+l&5HriU<@P1fl0jJ^3rXx4BPIXjTyG(`_=ow zfY`ENsnd`C8#DAz1SB>-Ho~9#Zv#B{5jHA%`MG6DO82t?EgNx#H^&yz&&24; z^dfgm&@sLSBFE6M&2X@;d|Ob9zUX3~xaiu1|KV?*%|w7*Z8(qp-e`pMAbnlW=`}&R z&$fxM)v<#F;MDdwbIaQ)>N-v8Om%~Lb0P(~Ztdjy{v_4y-I4zI<3d0EWTC(Kd7_7R zLfx9O=Y}HCQxo8{udxt_1-3E0rVTdmn9?yT#S=5h@Wnulo1G63gx-|J8b185Ux9uh4qpwP zA%M92dNwnh!F>9xL-_D%_Klx-8xuyvtrZ_8F|qM)RHh?UVWx3i=)I)UeH=rFvd9Xy zx3_4D1Pag&ar_J6V3B=->nz0iR=nx^X3d)ex&n}EYlt6f?%o-2-PLB&VFEg$xiqbX zpCzKxH-Gp|{lEX}U+6FX9c>YDJj ziTOj>+21ofr0WPO+UoG&$m)pVk&0!mB#Kqx*tU0?$>6O<*29!(E`gV|8q;Pn1d*a~ zCZeICNk|kDK*Wz3<+Q8sZDC$&UOfDh+4hRQj2`?}WvtrRrvTp6Z5m^J4~E;g;h$Zi zs;V`L(8`jMWTH==9Vnb1Nw?lt6GTdaPF1SSU?njnSB>OJVC)EB@8lFK<#luOl#1YEC4F#3XIq z{C!^gfhjv=>@;u)l>6R6mH&=>9)5hGwR3&44r++i5+2HUgM+Bqnb?)g0#3^IaTFOUEa<4x&_(88+~(g==nMYQ+%b zrIW(05V2Fmz1EMnHHNGQkZ;o>U~mlX-Fikc21Q361_nF*gb)QaVHuw~vyU1A6x$|` zQ92Wi5y-1yvadA^_OV5pIHwpS^fqrG#5{x87o|nuVFepw!K}ns$j&T>uyBsxSd+`= z6n|!4^L3q<|5ei+yq#vOxixmR6~0-&ha*=OLjY6CuzAbMBhweQiJ82OgGgW650r*u zJ)DO6Hy@wq*^^NDBGLYSYMKNwW+6eKvRx`oCx(;2j3DX}OkK3F&?2kK#=(YPkAudc zsW~*=7`(E*)Q}#a&I?{l>hJKLbzj!!&U#)TWY@%Mk|33FnlxS7k1vEoZ?c7^*hwC1 zS%)f?&S@tmZKE;HF&m@Se0|nNV??aa!c*=341c&bo^2NqNQgE9(;Z1MCNL?C#gNtE z#>svAdT{m`cKwZ3&DgAAi>lmtV`GK@qd@~N)o*eg&mWsA=em}a4h zqSDDCS2D^BZ_kZEX4JfW-$7NwjAJjh2pdv@FABJ4#|sl;BzyY`lGvHT850j3D8kdM z*MPNEjhT#$M)-!q(J9Pk=Mb3khKz7}DNC39`>%ku7XF6_XMXY7{=dS8*CGU=+Z zH_jqLo1=2xf#>tB;M*tkcmEyelO2M+{|Mg)r`6yb>=_(`K=d4QA}}CT9gi|)BQzW; zbybb;GFMjbaML@u99F$`-Sp!G6U4WRZ}OthVqOTNZ4mLvC^3@`vlT@$4f5B2OS#@_ zwy)2ZN{uIIF5ZJmx#$l2avOUeb*PP164QPXEz1Ac-e1|K9RMWe^Zm0skooLIHR zJNE`X$hw{Y4Wn3-$;=I6-syzFhV-nwOTAs zEF2u`&|ully!G7FwM?b@G{jt{HP@eKIR4kM-Zxvw_T%eV-`D&tPCx$EE#00-2S<&b9JD%GqAAqaJ`o0vnZdqjj&PB{oBI&QkTt?=3sb_k zapQP8)lR2I;m((J0FFR$zq?&@AQ;H}v7dSt`7jS{aWZ~PdTOMmB5(%C`GDjU zW^$u+6q_~#D)BHZ$CFrb>R^X*hu7xs;k(bvv)7iOJwfQS^@1i;s#dcM{{s&13kRXZ zVbgA2LwNjkB?L~xmD?)~hI$x8gL9mu`tEnWt^NI7WBdV^__ZR=EWVt|y3x_eQU^zK zbC`{(5sF4=`!UAwC0Ii+)L_=J2S*87m4&J&hXjz&Xm?jp8jDb`m@~l^ATN8I$16DJ zC@)J=&8E&b3w|UB<(%ia!(ICI=mndbbH44jou8(;ij(0`VS-lCX^7Zd7qnvtKikSB zZCgIKd$@h;yzhqT+sYW0&Dw`qYK)n#QI(%)d2*~M&P;nH+|YV+PQIP*sbM{=5b84j zH@q-SK$j!vqW6Y*Z=T=m2%Lt#H(S?D=^G=^<>e!iuk`JMTaP4qxTkR-P}*-#5!0GAB4F4W@B;X>D)^J>Mp%;KhO2 zR&qGm!QHFgVot%q!gXFfw9VWh+FC=;go7XC1ds2LsNeD|0i%^9J{s#F@AUYjR*5=y zk{D8%myX%vVTbkO)z*F5Rr~bz$IG>_KMq!ep>MbKqk-W^^aQ7Zyj(7HbbO#R#?;BJ zc|+7Nzv_p7oK03H8#V{M#0|{{*6Qo@leVySBSOls5wJE_q1`ab!pvh~dqIr<8Jk$H7axxPGq-_-P*uD^#DMS3HiA zZE=uy*}gCy_UDAo2%fk9v8L&t|LZGQeQ(Zt(T;P>D;EX?zZRAKwe3Q9rhveNKnz7l zNL02%A#Jt3dFEZePrRwQy6o6&&$ngoquu5e8Z((tBemKaNn<==a`gu({pPYU>z}u+ ziC<4*;4}=Z;0iNX1_Vc;U8i>*-q(j8exQ7DqUGVC;Tn}WQzc56#CdUaQtI$HS6-rB z)DyXAq?z9Xd?1BpQO2IdmRaX>waD9(UmIk(d3?ho@awr3 zz2QNhm-wtbr(rkApUDU`O;3rfaS&^VH;aGOMtRKyz8}II&%@tr z?k~GGzuC<18761SqG)qV(U`qw+~Z}=V{~Ae0GM%Lu-M=@3g?Ht1Qk;#;Job*onhIu z2Sj7ok8S-V4O5QAg8ChimL{EM*pb=?y@SbKvO*ok3~_HiyZ=$;wzfD#)DbSB?%mxH zLKen~vB56@*Klk;yGCEGX5ZG~-N3}8?0sYz1DjTpSlUfN*iV-YYiWvZjq-Y!!7lzfF`c z=O!t~=K&W?L|g!37mXwy7YLYlG1h*a`}-!N^li__rN-h4nSA>#tSCg3h5a2cC>s2v z^hAH+LM*r700H*XBQ<5M_ik1CosXm+evs+jY^-NbYkmC5Lh}mVZmcB2M9wiXJu{Og z*7e5X+S+bl%$ZQYK-v7G{k{);?tl9rVJKtW!P*PyL2AY#aL$CLOc5(cUODZ5I#k+cYKo zx7(2aZE0_^*R*r^=jYYm-(=mC?dk!J*II|90dL&xB1%Ub>ifU*eI;S1qi4@Fjw4mQ zW@a2=>KSX9S2~^-Dl51Wj$np)V1%=UpoG2W3~ZvZQge8$CNDMKzpWODe~lwn%m>)7 zBMbLU{hjTF>+^a%9vcJQ)?ycExyX$fYmASc766Ca-0NIt&i+q7O*;cKtu#@TIL$-G zfQuFUN=$^aRawevT+exbnPd;&aCkz~mI46;FAP;Jk5%PMg&B-h*O&9g!r`B;pXNZk zhetbuVi?~bp@gAszJ8f@-Q>BR5qR7C(Dk(XZ$c?u7sS%vqbn@b<$Nw2k8!}V=-9w~ zxWmhI*YBa^T@jXkW9e1Y;izISTr3ynHF!Ku6epQ+cjHL^<}&r%d*XXl#|2|z$ira0@D1%;E*h1kv%`<0N|T*bQQ)*DnqYlg z8)7`H52C0?Tzvg+>TcuKhyC=(1OyuC#w-as-F>jHFk*jUe_(g1%!hy<<2Ti|>nL~F zMhK1J1xadr!ugCOtQdq#phXku7srjB%OR;Lxwu}>e1Fy7zC3@w>h~ArcP0!ygQ-6bj5z^=!bIin%!lB? zzZ8BVltk*1kU*QNqJ;?Eal4a#^O5wozZL1Dhl%Q{)srU+J$+iJD)HHph>)-bGkrK_ zQ?ad-^29nQEx%EYjYsSd(dD&cYpj1=y?! zQp)#jaQn>gMBLt)ZS5u}<8)d0-(K<{wb$hEDZWmYh(%uLI>9vGn*`d4TxeOt^)@s> zhFj+f@ppw#kS~7aTVR#&YxCgd+mA2%P;5?CTjj-4@4x?^9zM9Q#nTsNE5>`A#KI7O zInmUCDww!L)?l!E$GX4)0!Px(1cRYk5#IB~3q_+;>F$oYHdIhmc3z`Rz|M?Q`>_9x zHrd*XBF$zq6G`&Bsw$n#=f-5VebevNW;k*&{Q7<}_mtJeq2erE(I8B_H&x}C{8znT z9S=pVz8_ZKpsklGcOyS#xHdVh792?G(8pC z3xTcC!)L?VHoLO1x%<~=w`l+7)$iL5AJVp6z^X+T8N4J7vjfZ|jG$h9>wH0=T0GmG zni*7GqPpu;e(^}pg#^`0a(!D?_Jci=Yxz8vygzt{Yj3_Nw49fQXrMNGYc^AoAZbI@ zybm?nAKJsUIOv8wf(XBf%M*3Ox=nKEeRg!U#%Zc|-?^*SqK_D7!r5b90@3i}M)}+R z-b9~$(r&dD~pPdOdCj_iFo;V{0OIu0TxNrRhwwjQ!C@H^59jQxuQY zwXuR`sdsPX`tf%&{mxfs+6!_WA1-xxu+(A>Lo-wo^;!mKK}2Y|^z*c(;YeYNUEN|E-pO=5fZY$Dyhm1uWoq%=y6A<6g; z=VSf+CQidG19XWbv_7_7413q|)9v(io0?i-sS*3C{U;P$2L!gc<*e6}euO zKJ{<@-NtmtBuiq0EzEv!7X97td`C^5Yk7dF089qP&+SiqYnnx{Okqx-EzvIzA{uq3 z34yRcs!vYT9-b)KpQ(uw`z|I-Da@qU%_&Sr${fOJ8Yh}er&zcdPL$`R=8N34#K`NS zfSq2G7wt2A!^K_+o`tjQ4s(d+^cnlQGmp8tuj_TnqA&iBa%$VlTpAj(RaIzlbYT8w z($S1Vdu4*@L&=+i;Qnme)+U(oTreig`FgKe_*Wll_Bw69`S$W7@awquTz+)kV9v=% z0a6Hm5#k3Az+7x<5J#_rSXnti@AgHcJAQ)bCP=<%dwlXd{G|A6<)&XkgAlL3t0VzY$9cem& zG0~|;tml#O{_t9dwOZHA8UsQ0HLxv!XVy|jv8 zD*p2MJiIw6yR)6|s=~f4!&rxTtHokr&J{gUNg4k?dvDexNs{FE{r!w1kE*Wjo(ltD zcCZU@XBQ*{;2{76AVv6qPXKy?+mBMx~OW9}Z1;6&h|tiZXQB<74!RH`5rOH)Vcy4DzyHdbL0#WBns zhEwp$aVXbsHw<{Vz^k{#eL|4d+cz@CEC@SSjpbG$vt;qHBil@K@`*6ZA4#-hA?@@17E*hsb4Hqp3Jm{mKjTvP&0-GZpLAn zo8$%RA6rHPF34w-pias-Z1KpkZZ>XTy|28@#?`_8P-257NYFtOJ@nENjqv{*iZfM)h3r*4cWK$N)Wc7C<);3?b#OuQ;g%jT9 z1>h1_g{LM8UDOMmJuTHWo$BnPAjx4TB}FhA1vAII2%zsBJPd&U9jzM{ebOWZhquvP znUTPY?{zLtmctcn2|&0Yx&7%6rpl{@=_vFa`r>TxkSds3zp?X@y$#fcaEYSSuG_tT zw{}d3xTZywnbNSh^8OaKrWP?7PW~O$~ znz6f9bs4nJ>3XDE6;pLXp-J0o+7Ei&5Bk-*((|@d9f=wG0y@Ox*|fN(rB8Dr8Tzf) z4H)26A+h1Vw^T3K1h7Ow&mGZn6EEM0;)fj4GHkpsX83WgY4#ZyfE=S`W?O|*FUC^G z3SR`t5pi?wY~@y0YTMuux$eDk^bcA+T}Mp6B!?OWv~V(+-kZIl(YW|K2z`9xhG zP6WpR7rlkBSzv8ovd6$s2&SenHe(pXHRG9a&5tq8uOc2}&Q%z*(Kc7+nL~(3cWPT8 zoomR~Qk|*jMvcpt>gp3iLMOa*V9@c2sdcS0*0b8wd4Pd2W#bCf6?C^vnkbwqr~UWX zS8ZPa03ZNKL_t*0vu$c^mJ5uqFjji=0uj_GZf@a}fkPW|ZOifTdUGB(eck5e8&+&_ zY=4}>)S*nQ?{lO*5hV3_BEG!qu%E6i}~c>PM#p_0m410oR6HF)(E*$;qi^=ReWOh{5HRT4)tiINFsN#4m=qD8hy+4A;Kb z>FE=bn1D%4-+T4y+SVfu8@Q~mFe+`$3P!ub><3L2=(3&lBT6!5WubaHRaTV7*e&Wh z81M|4-W93V)4^tM=4P>L2jejOd~ASk><9TTT_3za)+2t0#s_i0aKk#0Ri?7Fy81@r zh5`B%gAKL?9Lcz%x(675G)FAtCdbBPt{bJhN4rSL+9qo%JP5T zh*vTo6=klx!?5=(H8*TY>hjR-X@nw7$5j-6BOYE`lRtR zcv6>YnnqU_uT57M>$|*v{q@&cby<5TpU1Ed7Xz!jg+kj9L1DY*+qQ7uf&K^qv=e9V z#fT|3X#5b}9)bmYdr!I0FR|keh9mDBd0l3gx9aM=~!BdXQ%}$o#+s zTz$Kngf+x4o99tK_~A1>IXwwPF2~N`$b72?kVx~sm$&u%=JU?!_w=bfpGg&nc{V!q zA-^_tM(u-5G5y47@BI08|{I>7=@ZC1ue!Tn2XFuOV?^ae~;Bi}aU}}=am;swU z5>9(3)k^>LXLJ3}fAUm6{bZuAua^4d^R=$8N1YFu=0&L~n`Uf%bd8FkQI?_NHfm-2 ziO~1F4<3T;A;P?Veh-`3(5J&@f46UJ;{|B;`_^q?+)sy>A7)n!DZ@mjZ0vk-G43eW znGgGAI85AWn?n~&sOhBAv%;hHKyyyH#VOv?9qeZ{>2bb!A<=0#<)h-uWFP3V%L3KSf zH`li+B%yzNt#P_@lOAc^w*NQ(%b)+BVeoD~JU%=G2DX&iL*)LL=Wz_2EC$4|&{JD2 zm$q>EqQ;=`=R+CnuTegjJT9jfT;xGsEQ{(pz!pJij zc^X7C5j}Mmr!2ufJ;l|V@f^1Ody4BfQ@vZrwhr6P)@+iiWg6%Zj5_>ARcAxO+}XeUH<_GI@w$sV`Ypj zm`lbi8q{D2WbBP`&q-T|8^~eW6Qicx15(G^zGg*#u>XM5VNLHI9>Nk8fw%(>-$$L5 zQ#~y@{ruxb|MC~Le)02KnO6Gh%Z0vvo@tFlKtE_YjG7k{mBq|Fq_k>Onv7Khvz9sKae>bSX(ZJkGGWr>#-f;F~oY(^JVI6ZMw*Q8KpKlxO zhCClXy&nd4XVLe|>oN6RF!1RwhPLZeW~Ek<>&eoxy@GiD_B}l9ZVUInhRq%W$tRy7 z4@RoYAXJv?>guKXq1Ej4M9-hUFmYQ{Jyw0ad;Iri){h|{7zSDdZ}&FTfJoTpN}fHg z$JvRuNwE81k~uCmp4^$J`Ic_LHu>2^9yW8ROE^unnQY<-KYcV!zguz`3%^9k{UrxV>-(< znFaB9VjGMuwGi*yT;A{Lt;`7;A-N!aKmuaST(fDZkDkuev?~)St}1+#vzY)tNk7?R zrfk|W$@|dbZQ~tEd!J#)+VZqQ6qns>8`=qK$<%EEag7uOgc)8Yx}LrP0XfxGSLn0L zwJsa*Ss=z4>=tz4bSm^MWIv-cQLK#huh=BV`}Y0SJRP4KHHl=L?w90v0#5s3DV|MJ znJ^defPvtLc$K^oH1u5r_RQ@EwbLm%49ZJC@tShC8gzP~v?PX7~-8^uVABa~j`q zEYRQqWo-15vqt~w4@&);KRVIJ=e53g-RO7Uj9N9dCe_r`4AyMCGIZ4|O_DD4P_^5~ ztJmppc|khLHA_t8F7~a%@ox^@FFUAkgfx8P=bOe9--JV>G44ziFB;c#*!S~Ip|E^R z{Un4|V{1l!v8OXe#=Pg_>Gt0}{QGeKwqZB?CSwB}ad>FbR~WDyNBzAY{a8;=Pt+}z zHc#TBGHBCD>LOqrt$hp%jYjmy}CHrwWVm(5MwT(kH(()4h5cG zWu58tbiNt4tMyuoCG%jUK@wW;wr%V9%_=0~0!>35VK$n~<$H{e+rn_$cm|h`D__52 zpKlgdY8Dq-U0-UxH=kGw5@e72;k@7HwOQOa zK~C~^4!)P?@hIC*mU&J$aJy0yX+Pe=>|=v`@gOjn*Ba2R?V=THumV$oO=m$K;l$xk zox?T!(dJvV^BD5 z4Uh4p+s&-^>V$O1C!d~)eP@6tY(OA8Aa)MHcqr_)uzvgTwx_O62m-$m5|V9>W)NMd zD1gP-KW!5q4Ggz@Gh(n%+lB3JpHKA7s?+nUMpx|5!C$n}9r`$ZD%e4>zPzW_gnT(^_2v1rxRl}=7dRpVMC zV(#PIymH`~!@YAHhU|E#kh)7(m8!axcHYy&T#@ixIqbMO*#{nn4Zq!tx*5AA` zJ6R`BpQ@^6HXhUd>2*xQcm|H?bSl)peVtoHm5_b>cwh3n=ecu_dkcdW7wj1HhDc!l zabVw(!n2dlL%$q=g(AIf-0it-ls5~ttCgzhTzNHBk9zN0uiY^Mjli0hmzgG$i7}*`Y}^KM<}jmd=bih7ntUHB z?_Ed_G$auaoz0}PX{9oi4zWHJa=^7DZJ49?jdV>rYKY82p-Ud9|FP_Np%*8mxuo|MOTx@tY{_C+cUrkh2br?J3$7U;z zLzo2o?(-r)SLN`0jbSn7c7jD8UoWpUbd5$cpcZ1`wvT3}7U&tT``z)rsc$j|c>c%k zj=N*u-xls=9*gH=|NLjUrsYzfeRZwhJs&l!rLzi`oG5%?WHN4aB6H$h85CZ>x8aj`oBHjo z9ggGe_c(xK=KkHwI&^=d{3tQy;prWtm(X71%Y2JO?9g^vuU1-LFV!qpn<6~jCLlhf z(-uJvdpLj^bv6b6F!y0fgtj9u;+aj|I5uxnxBas1{hr76!7^?c_|A2>W&ZooHsyf> zJ1`9Pt-$M#KK@j~GZ5nf2_d)-W`hETwJEWxE=yC9V7^2Lt!P$SJ^#iwyYr7eG8$~Z zOy0d*W0n`eMjYYiXJ;yK2ODW0R7^3nnKE%nOZy+|PnLM^9}*haJu$|6REr}D_1wS6 z-{IT;_HDgy=uGDEd^B4drpCKos9P>Io1X`+YWH>_a1O1^IIXpDZVm!CZm8;7)03&; z*6~RjmwE9hG4U-lbh4fO7D{_8VuOJ{|FbXyn0uQgn}scrXp;(rLP9_tm?JDNNDd>4 zH#vuijmd^IoOHQc(q_HX#pNrVpG;KMh3aam)w;DfC(jqV)Ju}zT`y1eV z0^J1M;P>`vM@kMPENO9zr&}vNul11CEzsG4T$AP;5x$#LYT`9VDe5Mu{DHK zLsUB;#A8~IZ-MdOZO7J5nuOU%xV2G~%rN2{I2emjnu0U^#q~m6vum$8HFnwc86NyL zmlLxDc>8ZYzU2XUzW-N(jHEKuE#P}QhxiyGyy**@HzsATvg|Y#!NNU8{7!~U|Kex4 z{^cJ&)j#^E*7esf_3Pg(v{-Z6IMqZ!eQJZhh{wA!C*Gw`c@;hF1_q;wm?Qk>G4J^v z=K){8fCH77CHBNtc)7_nn=>~DQE^I7VRd-TyH*04Pj5(oahZLI63+#}u%=6BBuU=? z@%N(tza0&Z^E4)57@0J@LPoG#9|k@B=sb8UGfBK4;T7i9$fzhwVQe1e1X5`*d%KHE zb+0aT_R$k%^O=fd-%L5oOVI6HKDQE1zu^Al{M6zwmtjK(NoPB8Oy+jtZRYa>?Z$V% zfXT~(>1YO^@yc`u=7Y`4&hS2P_p;vWp1|y5#P8s&Z(EaO?UxvGhB0v(JVKdkVAj0t zFG$bAJPJP;d>e**7F4U48LCO8llgoDHaN$2*;?5ro50712gATUP|*(t+wXVASvF#0 z0;7~LC)kKE*nCp4=XesgOKNY?a){K}C%Tr)VBCzI8Rg);V19zmd8=2iUg?W3zOV`I z<;&%LXQP(}5;Oy(Zr+_=L?~7mhZT}fB8(TM8Oc(pVkir*= zG(BPdOT*v#oNVqqUt9FyZj)!+V6n)e|5;BarW4sTjeRFB@ti1pYk4t(mzBo%(}>lg z(R$T{4StbnHsusKoF)QCy5N%@A(e-?e17n})3S}I*@!9!n11-_Cn~YnJ_JkENJvqq zecU+we)s&}<$frSLt*cd_f2UIm62z?ohWkB#D<7CabImj9=0RETiZ0I?@g1^bj*)j zV_E3+venDWg&D=P{uh}U3B7a^Sl{WlbVKg2g9FAs?>sYJ_?0N%^UcOs_{R4VcawRs zvCU$3Ic}(x=S$kVUYoQ|pvRq9kFAU7IyUb|t=pBFb{*OI;dF1q$RBe%NgVbV9tKNn zJD%?X-(BL~way;@A=ZFDLlb?aVD`Dcmj(%DO@Am}{98 zns(A3ew6E9|C71?yMKJ5q3-n8U%b{=U#@iC;f^?rxlP^Pp-(uZp$`6bySt|`IARhH zJCs8T?*`^uq)YSS1lBJY57?1_A+fw(sK+p$sl1%n2{`ld#u#VPH$A=IH|9E`QD?$| zZ#F4a8l!nodC&HZyllI_N4xFh^PVsJZStPk9Zl}#aEC^xjp#S5orIlCXC|HH#(7a2 zg#PfxZi>j+=c|K0GoeZiCeKjI*mK{hpaUCchg7imV>m7nk|4 zT&t*aJN30eVqSm;Wr*nY9P|d+Ve`iuClX_rBZ6g%QJ^_`JK+iwCzHxJcIMj`f7bJf zbn*Nfb!%yuPxX5FLO*@-Bb}Z9*cQ!Se*W^2F>$x%`_5w*^(P$J~2(Jo@MzgWd zWi_bkf?>a5)r5^GxwB!3-cP+KUz`BPNO;B>;`)85svgyjD_vempZ@TPy8c3^=eg>M zbiE)i{B#e-B!N-Vb!+^0m=*4WhFcQC0K-;qTqy$3c}$UHLmg4kZ6sXtVbHe73zgZK z5i4caYdX#J><1^BOxa9KZL>X@W@^@hsv3QMh~fa@79?+wa6d*XL(Fg`-6yGr=aB>% zA-#P^W`ipp{B1wn@yYOD1}k0t4MK~JY7imErRT>*r;}pPZ~BQQ82(%@RMj)Bjk8PQ zQiAZ*pd}I|%&BbC`b;H0&a0_jv{Lz6`h$;io#ptV>{X02wb26#tq88DISdfQs{57` zW^|7aU+lSE?J17j!x0U4+xAW)VJF1K@)*jrwIYdtm@%m6#%oQAr&=|gs`81f{tz6C2kM=qyUuo1m^6f-NaCee`*TurTJ+uTsyk z;SiWXbS9Hrf#57FwZNiMb+(FD?Kusc*=ghT@=KL%rCPmK8nt8ttW0&+YF3xF0ldy& zsEk4{d;*b)B}Zaqh1C_qW)z+h;NGtTygSpA5%AO}ohSX|n)q%9BduW?Hx2ja)Zq1I z4mvjIJkcHQX?;Sn{o{;nzalQ9!0Ta~E>nl050&P%hGAQj=+1{RKD33}VX3EQjsAzT zxjvrH^&fw^($}whz3Qj>qi5F|HCI>UT92LDp;cYhnv4bR_q0~7CzTSRY1~sIy{Wtr^{01aA*AbjCoMd1#x^ z?rGdKjz1$2nO^jLBe!E4S9z@_8 zcrjy`yQ|lxH^edF^V@brrO;E{CdKZD_~vuX{zuO@kLi8Pv1YPXA*sQII_0ojs_(9~ zy7)#XXEUwmwbWAgP{;kecix9am}+aYQA3fd>T@9tR?jL`#=H+=Eul=Q%=3?S(m%dD z2nKe0-GdbInCUSL-F>@FoZS@f_7=*a?;W0I_T4QWA|i~z zVN8vv1E0h6U^~&P>DJ2FTvP?yGm{2#m!S|Bwuy?w=ApcATPwyVHd>a;wTVztFWhcU zr<1_!NKT!}ld;R?c)qD@;-tUZ!nBRYrUB+iScHvH1knJI0)eza{jh=c5Ihd6=X)rQ zfBQb&sR!FF#A+eBs3(02l-(p!9-A<@1s#I7j>~1MuP<7yvRYX=RkLn|ogkPJhH`83 zUSk(GE2*c8?;2^5kOYjBVHu>Mw!nccixW38Wf`P`tbfGQZ~K0ao9AumyHAHCx`3k? z3l+EnjZ!TzSs)z!GLt%))I_W7)RA=FrXDXz;z93q|9u%VrppxPO%M|571W@3Pnn{c ztW;Msa8?ZjM5n^r~rUhQ#TiLLJ>%!o8!aD!9?aiHapj^G_GMw(-NWwEU;|C^gT5i8ynuN=c z!vNs?9ENmfjMHrXk=Dz#t*c1n8C?Q1ckDHvPW0sLM6){Ayv)^KUf2O(HJ_Tn`DMFA znQ~LqA*KW$QN3htqwh@20C8da1q|jRDL@~()3tY!K;A`$T4#X8+_4+^@CIplr(zx| zayrjb2K67nL(`dEp%NUyLrT`Wn_#iFk5%3D15{-OX@#e^IRAkjzGo^Q851`l^q#(L zN5(y6_?XS@F)(J?>-Az~uKPUIX3^)Q3oW+2iN^*9gAVBk?oeCKUi3`tPSZxCJQxF8 zEp>f;tvWCD?Bl1F{&&Cqt)4%BZj;jg_V54w9cQ?m!X96~0}Kqli|`3L_LX$8@{^5s z1<(82vAgG+mPyzf?~t>5i^cwF>ml`rY+w@!0XHazfrsaf5pNPfRRh;hSYXBo9=f}I z-`F?YUBUSeMys5-4qg--=3{qJ`!LRG#8=WyA8Nms+yATa4u(bm_^K8oyJp{|KHn(z)5bB5WdB`xU z%MAti_mjHNgeeh1jNQ=Kn*@%3Ckvkd%~k;?XW-UsPOypSwP-tie%0#vve25oj99H% z%H&v?lXqBcoS1d8L(_!tyaB}b`ULz|2OnF0kGYy01$9VZ*@y=xC2!OoB7th-F3&WX zPAq@#S1=3M^6-o-lwfQp<~2LX44bXo3^L|w*B2&nlD450 zOxyvBCEz~*In)*CpY%7A|l_w796C$4z3 zVVY%TDTiLC>h#l7>0kV8s{i$$Jyn(U`t4`0^wrm`@}g3W?W}Gz?DvNN03ZNKL_t&t zqV7}dXdwrHgu!5pLdr3mm=w*!lc&4&i)APCzT?I3jvr4)ILrv9Qy3Dg0c+eiE*7Rb zo7bgnY_aoY>qE?&^v1yOjBjx#J+l(?%%skBGTSmMNS=D+xJ7pF9fdl4sMl>_+f`Ey zwXyzZv{Wt*I>0){bjcGoZMRy(o=|@Fk=kZ$-oKDcLw$p3Y?5bsdNR}LbfRY`Q$49O zt$z1~c?~;x@>G+m)(Try`<6Ow4V9^Q_??W!_{dk!Fw6ofG` z=xQ095|~sS2gay7X8rk*oF0Sk5d#lD^WP(|zi(Of!+5b=EOsUqHa0k0FhVd9W1{Zq zM0GPRw#^D-g9VVZ>-AD&)*JT~gMsyYrmMwLvy)T(`G5EiH)r|y^@GDeeqd*iGP0a+ z0dr#Wx5wzZk4ha|827`sV(Z6C-9I_7y~N0ZfK~HRUEio>Gsp(1%(du7HR#5dx!Pu> zkyF$nQ_IFP?nA~h*AO>Ul$_#-_kB3iuvE-@alO`R(OSM$S?KgEh~=_~F}_&1xO|*4 zhVObEf+b}{r1?=!pgFJ)5E(xsqKBd4&^MDwZAP0&7YN%B&tW8dzf8;5H@szSifLy#QCGDwAiyEh4JT3i{beVg zJHG69jniMmvevl`SxTtN9uv0KL~v0Kzp}20p>(tP%tk|s=2ZpwbP~Qs#iJG%9>11 zCY}D^@3s23e^TgY&u04O^{8KcxzJ+Bg${VZE~pE(fZ*a;pUQ)aXUgIoMv`>_W1<2? z{8>My?e4$*cClci*I0VS9A^xK5xuz^+|ej2&(4(Kc|M#OT#rk=! z#cI8woq&@z935#JU#H=z01%7{Hi{6z#5LE3!-!_GnqK<)^|e;rU@i@Z zu2gps&j zmW|WRNiamNHP=qDH^H+L@yH8skw=Qhptp{(%UZKJ>L$LK2pa*9>(=+vto>UW_Mtx? zf_W2WMiWOffH^M_vyFt!*lRdQXa~X+CPinG2Bk?GVEX`vd|h7Z^-6kv)#|d#goy80 zVDV&&TQ7Ux-ov+v$FyJ3r-3Q-Z}iR?A58aet`!~+STW33)p7S@g!{Jt(zm^y?_ICt z)QY^w*Z!dR&1Q|48yIdyR+*IG^6Hg|SCb~_iW3a(vF`exNCD<`Ulsr9iS!L$X^n0qvRlyJE(d~Qp) z+fzE0JSAcLnA3qDvHHu)OB2^GC$;8hr>b!W1Vb%$U#o|0G=pl989nz5kK9Au!$+I1 z$6jSVXjW$?0p{(ON=rDt{M(VN-!1qa`t`dNd_SoUwxtOkGk=FU(%Y7MpH0lh6ATCR zj=sKz&=12UVqu7!GdPVHj#hWmqJ7}ngq3V`(l|V);=29~`w|Si z<$7siXOn5As>*e7b*ZmkzO>W6ri0h`czxe6FbrL`KT)T3*e*%LF=7CX-Ci-nVFWV5Yc>51Vp~po$|Kbwg;f%CFli9d& zDP=^oOD)7oSiLZwW_5;yM=fRh8&Ol)gNvjoz8oLU)bP89TimdxFrd*FC5+#6T5D=f z?hmcdBsvuCIfwfp_;zEw-y8Y+@BMN*+>Z?YaTMgr86G!EC%kB6jAU|b

P8H~i86 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%0DuCRM3;bo|3^~K$i)|Mbo-a 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

81ZDgGLGfM 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