Compare commits

...
258 Commits
Author SHA1 Message Date
be5446b91c Update to 1.17
Update to Official classnames
Patchwork
Make the game compile and run
Merge in the new HUD overlay API
Merge in the new render properties API
PEEL
Use Gradle 7.2 snapshot to fix eclipse integration bug in 7.1, Would use 7.0 but FG needs 7.1 for some reason.
New FML installer
Update to 1.17.1

Co-authored-by: LexManos <[email protected]>
Co-authored-by: SizableShrimp <[email protected]>
Co-authored-by: cpw <[email protected]>
Co-authored-by: Curle <[email protected]>
Co-authored-by: Unnoen <[email protected]>
Co-authored-by: covers1624 <[email protected]>
Co-authored-by: DaemonUmbra <[email protected]>
Co-authored-by: gigaherz <[email protected]>
Signed-off-by: SizableShrimp <[email protected]>
2021-07-22 19:57:02 +01:00
LexManos 064ae6961b New 1.16.5 RB. 2021-07-21 18:25:45 -07:00
SizableShrimp 22d609ed6c ForgeGradle 5.1 and Gradle 7, which allows development on J16. Runtime still targets J8. (#7877) 2021-07-21 14:21:09 -07:00
LexManos 315bbb74ff Work around javac scoping issue. 2021-07-19 21:55:46 -07:00
LexManos 4e4d31b68c Fix LAN worlds where registry entries have been removed. 2021-07-19 21:15:26 -07:00
William Bradford Larcombe 1a17fa6129 Fix FakePlayers having null connection and add FakePlayer test mod (#7733) 2021-07-19 12:54:42 -07:00
AterAnimAvis ca9df21258 Use '{assets_root}' rather than task output path for userdev config (#7873)
Signed-off-by: AterAnimAvis <[email protected]>
2021-07-17 18:23:30 +02:00
Silk 93d7fa54fc Fix missing userdev config for datagen runs (#7871)
Signed-off-by: TheSilkMiner <[email protected]>
2021-07-17 13:14:38 +02:00
Bailey Hollingsworth f235d80d9f Adds a damage float in Lightning Entity and patches Entity to use it. (#7849) 2021-07-16 20:12:40 -07:00
Mike Garay be34dd89a9 Patch several mob classes to let them use modded versions of their ranged weapons (#7845) 2021-07-16 20:12:33 -07:00
AwesomeSyd239 6663f23e13 Add Fishing bobber projectile impact event (#7842) 2021-07-16 19:41:51 -07:00
OneLemonyBoi f9f7ef2580 Removes misapplied patch in Entity (#7841) 2021-07-16 19:38:56 -07:00
OneLemonyBoi 86352e9c19 Removes misleading Nullable annotation from canCreatureSpawn (#7840) 2021-07-16 19:38:06 -07:00
OneLemonyBoi 8c8b31435b Corrects the assigning of mob kills, Fixes MC-121048 (#7836) 2021-07-16 19:37:12 -07:00
OneLemonyBoi 16b3e2780e Updates MouseHelper to allow for Horizontal Scroll to be recognized as Vertical Scroll (#7834) 2021-07-16 19:31:14 -07:00
Take Weiland 1121f18413 Fix entities losing their scoreboard data when they are unloaded (#7826) 2021-07-16 19:24:29 -07:00
Take Weiland 96804fb4df [1.16] Allow blocks other than beds or respawn anchors to act as respawn points (#7824) 2021-07-16 19:23:36 -07:00
LexManos 03a6dbb405 Regen patches 2021-07-16 19:12:38 -07:00
Won-Ton 77e8c72589 Add AT entries for DimensionSettings to make them easier for mods to work with (#7817) 2021-07-16 18:03:56 -07:00
cech12 043e49a694 New hook to allow Trapdoors be climbable for custom ladders (#7816) 2021-07-16 18:01:27 -07:00
King Lemming 5169f1f6fe Convenience change for potion enumeration - does not change patch size in any meaningful way! (#7811) 2021-07-16 17:56:08 -07:00
Mike Garay 2bd83b26aa Adds knockback attribute to players and updated knockback calculation to PlayerEntity#attack (#7806) 2021-07-16 17:52:58 -07:00
Sekwah e6c1814122 Fix mod menu URL click bounds (#7804) 2021-07-16 17:51:11 -07:00
Daniel Houck 7f2892de7e Fix vanilla rotation/mirroring issues (#7803)
Patch minecraft to fix MC-227255 and MC-134110, which are block
rotation and mirroring issues.  I noticed this from problems with
Structurize, but this probably affects any other mods that allow
rotating or mirroring structures (as well as vanilla structure blocks).
2021-07-16 17:50:29 -07:00
PersonTheCat 439ba462d6 Synchronize ResourcePackList#addPackFinder (#7799) 2021-07-16 17:48:10 -07:00
mikewk 7c6ae3e61e Fixes tryFluidTransfer_Internal to respect the FluidStack drainable when draining fluidSource. (#7782) 2021-07-16 17:45:39 -07:00
Take Weiland f9b894ecbf Add IRecipeType parameter to burn time hooks (#7771) 2021-07-16 17:37:41 -07:00
Andy Dingley df53db351e Use MobGriefingEvent for PiglinEntity when determining whether Piglins want to pick up items. (#7762) 2021-07-16 17:35:24 -07:00
Andy Dingley 9aa04c8036 [1.16.x] Remove redundant mobgriefing check in SmallFireaballEntity. (#7761) 2021-07-16 17:33:59 -07:00
Queekusme 626496cec0 Changed AbstractFurnaceTileEntity's canBurn and burn functions to use IRecipe's 'assemble' instead of 'getResultItem' (#7756) 2021-07-16 17:33:02 -07:00
covers1624 022482a3bd Bypass chunk future chain when processing loads and getChunk called. (#7697) 2021-07-16 17:26:45 -07:00
DaemonUmbra dd228a9ac1 Removed sidedness from PacketBuffer methods. (#7236)
Affected methods:
* readLongArray (x2)
* readSectionPos
* readString (no-arg variant)
2021-07-16 17:25:11 -07:00
Silk a6d1646591 Add data generators for sounds.json (#6982) 2021-07-16 17:24:16 -07:00
Take Weiland 39f9f393db Add custom TextureAtlasSprite loaders (#7822)
Adds a system for mods to specify custom texture loaders which can be requested by the resource pack through a metadata section in the .mcmeta file. Due to technical reasons, png file is still required for MC to identify a texture as existing, even if the loader doesn't use it.
2021-07-16 01:55:43 +02:00
Commoble d35784eb14 Fix PlayerGameModeEventTest and ForgeWorldTypeTest so they don't crash the dedicated server when running forge_test_server in forgedev (#7869) 2021-07-15 16:40:07 -07:00
LexManos 31fb15c88d Add userdev to run config. 2021-07-13 18:15:54 -07:00
Take Weiland 29f175743b Add truncation to FMLStatusPing to work around protocol limits (#7818) 2021-06-16 19:23:20 -07:00
SizableShrimp 33499db93f Remove ModelResourceLocation patch for SAS entry (#7813) 2021-06-09 09:35:03 -07:00
Take Weiland 84381553a9 Fix jar file path detection if the path contains a "!" (#7790) 2021-06-08 13:26:01 -07:00
mrp-v2 2a7dde3d2e Add method to get the number of elements in a model builder (#7792) 2021-06-08 12:49:25 -07:00
Take Weiland aa4f24c915 Fix vanilla packet splitter remote detection and add advancement packet splitting (#7802) 2021-06-08 12:47:37 -07:00
Nightenom 1d87831773 Add option for linear filtering of text texture (#7645) 2021-06-08 21:33:31 +02:00
mrp-v2 65e99f9b58 Use empty model instead of missing model for non-existant layers in multilayer models (#7750)
Fixes issues when using multi-layer models as part of composite models
2021-06-08 21:07:33 +02:00
LexManos b98991dc70 Add debug logging to packet compression encoder.
Should make figuring out who is sending large packets easier.
Disable with -Pforge.disablePacketCompressionDebug=true
2021-06-03 10:29:49 -07:00
LexManos 435e65eb18 Removed signature line from mod list screen. #7500 2021-05-23 11:08:45 -07:00
Curle 8211a5048a Reinstate the MinecartCollisionHandler field to AbstractMinecartEntity (#7748) Closes #7506. 2021-05-17 13:51:23 -07:00
Curle 167f14f4a1 Fix PlayerEvent.BreakSpeed's pos being nullable. (#7747) Closes #7615. 2021-05-17 13:46:11 -07:00
Curle f332642409 Fix OBJ Loader data gen string (#7746) Closes #7616 2021-05-17 13:43:37 -07:00
noeppi_noeppi 77d41023b5 Add an event similar to PlayerEvent.NameFormat but for the name shown in the tab list. (#7740) 2021-05-17 13:17:01 -07:00
Curle da2594289c Fix filling buckets with fluids without bucket items consuming the fluid (#7745) Closes #7670 2021-05-17 13:10:27 -07:00
David Quintana 6f3da80b5a Work around crash while loading flatworld with modded structures. (#7764)
* Work around crash while loading flatworld with modded structures.

* Maybe fix issue with gradle daemon leaking memory and slowing down CI builds.
2021-05-14 00:11:46 +02:00
gigaherz 474b47ea51 Update Forge to Gradle 6.9 2021-05-12 23:33:33 +02:00
Trikzon b6ce4fb066 Add barrels and barrels/wooden block and item tag (#7676) 2021-04-30 10:53:19 -07:00
KnightMiner 1406f2bf1f Fix shears not properly breaking tripwire (MC-129055) (#7718) 2021-04-30 10:52:02 -07:00
JoJoModding 5125775992 Fix Line endings in tooltips not handled properly in multiplayer screen Closes #7738 (#7739) 2021-04-30 10:42:15 -07:00
Sydney 929c7b7a0b Fix cats, phantoms and pillagers saying they're at BlockPos.ZERO during LivingSpawnEvent.CheckSpawn (#7722) 2021-04-23 13:27:56 -07:00
mrp-v2 7bf02e7dcd [1.16] Add missing Multipart Blockstate Builder feature: Nested condition groups (#7677) 2021-04-22 22:55:18 -07:00
Dennis C 9d0d249eaf Pass BlockPos to BlockParticleData used for "fall impact" particle (#7705) 2021-04-22 22:53:58 -07:00
sciwhiz12 c4b1df1fc7 Check version ranges of optional dependencies when present (#7710)
If an optional dependency is present, but it does not conform to the version range,
it will now error out in the same fashion as missing required dependencies, instead
of a more cryptic error down the line due to a missing method/class/field/etc.

Implements and closes #7696
2021-04-22 22:52:24 -07:00
Take Weiland b3f253df61 Fix ClientVisualization crashing on systems without monitors (#7719) 2021-04-22 22:45:38 -07:00
atkarimarton dc099069fa Fix Furnace Minecarts going faster then vanilla (#7725) 2021-04-22 22:29:33 -07:00
AterAnimAvis e80c785563 Update for Forge's new maven (#7723) 2021-04-22 22:28:18 -07:00
cpw 1f9611204f A bloody quote FFS
Signed-off-by: cpw <[email protected]>
2021-04-18 11:35:05 -04:00
cpw 0120f6274d Update for new maven
Signed-off-by: cpw <[email protected]>
2021-04-18 11:28:54 -04:00
cpw c0e74bc8a8 Fix broken java9hacks for j16 handling..
Signed-off-by: cpw <[email protected]>
2021-04-02 14:27:25 -04:00
SizableShrimp 80feb0aeb2 Add generic EntityTeleportEvent (#7694) 2021-03-29 18:05:13 -07:00
covers1624 f47429717d Restore SS version, fixes findFieldInstanceChecks 2021-03-22 16:51:53 +10:30
Take Weiland 0239a736ec Fix sign textures being stitched onto every texture atlas (#7690) 2021-03-17 10:04:07 -07:00
LexManos 5c488c9007 Fix AT order, missed exec line and bump for RB. 2021-03-15 15:06:12 -07:00
Take Weiland 53c039680c Fix wrong eye height when entity size changes (esp. baby animals) (#7628) 2021-03-15 14:08:40 -07:00
Take Weiland 7379e8b9a4 Allow ITeleporter to override the vanilla teleport sound (#7682) 2021-03-15 14:02:20 -07:00
SizableShrimp 2a0d9e8dac Fix datapack exception related to EnumArgument with siblings (#7686)
Invalid enum constants are now properly thrown as a CommandSyntaxException
2021-03-15 13:20:08 -07:00
kaydogz aacba8e38e Add support for custom WoodTypes (#7623) 2021-03-15 12:28:45 -07:00
LexManos f4fd1c2f16 Use JGit instead of GrGit now that jcenter is going away.
Update missed mapped name in MDK.
2021-03-15 12:18:51 -07:00
gigaherz 813f3d630d Bump nashorn wrapper version. 2021-03-13 19:56:17 +01:00
gigaherz 76cea5a7da Fix yet another copypasta. 2021-03-13 19:56:17 +01:00
diesieben07 e33f794298 Fix incorrectly replaced SRG names 2021-03-13 19:56:14 +01:00
AterAnimAvis 72d05d17a9 Fix potential Deadlock when using custom Item entities. (#7532)
Be careful when adding Entities during Chunk Load (#7519)
2021-03-12 10:50:05 -08:00
gigaherz 19f9b309a6 Fix copypasta. 2021-03-12 02:54:10 +01:00
Curle 5b53616a47 Automatically fix some issues with configurations deemed invalid for simple reasons (#7671) 2021-03-11 16:11:05 -08:00
gigaherz 5f9e6f3b56 Add coremod that injects bouncer methods to work around name conflicts with official names.
Fixes a binary break.
2021-03-11 21:57:47 +01:00
gigaherz 0ad8e2c27f Bump SpecialSource 2021-03-11 19:29:20 +01:00
David Quintana 55f29764f8 Bulk update license year, and use replacement variable so that the current year is always used. 2021-03-10 23:41:00 +01:00
David Quintana a4f7087b92 Introduce a new feature that lets mods know if optional mods and optional network channels are present in the remote.
Allow connections from forge versions that don't have the vanilla splitter.
2021-03-10 23:40:59 +01:00
LexManos a95b968c13 Regenerate patches with relative headers. This should lower conflicts in future PRs.
Convert Forge to use Official mappings.
Mojang released their obfuscation mappings but we have not used them up until now due to wanting to get their license to be more explicitly permissive.
It is clear that their intent is to allow us to use their names for developing mods like this.
See the full wording, and our interpretation here: https://github.com/MinecraftForge/MCPConfig/blob/master/Mojang.md
2021-03-09 14:21:48 -08:00
LexManos 802298d99d Update to FG4, and Gradle 6.8. 2021-03-09 13:27:46 -08:00
Take Weiland 5363dc5d99 Support splitting vanilla packets that are too large on forge<->forge connections (#7485)
Currently only for SUpdateRecipesPacket and STagsListPacket that blow up with huge datapacks
2021-03-04 12:14:52 -08:00
Sara Freimer 9602c22083 Fix a few places where the vanilla method was being called instead of the forge one (#7535)
Cleanup javadocs references slightly, fix a couple spots not using the proper forge hooks, and remove a couple unneeded patches
Update deprecation comment on isAir
2021-03-03 12:50:32 -08:00
FireController#1847 17500032ae Add Opacity to ForgeHooksClient#renderMainMenu (#7660) 2021-03-02 21:28:48 -08:00
Marc Hermans 65bc41281f Add support for caching of configuration values. (#7608) 2021-02-24 18:36:51 -08:00
Kovak ba15737fe3 Added entity attribute setup and creation events 2021-02-15 18:40:32 -08:00
KnightMiner 58f93263e2 Fix updateItemStackNBT not properly being called (#7646)
Re-added ItemStack delegate redirect transformer
2021-02-15 17:28:35 -08:00
Sara Freimer d97f28141c Fix a few FluidUtil issues that were causing DispenseFluidContainer to not function properly (#7422) 2021-02-15 17:08:05 -08:00
ichttt 0340664dbf Add a way to specify a custom background texture with namespaces in the Creative GUI. (#7404) 2021-02-15 16:46:23 -08:00
DaemonUmbra d2cfda3fb4 Fixed Configs not correcting when hot-loaded from changes on disk (#7427) 2021-02-15 16:39:59 -08:00
FledgeShiu 48225e1bea Reduce default logging markers in the MDK. Modders can re-enable these for better debugging. (#7432)
Modders PLEASE read your damn log, and fix the errors we point out. Spamming modpacks with stack traces is just lazy programming.
2021-02-15 16:39:02 -08:00
sciwhiz12 37ea725749 Deprecate Forge's setdimension command, vanilla execute command can do this now. (#7459) 2021-02-15 16:19:13 -08:00
LeBossMax2 733b812c7b Fix ItemTextureQuadConverter.convertTexture generating wrong quads, fixes #7620 (#7650) 2021-02-16 00:38:21 +01:00
Sangar 9ab29ea8fe Added MultipartBakedModel.getModelData(). (#7595)
This allows custom IBakedModel implementations to use the IModelData provided by their IBakedModel.getModelData() when used in the context of a multipart model.
2021-02-16 00:22:24 +01:00
Cyborgmas fe26b77e3b fix global cache not being a block render type (#7648) 2021-02-16 00:15:33 +01:00
Alex O'Neill b8eca88f75 Allow mods to use additional custom LootParameter when querying existing loot tables (#7515) 2021-02-15 14:52:00 -08:00
Sydney e039531497 Add ForgeHooks.canEntitySpawn to Cat, Phantom, and Patrol spawners. (#7569) 2021-02-15 13:40:03 -08:00
Max Becker 9017e24b40 Fix/Replace player visibility event (#7573) 2021-02-15 13:25:54 -08:00
AterAnimAvis 75570079ae Fix: Clear the last error from glfwInit to prevent vanilla from throwing an exception later in the chain when glfw errors. (#7587) 2021-02-15 13:16:09 -08:00
seymourimadeit e2167140db Fix MC-181464 persisting for modded shields (#7602) 2021-02-15 12:56:34 -08:00
malte0811 a89ce2d6f1 FIx race condition in LazyOptional (#7611) 2021-02-15 12:11:27 -08:00
Dennis C 007cd42ec6 [1.16.5] Fix shaders breaking almost every overlay that uses textures, fixes #7575 (#7624) 2021-02-14 19:11:46 -08:00
TelepathicGrunt d16a8d6d5d Disable syncing of Feature and Biome registries (#7639) 2021-02-14 19:05:11 -08:00
Drullkus 69321a363e Add IExtensibleEnum to GrassColorModifier (#7641) 2021-02-14 19:04:31 -08:00
Sydney 0e1ee4b1d2 Log stacktraces in NettyPacketEncoder. (#7654) 2021-02-14 18:36:09 -08:00
Dennis C cc1a9be2b4 Lower logging level for datafixer warning to debug (#7636) 2021-02-10 11:05:01 -08:00
Sara Freimer 1d7da4c595 Reintroduce forge's chunk manager to allow mods to force chunks with either a block position or entity (UUID) "owner" and have them properly persist between restarts (#7642) 2021-02-09 14:19:07 -08:00
Sara Freimer 1ac432c594 Fix two places where querying an object for the new "valid" capability from a capability invalidation listener could cause the object to return the old invalid capability. (#7643) 2021-02-09 13:28:02 -08:00
Cyborgmas 276871d5a3 Fix config spec in cases of enum class discrepancies (#7635) 2021-02-09 13:21:23 -08:00
Take Weiland 8460227ddf Fix onBlockAdded being called twice for ItemEntity placing non-TE blocks (#7607) 2021-02-09 13:02:08 -08:00
Jon f450d4025d Prevent NullPointerException when adding new loot pool. (#7605) 2021-02-09 12:59:48 -08:00
brandon3055 93a815957d Added generic multi part entity API (#7554) 2021-02-09 12:53:25 -08:00
Cyborgmas 84b7cdc1cd Fix IAngerable entities crashing when reading nbt on client (#7618) 2021-02-06 19:41:12 -08:00
Silk 83fee0b3d4 [1.16.x] Add loot table ID in Global Loot Modifiers (#7428) 2021-02-02 13:32:02 +01:00
Sara Freimer aeaebf5785 Add a block tag to allow mods to blacklist blocks endermen should not be able to place blocks on top of, similar to how vanilla hardcodes against them being able to place things on bedrock (#7548) 2021-01-29 18:02:08 -08:00
HellFirePvP d88e660cbb Fix translucent model parts of MultiLayerModels rendering as missing models due to differing rendertypes when rendering block model (#7579)
Signed-off-by: HellFirePvP <[email protected]>
2021-01-29 18:01:16 -08:00
Sara Freimer ab949c7cca Fix existing file tag provider support looking in the wrong folder for custom tag types (#7576) 2021-01-29 17:34:54 -08:00
Cyborgmas 7728dde36b Propery re-encode registries (#7629) 2021-01-28 13:07:11 -08:00
Cyborgmas 004ab59e6f Properly encode registries. (#7626) 2021-01-27 17:22:58 -08:00
Cyborgmas 7bfd2b8f34 Inject vanilla dimensions inside worlds missing them (#7599) 2021-01-27 16:00:28 -08:00
LexManos f169c99348 Introduce a new field_to_instanceof transformer to reduce some simple patches. 2021-01-26 16:32:13 -08:00
LexManos d3d3bdc769 Fix broken build. 2021-01-25 18:52:46 -08:00
Max Becker 0a0f3232ea Add modded biomes to overworld biome list (#7360) 2021-01-25 18:36:46 -08:00
LexManos 50d75a27e1 Fix dynamic registries not getting ids assigned correctly from old worlds in specific unordered value insertions. Closes #7586 2021-01-25 18:17:51 -08:00
KnightMiner 19f8d2a793 Optionally add a milk fluid to the vanilla bucket (#7294)
Fixes the previous broken code that was supposed to make mod registered milk returned by the vanilla bucket by allowing mods to enable a milk fluid.
2021-01-17 16:05:24 -05:00
LexManos f173bde812 1.16.5 Initial Update. 2021-01-15 11:33:11 -08:00
LexManos dd10933ab0 Update Coremods, ASM, and include standalone Nashorn to load on J15. 2021-01-14 15:48:53 -08:00
LexManos 9ffa44f254 Introduce a new field_to_instanceof transformer to reduce some simple patches. 2021-01-14 02:52:52 -08:00
LexManos d8f41adf39 Update Coremods, ASM, and include standalone Nashorn to load on J15. 2021-01-12 13:22:13 -08:00
Ian Rehwinkel c3e84646db Added IWeatherParticleRenderHandler to allow a mod to take control over weather particles and sounds. (#7522) 2021-01-07 12:24:40 -08:00
covers1624 2094f99640 Allow Chunk loading Tickets to opt-into forcing chunk ticks. (#7525) 2021-01-07 12:13:47 -08:00
malte0811 94f3bdaa69 Fix crash when mods add goals to skeleton horses (MC-206338) (#7509) 2021-01-07 12:04:50 -08:00
Take Weiland 7220e9d0b0 Set WM_CLASS and WM_INSTANCE_NAME for early progress window (#7534) 2021-01-07 12:03:46 -08:00
Alex O'Neill 020102d87f Make UnboundedMapCodec more lenient in decoding dimensions. Fixes MC-197860 (#7527) 2021-01-05 19:17:24 -08:00
LexManos f101700969 Fix FML's Config Sync packet not allowing same length filenames in encoder and decoder. Closes #7584 2021-01-05 11:50:05 -08:00
LexManos c4b148b84b Prevent NPE and deprecated MissingMappings.getMappings function. Closes #6252 2021-01-05 11:47:00 -08:00
LexManos b6a9274870 Fix entities not correctly being able to be ridden under water. 2021-01-03 03:02:32 -08:00
Jonathan Coates 830d9699e3 Fix crash when beehive is broken by fake player (#7566) 2020-12-28 13:56:44 -08:00
Alex O'Neill fc68b81b21 Add supplier variant to AbstractBlock.Properties#lootFrom (#7563) 2020-12-28 13:42:15 -08:00
Take Weiland 2904772b16 Fix ModFileResourcePack.getAllResourceLocations ignoring resourceNamespace. (#7562)
Fixes #7405
2020-12-28 13:39:44 -08:00
Take Weiland e120b57032 Fix missing serializers when deserializing global loot modifiers (#7561) 2020-12-28 13:37:32 -08:00
Take Weiland b86b56260d Fix VanillaConnectionNetworkFilter sending out invalid entity properties packets without an entity ID (#7560) 2020-12-28 13:34:31 -08:00
Richard Freimer b222b23557 Make shear interactions extend to subclasses (#7544) 2020-12-28 13:10:35 -08:00
sciwhiz12 8ec4253068 Add a SoundType subclass that uses suppliers (#7538) 2020-12-28 13:09:03 -08:00
sciwhiz12 74ca88b7be Fix compound ingredient in shapeless recipes (#7537) Fixes #7530 2020-12-28 13:03:48 -08:00
Alex O'Neill a1119cd77a Fix potential NPE in ForgeHooks.onItemPlaceIntoWorld when passing in null player. (#7505) 2020-12-28 12:18:52 -08:00
mrp-v2 545723dc8c Fix modded PointOfInterestType's not populating blockstate map when registered (#7503) 2020-12-28 12:17:51 -08:00
poopoodice b64f4780c5 Add new LivingConversionEvent to control mobs turning into other mobs. (#7386) 2020-12-28 12:03:11 -08:00
KnightMiner 1c98b29087 Add ItemAttributeModifierEvent (#7484) 2020-12-28 11:59:09 -08:00
Brennan Ward 33880331d2 Fix RightClickBlock ALLOW not being implemented (#7426) 2020-12-28 11:54:30 -08:00
LexManos 74a43877e4 Quiet down errors related to modders not changing their update urls from the default. 2020-12-26 11:39:14 -08:00
LexManos 7542fbea48 Make mod data packs able to be disabled. It'll break things, but that's on you. Closes #6776 2020-12-26 11:38:45 -08:00
tterrag 2d9a1bc6f9 Add generated resource tracking to ExistingFileHelper 2020-12-12 12:33:56 -05:00
tterrag a57a240c13 Fix BlockStateProvider item models not knowing about block models
Add tests for this case
2020-12-10 21:37:13 -05:00
Richard Freimer b7fb6484d7 Override invalidateCaps instead of remove for vanilla TE capability invalidation (#7536)
Properly invalidate patched in vanilla TE caps in invalidateCaps instead of remove so that they get invalidated on chunk unload
2020-12-08 11:54:29 -08:00
Richard Freimer 1a539ffebc Make TEs invalidate capabilities when the chunk they are in unloads (#7529)
Fixed LazyOptional potentially notifying invalidation listeners multiple times.
2020-12-05 12:05:32 -08:00
Kevin G 27220a5ad8 Fixed entity navigation to stop entities spinning - MC-94054 (#7520) 2020-12-05 11:54:03 -08:00
Unbekannt1998 e975fc8252 Fix wrong function call in BlockStateProvider::horizontalFaceBlock (#7514) 2020-12-05 11:52:44 -08:00
tterrag d85ea5a3b0 Fix datagen order of multipart conditions being unstable 2020-11-28 21:10:49 -05:00
Alex O'Neill ccb7345084 Fix forge config option for default world type not applying unless you change the default world type (#7521) 2020-11-28 03:56:44 +01:00
David Quintana 93c00b67d9 Implement feature for mods to define new world types (#7448)
* Mods can now register world types via a new forge registry, and optionally register a settings screen to tweak them.
  * The default world type for dedicated servers and singleplayer world creation is configurable via forge's common config.
2020-11-28 00:57:15 +01:00
IzzelAliz cd393bbfdc Fix dimType not encode to registries (#7513) 2020-11-24 09:14:10 -08:00
Richard Freimer fd045d4628 Add support for referencing forge's resources and specifying existing mods to data generators (#7456) 2020-11-22 22:45:13 -05:00
cpw 47e076071b Fix #6692
Thanks @AterAnimAvis for help and suggestions

Signed-off-by: cpw <[email protected]>
2020-11-22 17:00:48 -05:00
Cyborgmas a73e003dd3 Fix translucent blocks not rendering properly when moved by pistons on fabulous (#7441) 2020-11-21 11:57:33 -08:00
LexManos 949984268d Bump version for RB. 2020-11-20 12:53:44 -08:00
Take Weiland 114acfca3b Fix food bar not rendering when non-living entities are mounted (#7446) 2020-11-20 10:24:43 -08:00
Alex O'Neill 56e538e8a9 Fix MC-194811 - Removing structures causes chunk save errors. 2020-11-20 10:23:50 -08:00
Take Weiland fa46f3dd49 Fix concurrency issue in StartupMessageManager (#7483) 2020-11-20 10:17:00 -08:00
Alex O'Neill 6ec5a8f2c1 Fix forge registry types that have private constructors (BlockStateProviderType, BlockPlacerType, FoliagePlacerType, TreeDecoratorType) (#7482) 2020-11-20 10:11:15 -08:00
cpw 49b596dda3 Fix problem where the absence of forge and MC in later loading triggered a weird crash.
Signed-off-by: cpw <[email protected]>
2020-11-15 11:08:34 -05:00
cpw 0c5ced1bbf Fix NPE problem when modid is mismatched.
Signed-off-by: cpw <[email protected]>
2020-11-13 20:41:20 -05:00
cpw 4a09a2420d Return the processed modlist data to the upstream system, not the raw unprocessed data. Should resolve the problem
that mixin complains about missing info when it's in a "crashed" situation.

Signed-off-by: cpw <[email protected]>
2020-11-13 19:12:43 -05:00
Cyborgmas 0ff8a596fc Fix dims on servers not loading the first run (#7445) 2020-11-11 01:09:35 -08:00
Take Weiland bca20ace4e Allow for custom argument types by filtering them on vanilla connections (#7463) 2020-11-10 12:24:25 -08:00
Brennan Ward f3b53001c9 Add Player context to AnvilUpdateEvent (#7442) 2020-11-10 12:05:47 -08:00
Jonathan Coates 15bac0eeaa Don't overwrite PlayerAdvancement's player with a fake one (#7454)
If a FakePlayer is constructed with the same UUID/GameProfile as a
currently active player, the player object within PlayerAdvancement is
set to the fake player.

As fake players cannot receive advancements (see grantCriterion), this
prevents the actual player from receiving any advancements until they
change dimension/relog.
2020-11-10 11:55:42 -08:00
Curle 1782973a29 Add BannerBlock.forColor to SAS to fix banner.toItem() on servers. 2020-11-10 11:38:20 -08:00
Boy132 9a4a501a95 Call Harvest check event even if the block doesn't require any tool (#7414) 2020-11-10 11:36:32 -08:00
LexManos 9bbfbd5479 Use linked collections to stabilize order when adding new registry entries. 2020-11-10 11:24:57 -08:00
Dennis C 8c68731838 Render local player when the renderViewEntity is not the local player (#7216) 2020-11-10 11:13:49 -08:00
cpw 0d7f507f4e Some help in ExtensionPoint regarding DISPLAYTEST. Let's improve those tick rates!
Signed-off-by: cpw <[email protected]>
2020-11-07 23:11:45 -05:00
cpw f78b943bdf Handle erroring during early mod construction phases, and actually report that into the error UI
by doing armslength exception handling and propagation.

Signed-off-by: cpw <[email protected]>
2020-11-07 22:30:19 -05:00
cpw 160f3f88f9 Support backwards loading 1.16.3 mods in 1.16.4, because we are able to do that. Tweak loading a bit to be smarter about dependency errors of various kinds.
Signed-off-by: cpw <[email protected]>
2020-11-07 20:48:02 -05:00
David Quintana 45e38859ed Add FluidStack codec, and a test mod that verifies its behaviour matches the existing write/read logic.
Add missing license headers.
2020-11-07 21:10:18 +01:00
cpw 38a5400a8c Update event bus version (should be 3.0.5)
Tweak MDK to automatically populate recommended values for things like forge version, loader version and minecraft version.

Signed-off-by: cpw <[email protected]>
2020-11-06 21:11:26 -05:00
diesieben07 acd18455c2 Workaround for modded attributes on vanilla entities logging warnings on vanilla clients
Switch to a handler-based approach per packet class, simplify patch, add some docs

Add license header and docs

Switch to a network handler based approach

Switch to a network handler based approach

revert build gradle change

Simplify Packet patch

Add license header to IForgePacket

Revert ForgeHooks changes

Less hacky and more generic way to filter packets for vanilla connections

_Actually_ Order SAS.
It's early

Order SAS

simplify vanilla connection check

Remove unneeded import change
2020-11-03 18:47:04 -05:00
cpw 5a7facc20f Fix early sorting bug that meant the file deduping was causing an error, to, well, not cause it, so we can get to an error screen.
Signed-off-by: cpw <[email protected]>
2020-11-02 14:57:23 -05:00
LexManos f54998a6b7 1.16.4 Initial Update 2020-11-02 10:42:45 -08:00
LexManos 7d00d015f3 Fix Biomes not properly copying over ids loaded from the save to the new Dynamic Registry. 2020-11-01 20:30:38 -08:00
David Quintana fed7beab89 Introduce custom loader additions to the model data generators. (#7450)
Currently implemented loaders:
* OBJ
* Composite
* Multi-layer
* Item layers (vanilla item/generated but with fullbright texture support)
* Bucket
* Separate Perspective
2020-11-02 02:09:49 +01:00
cpw cf3e9d1e0c actually rollback on error in registry events.
Signed-off-by: cpw <[email protected]>
2020-11-01 19:51:56 -05:00
cpw 749c9063af Fix config parse failure causing crash in building exception message. fixes #7438
Signed-off-by: cpw <[email protected]>
2020-11-01 17:09:00 -05:00
Tobias Hotz 1af6632a29 Auto-detect ansi support for log4j2
move to fml.loading subpackage

Add license header
2020-11-01 17:03:12 -05:00
cpw 7e79243bca Return client resources even if no data pack found on server. Closes #6225 (Pull request)
Signed-off-by: cpw <[email protected]>
2020-11-01 17:02:56 -05:00
cpw 36f9c804d9 Update modlauncher. fixes #7452
Signed-off-by: cpw <[email protected]>
2020-11-01 16:05:02 -05:00
malte0811 06fe9ccda0 Fix (NonNull)Lazy.Concurrent using a global lock (#7403)
* Fix Lazy.Concurrent using a global lock, thus preventing multiple threads from resolving independent Lazy's at the same time
* Use Lazy with an added null check to implement NonNullLazy
2020-10-29 18:09:20 +01:00
David Quintana 53eedb0f10 Update forge mappings to 20201028-1.16.3 (#7435) 2020-10-29 01:11:57 +01:00
Alex O'Neill 6e0e67b14d Fix breaking changes from the Biome rename PR #7434 (#7439) 2020-10-27 09:00:53 -07:00
sciwhiz12 22f7f4649b Reimplement nametag distance attribute, fix attribute translation keys (#7387) 2020-10-26 16:52:36 -07:00
Alex O'Neill 8a77681574 Fix data pack biomes failing to load in SingleBiomeProvider (#7434) 2020-10-26 15:06:53 -07:00
cpw 6982c5dd56 Add in proper handling of equals and hashcode for modjar urls. Fixes very slow loading on windows.
Signed-off-by: cpw <[email protected]>
2020-10-26 18:00:14 -04:00
cpw 7205c30ece Force 8.0.5 ML
Signed-off-by: cpw <[email protected]>
2020-10-26 08:51:05 -04:00
cpw 80baad974e Restore FingerprintViolationEvent with appropriate THIS IS F*CKING DEAD DELET WARNINGS.
Also, notify in UI if using legacy JDK without capability to read out security data from mod jars.

Signed-off-by: cpw <[email protected]>
2020-10-26 07:31:49 -04:00
cpw ae160cad12 Add signature reporting for mods, using new signature capture from ModLauncher. Need to figure out
how to reflect Minecraft's JAR signatures into here.

Signed-off-by: cpw <[email protected]>
2020-10-25 22:26:16 -04:00
cpw 6ff6277efa Rollback registries to vanilla state if something happens during loading, so subsequent activities can still run and not generate false reports..
Signed-off-by: cpw <[email protected]>
2020-10-25 11:33:43 -04:00
LexManos 74f9ef838a Fix mcp_snapshot mapping issue causing unneeded patches. Closes #7424 2020-10-20 12:32:19 -07:00
David Quintana 395f89c973 Fix resource leak in the OBJ loader. 2020-10-20 13:24:12 +02:00
SilverDavid 8536521b7b Fix issue with ITeleporter allowing easier use of vanilla logic. (#7317) 2020-10-16 12:09:53 -07:00
Richard Freimer b1659300e0 Adds tag support for Enchantments, Potions, and TileEntityTypes (#7379) 2020-10-15 12:45:25 -07:00
LexManos 93226bbcff Resuscitate BiomeDictionary using RegistryKeys instead of biome references. 2020-10-15 12:43:18 -07:00
Ocelot 51fa230e7b Add event for player changing game mode (#7355) 2020-10-15 10:15:06 -07:00
cpw 5f292895cb Fix RCON multipacket responses not actually understanding UTF8.
Signed-off-by: cpw <[email protected]>
2020-10-12 14:10:57 -04:00
cpw 9cfe741cea Fix RCON not sending newlines in output for multiline. Fixes https://bugs.mojang.com/browse/MC-7569, a very old bug that is really annoying if you use RCON.
Signed-off-by: cpw <[email protected]>
2020-10-11 21:48:55 -04:00
ChampionAsh5357 bed38d4253 Fix Texture Presence String (#7408) 2020-10-10 09:45:18 -07:00
LexManos 37f226eda5 Fix typo causing potential error in vine growth. Closes #7406
Sort missing registry dumps by name, making it easier to read.
2020-10-09 12:56:26 -07:00
David Quintana 59b4affbe7 Fixed conditional advancement loading when using the "advancements" array.
Added automatic generation of conditional advancements from the criteria in the conditional recipe entries.
Added advancement name calculation from the recipe ID.
2020-10-09 15:47:32 +02:00
Flanks255 5477a36656 Additions to the mdk build.gradle to accommodate datagens. (#7398) 2020-10-08 14:03:41 -07:00
DaemonUmbra 5648336893 Added Basic Class-Level SAS Capability to checkSAS, added Vector4f to SAS (#7385) 2020-10-08 14:02:48 -07:00
Richard Freimer f5b53d5d10 Add hooks to allow modification of structures spawn lists (#7344) 2020-10-07 13:04:03 -07:00
Richard Freimer 10448c1ac9 Add back patches to Screen allowing for item tooltips to be auto wrapped again (#7378)
Only deals with the methods receiving an ItemStack or ITextComponent(s), the methods that take IReorderingProcessor(s) are left alone.
2020-10-06 21:38:27 +02:00
Mumfrey 5243275db2 Bump mixin version to 0.8.2 2020-10-05 15:34:07 +01:00
cpw 3041c2022b Add in extra debug logging
Signed-off-by: cpw <[email protected]>
2020-10-04 17:45:28 -04:00
cpw 09be003d61 Remove redundant call to CrashReport generator - Vanilla is doing a crashreport for itself at startup now.
Add a UUID into crashreport that is also logged in all channels at crash report generation time. This will allow to associate crash reports and the logs.

Signed-off-by: cpw <[email protected]>
2020-10-04 16:40:38 -04:00
cpw 3fe5ddd68f Fix doc README and answer lex's question
Signed-off-by: cpw <[email protected]>
2020-10-04 15:50:58 -04:00
cpw 935cb6782d Modify how ModLoadingStage handles dispatch to Registry Events. Stops the objectholder spam and generally improves performance on larger packs.
Signed-off-by: cpw <[email protected]>
2020-10-04 15:50:15 -04:00
DaemonUmbra 9b421b54a7 Added "Bukkit Plugin" to InvalidModIdentifier (#7384) 2020-10-02 16:40:06 -07:00
Richard Freimer 6e23030595 Fix vanilla Campfire smoke bug. MC-201374 (#7381) 2020-10-02 16:34:17 -07:00
sciwhiz12 78d69db79e Fix toggleable keybindings still being active while in GUI Fixes #7370 (#7373) 2020-10-02 16:28:21 -07:00
Max Becker 9177ac1b2e Fix modded EntityClassifications not being useable in the codec. (#7337) 2020-10-02 15:06:48 -07:00
cech12 248d207dbc Support effective materials of vanilla AxeItem (#7351) 2020-09-28 11:01:59 -07:00
LexManos 03082c361a Prep new RB. 2020-09-23 23:48:57 -07:00
ichttt 65372e3123 Fix grass disappearing when alwaysSetupTerrainOffThread is true (#7291) 2020-09-23 23:43:07 -07:00
Alex O'Neill 0f923fa51f Accessors for inspecting and removal of biome generation settings. Fixed carvers still being immutable. (#7339) 2020-09-23 23:39:25 -07:00
LexManos d1e3567c6b Revive BiomeManager and BiomeLayer hooks. 2020-09-23 23:35:40 -07:00
Richard Freimer af75547d37 Fix a few minor issues with custom tag types and fix OptionalNamedTags (#7316) 2020-09-23 20:12:11 -07:00
Take Weiland 37be3aff2d Fix ToggleableKeyBinding differences to vanilla. (#7338) 2020-09-23 15:10:01 -07:00
Take Weiland b9b17d8331 Fix forge light pipeline applying block offsets twice (#7323) 2020-09-23 14:34:38 -07:00
Yunus 2a433a5c8c Updated build badge versions to 1.16.3 in readme (#7325) 2020-09-23 14:25:59 -07:00
ichttt e344fd08a5 Add a better license error screen (#7350) 2020-09-23 14:16:36 -07:00
Tyler Hancock 0484f695fb Fixed container item being consumed in brewing stand. #7307 (#7314) 2020-09-22 12:14:08 -07:00
sciwhiz12 e55bd86dff Fix parse results of CommandEvent being disregarded (#7303) 2020-09-22 12:06:01 -07:00
Nightenom b1247df4dc [1.16] Fix possible crash when using rendering regionCache (#7207) 2020-09-22 11:58:19 -07:00
Alex O'Neill 91dda36b08 [1.16] Reimplement ICloudRenderHandler, ISkyRenderHandler and IWeatherRenderHandler (#6994) 2020-09-22 11:41:07 -07:00
Alex O'Neill ac19d1bf2b Make Biome.Climate and BiomeAmbiance fields accessible (#7336) 2020-09-17 17:57:58 -07:00
cpw e0e0302ece Use mixin 0.8.1. Should fix problems with mixin not working properly with latest modlauncher.
Signed-off-by: cpw <[email protected]>
2020-09-17 16:41:46 -04:00
Sebastian Hartte 6eb3e20abb Sets the empty/fill sounds for vanilla fluids.
Use Fluid's fillSound rather than emptySound when filling buckets.
2020-09-15 22:06:17 +02:00
Cyborgmas 738491c25d Add MatrixStack-aware alternatives to the methods in GuiUtils (#7127) 2020-09-15 21:46:58 +02:00
Justin Wiblin 2686b7a9ab Fix json biomes not setting registry name correctly for the BiomeLoadingEvent. (#7329) 2020-09-15 09:51:45 -07:00
David Quintana 4b93e3a224 Fix inconsistencies in how the values from the model are passed into the baked model.
This puts them in line with vanilla, as intended.
2020-09-15 16:17:57 +02:00
Yunus 873c490470 Reimplemented drawHoveringText (#7268) 2020-09-15 15:22:50 +02:00
LexManos 11e3281b3f New BiomeLoadingEvent that allows modders to edit biomes as they are being deserialized. 2020-09-14 17:43:01 -07:00
LexManos ce6c664acd Bump MCP version for lambda issue. 2020-09-11 08:55:13 -07:00
2060 changed files with 50187 additions and 37442 deletions

No files matched your search

+10 -12
View File
@@ -9,19 +9,24 @@
#idea
/.idea
/*/out
/classes
*.iml
#gradle
/build
/.gradle
/mdk/.gradle
/mdk/build
/*/build
/*/.gradle
#occupational hazards
# Projects repo, either ignore it, or ignore patches.
/projects/mcp/
/projects/clean/
/projects/forge/
/projects/fmlonly/
#/patches/
#occupational hazards
/projects/**/build/
/projects/**/out/
/projects/**/run/
@@ -31,18 +36,11 @@ src/generated/resources/.cache/
#Patch rejects
/patches-/
*.patch.rej
#*.patch.rej
/projects/*/rejects/
# FML changelog
changelog.txt
*.py
*.7z
/logs/
gradle.properties
!/mdk/gradle.properties
/projects/forge/rejects/
# Srg2Source causes import bugs on these patches. If you intentionnally change these, remove the ignore.
/patches/minecraft/net/minecraft/client/renderer/ViewFrustum.java.patch
/patches/minecraft/net/minecraft/data/BlockModelDefinition.java.patch
Vendored
+18 -7
View File
@@ -6,7 +6,7 @@ pipeline {
}
agent {
docker {
image 'gradle:jdk8'
image 'gradle:7-jdk16'
args '-v forgegc:/home/gradle/.gradle/'
}
}
@@ -36,9 +36,11 @@ pipeline {
}
stage('setup') {
steps {
sh './gradlew ${GRADLE_ARGS} --refresh-dependencies --continue setup'
withGradle {
sh './gradlew ${GRADLE_ARGS} --refresh-dependencies --continue setup'
}
script {
env.MYVERSION = sh(returnStdout: true, script: './gradlew :forge:properties -q | grep "version:" | awk \'{print $2}\'').trim()
env.MYVERSION = sh(returnStdout: true, script: './gradlew :forge:properties -q | grep "^version:" | cut -d" " -f2').trim()
}
}
}
@@ -59,15 +61,22 @@ pipeline {
}
}
environment {
FORGE_MAVEN = credentials('forge-maven-forge-user')
CROWDIN = credentials('forge-crowdin')
KEYSTORE = credentials('forge-jenkins-keystore-old')
KEYSTORE_KEYPASS = credentials('forge-jenkins-keystore-old-keypass')
KEYSTORE_STOREPASS = credentials('forge-jenkins-keystore-old-keypass')
}
steps {
sh './gradlew ${GRADLE_ARGS} :forge:publish -PforgeMavenUser=${FORGE_MAVEN_USR} -PforgeMavenPassword=${FORGE_MAVEN_PSW} -PkeystoreKeyPass=${KEYSTORE_KEYPASS} -PkeystoreStorePass=${KEYSTORE_STOREPASS} -Pkeystore=${KEYSTORE} -PcrowdinKey=${CROWDIN}'
sh 'curl --user ${FORGE_MAVEN} http://files.minecraftforge.net/maven/manage/promote/latest/net.minecraftforge.forge/${MYVERSION}'
withCredentials([usernamePassword(credentialsId: 'maven-forge-user', usernameVariable: 'MAVEN_USER', passwordVariable: 'MAVEN_PASSWORD')]) {
withGradle {
sh './gradlew ${GRADLE_ARGS} publish -PkeystoreKeyPass=${KEYSTORE_KEYPASS} -PkeystoreStorePass=${KEYSTORE_STOREPASS} -Pkeystore=${KEYSTORE} -PcrowdinKey=${CROWDIN}'
}
}
}
post {
success {
build job: 'filegenerator', parameters: [string(name: 'COMMAND', value: "promote net.minecraftforge:forge ${env.MYVERSION} latest")], propagate: false, wait: false
}
}
}
stage('test_publish_pr') { //Publish to local repo to test full process, but don't include credentials so it can't sign/publish to maven
@@ -78,7 +87,9 @@ pipeline {
CROWDIN = credentials('forge-crowdin')
}
steps {
sh './gradlew ${GRADLE_ARGS} :forge:publish -PcrowdinKey=${CROWDIN}'
withGradle {
sh './gradlew ${GRADLE_ARGS} publish -PcrowdinKey=${CROWDIN}'
}
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
Minecraft Forge
Copyright (c) 2016-2020.
Copyright (c) 2016-${year}.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
+971 -626
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -1,2 +1,3 @@
/.gradle/
/build/
/out/
+5 -6
View File
@@ -1,10 +1,9 @@
repositories {
//mavenCentral() //TODO: Update Gradle to use HTTPS by default
maven {
name 'maven_central'
url 'https://repo.maven.apache.org/maven2/'
}
maven { url = 'https://maven.minecraftforge.net/' }
mavenCentral()
}
dependencies {
implementation 'org.ow2.asm:asm:7.2'
implementation 'org.ow2.asm:asm:9.1'
implementation 'org.ow2.asm:asm-tree:9.1'
implementation 'net.minecraftforge:srgutils:0.4.+'
}
@@ -0,0 +1,64 @@
package net.minecraftforge.forge.tasks
import groovy.json.JsonBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.ClassReader
import org.objectweb.asm.Opcodes
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.FieldNode
import org.objectweb.asm.tree.MethodNode
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
abstract class BytecodeFinder extends DefaultTask {
@InputFile abstract RegularFileProperty getJar()
@OutputFile abstract RegularFileProperty getOutput()
BytecodeFinder() {
output.convention(project.layout.buildDirectory.dir(name).map { it.file("output.json") })
}
@TaskAction
protected void exec() {
Util.init()
def outputFile = output.get().asFile
if (outputFile.exists())
outputFile.delete()
pre()
jar.get().asFile.withInputStream { i ->
new ZipInputStream(i).withCloseable { zin ->
ZipEntry zein
while ((zein = zin.nextEntry) != null) {
if (zein.name.endsWith('.class')) {
def node = new ClassNode(Opcodes.ASM9)
new ClassReader(zin).accept(node, 0)
process(node)
}
}
}
}
post()
outputFile.text = new JsonBuilder(getData()).toPrettyString()
}
protected process(ClassNode node) {
if (node.fields != null) node.fields.each { process(node, it) }
if (node.methods != null) node.methods.each { process(node, it) }
}
protected pre() {}
protected process(ClassNode parent, FieldNode node) {}
protected process(ClassNode parent, MethodNode node) {}
protected post() {}
protected abstract Object getData()
}
@@ -1,20 +1,24 @@
package net.minecraftforge.forge.tasks
import java.util.ArrayList
import java.util.TreeMap
import net.minecraftforge.srgutils.IMappingFile
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.Opcodes
public class CheckATs extends DefaultTask {
@InputFile File inheritance
@InputFiles File[] ats
abstract class CheckATs extends DefaultTask {
@InputFile abstract RegularFileProperty getInheritance()
@InputFiles abstract ConfigurableFileCollection getAts()
@InputFile @Optional abstract RegularFileProperty getMappings()
@TaskAction
protected void exec() {
def mappings = mappings.map { IMappingFile.load(it.asFile) }.getOrNull()
Util.init()
def parse = { line ->
def idx = line.indexOf('#')
@@ -41,7 +45,7 @@ public class CheckATs extends DefaultTask {
default: return -1
}
}
def json = inheritance.json()
def json = inheritance.get().asFile.json()
ats.each { f ->
TreeMap lines = [:]
@@ -51,12 +55,12 @@ public class CheckATs extends DefaultTask {
if (line.startsWith('#group ')) {
def (modifier, cls, desc, comment, key) = parse.call(line.substring(7))
if (!desc.equals('*') && !desc.equals('*()') && !desc.equals('<init>'))
if (desc != '*' && desc != '*()' && desc != '<init>')
throw new IllegalStateException('Invalid group: ' + line)
group = [modifier: modifier, cls: cls, desc: desc, comment: comment,
'existing': [] as Set,
'children': [] as TreeSet,
existing: [] as Set,
children: [] as TreeSet,
group: true
]
if (lines.containsKey(key))
@@ -93,7 +97,7 @@ public class CheckATs extends DefaultTask {
if (jcls == null) {
lines.remove(key)
println('Invalid Group: ' + key)
} else if ('*'.equals(entry['desc'])) {
} else if ('*' == entry['desc']) {
if (!jcls.containsKey('fields')) {
lines.remove(key)
println('Invalid Group, Class has no fields: ' + key)
@@ -114,13 +118,13 @@ public class CheckATs extends DefaultTask {
}
entry['existing'].stream().findAll{ !entry['children'].contains(it) }.each{ println('Removed: ' + it) }
}
} else if ('*()'.equals(entry['desc'])) {
} else if ('*()' == entry['desc']) {
if (!jcls.containsKey('methods')) {
lines.remove(key)
println('Invalid Group, Class has no methods: ' + key)
} else {
jcls['methods'].each{ mtd, value ->
if (mtd.startsWith('<clinit>'))
if (mtd.startsWith('<clinit>') || mtd.startsWith('lambda$'))
return
key = cls + ' ' + mtd.replace(' ', '')
if (accessLevel.call(value['access']) < accessStr.call(entry['modifier'])) {
@@ -137,7 +141,7 @@ public class CheckATs extends DefaultTask {
}
entry['existing'].stream().findAll{ !entry['children'].contains(it) }.each{ println('Removed: ' + it) }
}
} else if ('<init>'.equals(entry['desc'])) { //Make all public non-abstract subclasses
} else if ('<init>' == entry['desc']) { //Make all public non-abstract subclasses
json.each{ tcls,value ->
if (!value.containsKey('methods') || ((value['access'] & Opcodes.ACC_ABSTRACT) != 0))
return
@@ -182,7 +186,7 @@ public class CheckATs extends DefaultTask {
lines.remove(key)
println('Invalid: ' + key)
} else if (entry['desc'] == '') {
if (accessLevel.call(jcls['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
if (accessLevel.call(jcls['access']) > accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
lines.remove(key)
println('Invalid Narrowing: ' + key)
}
@@ -192,7 +196,7 @@ public class CheckATs extends DefaultTask {
println('Invalid: ' + key)
} else {
def value = jcls['fields'][entry['desc']]
if (accessLevel.call(value['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
if (accessLevel.call(value['access']) > accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
lines.remove(key)
println('Invalid Narrowing: ' + key)
println(entry.comment)
@@ -205,7 +209,7 @@ public class CheckATs extends DefaultTask {
println('Invalid: ' + key)
} else {
def value = jcls['methods'][jdesc]
if (accessLevel.call(value['access']) >= accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
if (accessLevel.call(value['access']) > accessStr.call(entry['modifier']) && (entry.comment == null || !entry.comment.startsWith('#force '))) {
lines.remove(key)
println('Invalid Narrowing: ' + key)
}
@@ -216,12 +220,44 @@ public class CheckATs extends DefaultTask {
def data = []
def remapComment = { entry ->
if (!mappings || !entry || !entry.desc) return null
def comment = entry.comment?.substring(1)?.trim()
def jsonCls = json.get(entry.cls.replaceAll('\\.', '/'))
def mappingsClass = mappings?.getClass(jsonCls.name)
if (!mappingsClass) return entry.comment
def idx = entry.desc.indexOf('(')
def mappedName = idx == -1
? mappingsClass.remapField(entry.desc)
: mappingsClass.remapMethod(entry.desc.substring(0, idx), entry.desc.substring(idx))
if (!mappedName) return entry.comment
if (mappedName == '<init>')
mappedName = 'constructor'
if (comment?.startsWith(mappedName))
return '# ' + comment
if (comment && comment.indexOf(' ') != -1) {
def split = comment.split(" - ").toList()
if (split[0].indexOf(' ') != -1)
// The first string is more than one word, so append before it
return "# ${mappedName} - ${comment}"
split.remove(0)
return "# ${mappedName} - ${String.join(' - ', split)}"
}
return '# ' + mappedName
}
lines.each { key,value ->
if (!value.group) {
data.add(value.modifier + ' ' + key + (value.comment == null ? '' : ' ' + value.comment))
def comment = remapComment.call(value)
data.add(value.modifier + ' ' + key + (comment ? ' ' + comment : ''))
} else {
data.add('#group ' + value.modifier + ' ' + key + (value.comment == null ? '' : ' ' + value.comment))
value.children.each{ data.add(value.modifier + ' ' + it) }
value.children.each {
def line = value.modifier + ' ' + it
def (modifier, cls, desc, comment) = parse.call(line)
comment = remapComment.call([modifier: modifier, cls: cls, desc: desc, comment: comment])
data.add(line + (comment ? ' ' + comment : ''))
}
data.add('#endgroup')
}
}
@@ -1,7 +1,7 @@
package net.minecraftforge.forge.tasks
import java.util.ArrayList
import java.util.TreeMap
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputFile
@@ -17,17 +17,17 @@ import org.objectweb.asm.Type
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
public class CheckExcs extends DefaultTask {
@InputFile File binary
@InputFiles File[] excs
abstract class CheckExcs extends DefaultTask {
@InputFile abstract RegularFileProperty getBinary()
@InputFiles abstract ConfigurableFileCollection getExcs()
@TaskAction
protected void exec() {
Util.init()
def known = []
binary.withInputStream { i ->
binary.get().asFile.withInputStream { i ->
new ZipInputStream(i).withCloseable { zin ->
def visitor = new ClassVisitor(Opcodes.ASM7) {
def visitor = new ClassVisitor(Opcodes.ASM9) {
private String cls
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
@@ -68,8 +68,7 @@ public class CheckExcs extends DefaultTask {
def (key, value) = line.split('=', 2)
if (!known.contains(key)) {
println(key)
println('Invalid: ' + line)
println('Unknown: ' + line)
return
}
@@ -1,6 +1,7 @@
package net.minecraftforge.forge.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.TaskAction
@@ -9,19 +10,19 @@ import java.nio.file.Files
import java.nio.file.Paths
import java.util.regex.Pattern
public class CheckPatches extends DefaultTask {
@InputDirectory File patchDir
abstract class CheckPatches extends DefaultTask {
@InputDirectory abstract DirectoryProperty getPatchDir()
@Input boolean autoFix = false
@TaskAction
protected void exec() {
def hasS2SArtifact = [
Paths.get("patches/minecraft/net/minecraft/client/renderer/ViewFrustum.java.patch"),
Paths.get("patches/minecraft/net/minecraft/data/BlockModelDefinition.java.patch")
Paths.get("patches/minecraft/net/minecraft/client/renderer/ViewArea.java.patch"),
Paths.get("patches/minecraft/net/minecraft/data/models/blockstates/Variant.java.patch")
]
def verified = true;
project.fileTree(patchDir).each { patch ->
patchDir.get().asFileTree.each { patch ->
def patchPath = project.rootDir.toPath().relativize(patch.toPath())
verified &= verifyPatch(patch, autoFix, patchPath.toString(), hasS2SArtifact.contains(patchPath))
}
@@ -31,7 +32,7 @@ public class CheckPatches extends DefaultTask {
}
def verifyPatch(patch, fix, patchPath, hasS2SArtifact) {
def hunk_start_pattern = Pattern.compile('^@@ -[0-9,]* \\+[0-9,]* @@$')
def hunk_start_pattern = Pattern.compile('^@@ -[0-9,]* \\+[0-9,_]* @@$')
def white_space_pattern = Pattern.compile('^[+\\-]\\s*$')
def import_pattern = Pattern.compile('^[+\\-]\\s*import.*')
def field_pattern = Pattern.compile('^[+\\-][\\s]*((public|protected|private)[\\s]*)?(static[\\s]*)?(final)?([^=;]*)(=.*)?;\\s*$')
@@ -1,51 +1,63 @@
package net.minecraftforge.forge.tasks
import java.util.ArrayList
import java.util.TreeMap
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.TaskAction
import org.objectweb.asm.Opcodes
public class CheckSAS extends DefaultTask {
@InputFile File inheritance
@InputFiles File[] sass
abstract class CheckSAS extends DefaultTask {
@InputFile abstract RegularFileProperty getInheritance()
@InputFiles abstract ConfigurableFileCollection getSass()
@TaskAction
protected void exec() {
Util.init()
def json = inheritance.json()
def json = inheritance.get().asFile.json()
sass.each { f ->
def lines = []
f.eachLine { line ->
if (line[0] == '\t') return //Skip any tabed lines, those are ones we add
if (line[0] == '\t') return //Skip any tabbed lines, those are ones we add
def idx = line.indexOf('#')
if (idx == 0 || line.isEmpty()) {
lines.add(line)
return
}
def comment = idx == -1 ? null : line.substring(idx)
if (idx != -1) line = line.substring(0, idx - 1)
def (cls, desc) = (line.trim() + ' ').split(' ', -1)
cls = cls.replaceAll('\\.', '/')
desc = desc.replace('(', ' (')
if (desc.isEmpty() || json[cls] == null || json[cls]['methods'] == null || json[cls]['methods'][desc] == null) {
if (json[cls] == null || (!desc.isEmpty() && (json[cls]['methods'] == null || json[cls]['methods'][desc] == null))) {
println('Invalid: ' + line)
return
}
def mtd = json[cls]['methods'][desc]
//Class SAS
if (desc.isEmpty()) {
lines.add(cls + (comment == null ? '' : ' ' + comment))
if (json[cls]['methods'] != null)
(json[cls]['methods'] as TreeMap).each {
findChildMethods(json, cls, it.key).each { lines.add('\t' + it) }
}
return
}
//Method SAS
lines.add(cls + ' ' + desc.replace(' ', '') + (comment == null ? '' : ' ' + comment))
def children = json.values().findAll{ it.methods != null && it.methods[desc] != null && it.methods[desc].override == cls}
.collect { it.name + ' ' + desc.replace(' ', '') } as TreeSet
children.each { lines.add('\t' + it) }
findChildMethods(json, cls, desc).each { lines.add('\t' + it) }
}
f.text = lines.join('\n')
}
}
protected static findChildMethods(json, cls, desc)
{
return json.values().findAll{ it.methods != null && it.methods[desc] != null && it.methods[desc].override == cls}
.collect { it.name + ' ' + desc.replace(' ', '') } as TreeSet
}
}
@@ -0,0 +1,31 @@
package net.minecraftforge.forge.tasks
import java.util.function.BiConsumer
public class ClosureHelper {
BiConsumer<String, Closure> callback
public ClosureHelper(Closure cl, BiConsumer<String, Closure> callback) {
this.callback = callback
apply(this, cl)
}
def methodMissing(String name, Object args) {
if (!args.class.isArray()) return
Object[] aargs = (Object[])args
if (aargs.length == 1 && aargs[0] instanceof Closure) {
this.callback.accept(name, (Closure)aargs[0])
} else {
throw new IllegalArgumentException('Unknown method: "' + name + '" with arguments ' + args + ' for ' + this)
}
}
static <T> T apply(T obj, Closure cl) {
cl.delegate = obj
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl()
return obj
}
}
@@ -1,47 +1,55 @@
package net.minecraftforge.forge.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import java.util.zip.ZipOutputStream
import java.net.URL
public class CrowdinTask extends DefaultTask {
@Input String id = 'minecraft-forge'
@Input @Optional String key
abstract class Crowdin extends DefaultTask {
@Input abstract Property<String> getId()
@Input @Optional abstract Property<String> getKey()
@Input boolean json = true
@OutputFile output = project.file("build/${name}/output.zip")
@OutputFile export = project.file("build/${name}/export.json")
CrowdinTask() {
@OutputFile abstract RegularFileProperty getOutput()
@OutputFile abstract RegularFileProperty getExport()
Crowdin() {
outputs.upToDateWhen{ false }
id.convention('minecraft-forge')
output.convention(project.layout.buildDirectory.dir(name).map {it.file("output.zip") })
export.convention(project.layout.buildDirectory.dir(name).map {it.file("export.json") })
}
@TaskAction
def run() {
if (output.exists())
output.delete()
File outputFile = output.get().asFile
File exportFile = export.get().asFile
if (outputFile.exists())
outputFile.delete()
if (key == null)
if (!key.isPresent())
return
String key = this.key.get()
String id = this.id.get()
// Force an export
new URL("https://api.crowdin.com/api/project/${id}/export?key=${key}").withInputStream { i ->
export.withOutputStream { it << i }
new URL("https://api.crowdin.com/api/project/${id}/export?key=${key}").withInputStream { i ->
exportFile.withOutputStream { it << i }
}
if (!export.text.contains('success')) {
throw new RuntimeException("Crowdin export failed, see ${export} for more info")
if (!exportFile.text.contains('success')) {
throw new RuntimeException("Crowdin export failed, see ${exportFile} for more info")
}
new URL("https://api.crowdin.com/api/project/${id}/download/all.zip?key=${key}").withInputStream { i ->
new ZipInputStream(i).withCloseable { zin ->
output.withOutputStream { out ->
outputFile.withOutputStream { out ->
new ZipOutputStream(out).withCloseable { zout ->
ZipEntry zein
while ((zein = zin.nextEntry) != null) {
@@ -0,0 +1,54 @@
package net.minecraftforge.forge.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.OutputFiles
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.OutputDirectory
import java.nio.file.Files
abstract class DownloadLibraries extends DefaultTask {
@InputFile abstract RegularFileProperty getInput()
@OutputDirectory abstract DirectoryProperty getOutput()
@OutputFile abstract RegularFileProperty getLibrariesOutput()
DownloadLibraries() {
output.convention(project.layout.buildDirectory.dir(name))
librariesOutput.convention(project.layout.buildDirectory.dir(name).map(d -> d.file('libraries.txt')))
}
@TaskAction
def run() {
Util.init()
File outputDir = output.get().asFile
def libraries = new ArrayList()
def json = input.get().asFile.json().libraries.each { lib ->
//TODO: Thread?
def artifacts = [lib.downloads.artifact] + lib.downloads.get('classifiers', [:]).values()
artifacts.each{ art ->
def target = new File(outputDir, art.path)
libraries.add(target.absolutePath)
if (!target.exists() || !art.sha1.equals(target.sha1())) {
project.logger.lifecycle("Downloading ${art.url}")
if (!target.parentFile.exists()) {
target.parentFile.mkdirs()
}
new URL(art.url).withInputStream { i ->
target.withOutputStream { it << i }
}
if (!art.sha1.equals(target.sha1())) {
throw new IllegalStateException("Failed to download ${art.url} to ${target.canonicalPath} SHA Mismatch")
}
}
}
}
Files.write(librariesOutput.get().asFile.toPath(), libraries)
}
}
@@ -1,43 +0,0 @@
package net.minecraftforge.forge.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.OutputDirectory
import java.io.File
import java.util.HashSet
import java.util.Set
import java.net.URL
public class DownloadLibrariesTask extends DefaultTask {
@InputFile File input
@OutputDirectory File output = project.file("build/${name}/")
Set<File> libraries = new HashSet<>()
@TaskAction
def run() {
Util.init()
def json = input.json().libraries.each { lib ->
//TODO: Thread?
def artifacts = [lib.downloads.artifact] + lib.downloads.get('classifiers', [:]).values()
artifacts.each{ art ->
def target = new File(output, art.path)
libraries.add(target)
if (!target.exists() || !art.sha1.equals(target.sha1())) {
project.logger.lifecycle("Downloading ${art.url}")
if (!target.parentFile.exists()) {
target.parentFile.mkdirs()
}
new URL(art.url).withInputStream { i ->
target.withOutputStream { it << i }
}
if (!art.sha1.equals(target.sha1())) {
throw new IllegalStateException("Failed to download ${art.url} to ${target.canonicalPath} SHA Mismatch")
}
}
}
}
}
}
@@ -0,0 +1,109 @@
package net.minecraftforge.forge.tasks
import groovy.transform.EqualsAndHashCode
import java.util.ArrayList
import java.util.HashMap
import java.util.TreeMap
import java.util.TreeSet
import java.util.function.BiConsumer
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.*
import org.objectweb.asm.Opcodes
import org.objectweb.asm.Type
import org.objectweb.asm.tree.ClassNode
import org.objectweb.asm.tree.FieldNode
import org.objectweb.asm.tree.MethodNode
import static org.objectweb.asm.Opcodes.*
abstract class FieldCompareFinder extends BytecodeFinder {
@Nested
Map<String, Search> fields = [:] as HashMap
@Internal
Map<Search, String> fieldsReverse = [:] as HashMap
@Internal
Map<String, Set<ObjectTarget>> targets = [:] as TreeMap
@Override
protected pre() {
//fields.each{ k,v -> logger.lifecycle("Fields: " + k + ' ' + v) }
}
@Override
protected process(ClassNode parent, MethodNode node) {
def last = null
def parentInstance = new ObjectTarget(owner: parent.name, name: '', desc: '')
for (int x = 0; x < node.instructions.size(); x++) {
def current = node.instructions.get(x)
if (current.opcode == IF_ACMPEQ || current.opcode == IF_ACMPNE) {
if (last != null && (last.opcode == GETSTATIC || last.opcode == GETFIELD)) {
def target = new Search(cls: last.owner, name: last.name)
def wanted = fieldsReverse.get(target)
def original = fields.get(wanted)
def instance = new ObjectTarget(owner: parent.name, name: node.name, desc: node.desc)
if (wanted != null && (original.blacklist == null || (!original.blacklist.contains(instance) && !original.blacklist.contains(parentInstance)))) {
targets.computeIfAbsent(wanted, { k -> new TreeSet() }).add(instance)
}
}
}
last = current
}
}
@Internal
@Override
protected Object getData() {
def ret = [:] as HashMap
targets.forEach{ k, v ->
def e = fields.get(k)
ret[k] = [
cls: e.cls,
name: e.name,
replacement: e.replacement,
targets: v
]
}
return ret
}
@EqualsAndHashCode(excludes = ['replacement', 'blacklist'])
public static class Search {
@Input
String cls
@Input
String name
@Input
String replacement
@Nested
@Optional
Set<ObjectTarget> blacklist
@Override
String toString() {
return cls + '.' + name
}
def blacklist(def owner, def name, def desc) {
if (blacklist == null)
blacklist = new HashSet()
blacklist.add(new ObjectTarget(owner: owner, name: name, desc: desc))
}
def blacklist(def owner) {
blacklist(owner, '', '')
}
}
def fields(Closure cl) {
new ClosureHelper(cl, {name, ccl ->
def search = ClosureHelper.apply(new Search(), ccl)
this.fields.put(name, search)
this.fieldsReverse.put(search, name)
})
}
}
@@ -0,0 +1,44 @@
package net.minecraftforge.forge.tasks
import org.gradle.api.tasks.bundling.Zip
import org.gradle.api.tasks.*
import org.gradle.api.provider.SetProperty
abstract class InstallerJar extends Zip {
@Input @Optional abstract SetProperty<String> getPackedDependencies()
InstallerJar() {
archiveClassifier.set('installer')
archiveExtension.set('jar') // Needs to be Zip task to not override Manifest, so set extension
destinationDirectory.set(project.layout.buildDirectory.dir('libs'))
def installerJson = project.tasks.installerJson
def launcherJson = project.tasks.launcherJson
def downloadInstaller = project.tasks.downloadInstaller
dependsOn(installerJson, launcherJson, downloadInstaller)
from(installerJson, launcherJson)
from(project.rootProject.file('/src/main/resources/url.png'))
project.afterEvaluate {
from(project.zipTree(downloadInstaller.output)) {
duplicatesStrategy = 'exclude'
}
if (!System.env.MAVEN_USER) {
dependsOn(project.universalJar)
from(project.universalJar) {
into '/maven/' + project.group.replace('.', '/') + '/' + project.universalJar.archiveBaseName.get() + '/' + project.version + '/'
}
packedDependencies.get().forEach {
def jarTask = project.rootProject.getTasks().findByPath(it)
dependsOn(jarTask)
from(jarTask) {
into '/maven/' + jarTask.project.group.replace('.', '/') + '/' + jarTask.archiveBaseName.get() + '/' + jarTask.project.version + '/'
}
}
}
}
}
}
@@ -0,0 +1,81 @@
package net.minecraftforge.forge.tasks
import groovy.json.JsonBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.*
import java.nio.file.Files
abstract class InstallerJson extends DefaultTask {
@OutputFile abstract RegularFileProperty getOutput()
@InputFiles abstract ConfigurableFileCollection getInput()
@Input @Optional abstract SetProperty<String> getPackedDependencies()
@Input @Optional final Map<String, Object> libraries = new LinkedHashMap<>()
@Input Map<String, Object> json = new LinkedHashMap<>()
@InputFile abstract RegularFileProperty getIcon()
@Input abstract Property<String> getLauncherJsonName()
@Input abstract Property<String> getLogo()
@Input abstract Property<String> getMirrors()
@Input abstract Property<String> getWelcome()
InstallerJson() {
getLauncherJsonName().convention('/version.json')
getLogo().convention('/big_logo.png')
getMirrors().convention('https://files.minecraftforge.net/mirrors-2.0.json')
getWelcome().convention("Welcome to the simple ${project.name.capitalize()} installer.")
getOutput().convention(project.layout.buildDirectory.file('install_profile.json'))
['client', 'server'].each { side ->
['slim', 'extra'].each { type ->
def tsk = project.tasks.getByName("download${side.capitalize()}${type.capitalize()}")
dependsOn(tsk)
input.from(tsk.output)
}
def tsk = project.tasks.getByName("create${side.capitalize()}SRG")
dependsOn(tsk)
input.from(tsk.output)
}
project.afterEvaluate {
(packedDependencies.get().collect{ project.rootProject.tasks.findByPath(it) } + [project.universalJar]).forEach {
dependsOn(it)
input.from it.archiveFile
}
}
}
@TaskAction
protected void exec() {
def libs = libraries
for (def child : packedDependencies.get().collect{ project.rootProject.tasks.findByPath(it) } + [project.universalJar]) {
def dep = Util.getMavenDep(child)
def path = Util.getMavenPath(child)
libs.put(dep.toString(), [
name: dep,
downloads: [
artifact: [
path: path,
url: "https://maven.minecraftforge.net/${path}",
sha1: child.archiveFile.get().asFile.sha1(),
size: child.archiveFile.get().asFile.length()
]
]
])
}
json.libraries = libs.values().sort{a,b -> a.name.compareTo(b.name)}
json.icon = "data:image/png;base64," + new String(Base64.getEncoder().encode(Files.readAllBytes(icon.get().asFile.toPath())))
json.json = launcherJsonName.get()
json.logo = logo.get()
if (!mirrors.get().isEmpty())
json.mirrorList = mirrors.get()
json.welcome = welcome.get()
Files.writeString(output.get().getAsFile().toPath(), new JsonBuilder(json).toPrettyString())
}
}
@@ -0,0 +1,71 @@
package net.minecraftforge.forge.tasks
import groovy.json.JsonBuilder
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.*
import java.nio.file.Files
import static net.minecraftforge.forge.tasks.Util.getArtifacts
import static net.minecraftforge.forge.tasks.Util.iso8601Now
abstract class LauncherJson extends DefaultTask {
@OutputFile abstract RegularFileProperty getOutput()
@InputFiles abstract ConfigurableFileCollection getInput()
@Input Map<String, Object> json = new LinkedHashMap<>()
@Input @Optional abstract SetProperty<String> getPackedDependencies()
@Internal final vanilla = project.project(':mcp').file('build/mcp/downloadJson/version.json')
@Internal final timestamp = iso8601Now()
@Internal final comment = [
"Please do not automate the download and installation of Forge.",
"Our efforts are supported by ads from the download page.",
"If you MUST automate this, please consider supporting the project through https://www.patreon.com/LexManos/"
]
@Internal final id = "${project.rootProject.ext.MC_VERSION}-${project.name}${project.version.substring(project.rootProject.ext.MC_VERSION.length())}"
LauncherJson() {
getOutput().convention(project.layout.buildDirectory.file('version.json'))
dependsOn(':fmlloader:jar', 'universalJar')
getInput().from(project.tasks.universalJar.archiveFile,
project.project(':fmlloader').jar.archiveFile,
vanilla)
project.afterEvaluate {
packedDependencies.get().forEach {
def jarTask = project.rootProject.tasks.findByPath(it)
dependsOn(jarTask)
input.from jarTask.archiveFile
}
}
}
@TaskAction
protected void exec() {
if (!json.libraries)
json.libraries = []
getArtifacts(project, project.configurations.installer, false).each { key, lib -> json.libraries.add(lib) }
getArtifacts(project, project.configurations.moduleonly, false).each { key, lib -> json.libraries.add(lib) }
packedDependencies.get().collect{ project.rootProject.tasks.findByPath(it) }.forEach {
def path = Util.getMavenPath(it)
json.libraries.add([
name: Util.getMavenDep(it),
downloads: [
artifact: [
path: path,
url: "https://maven.minecraftforge.net/${path}",
sha1: it.archiveFile.get().asFile.sha1(),
size: it.archiveFile.get().asFile.length()
]
]
])
}
Files.writeString(output.get().asFile.toPath(), new JsonBuilder(json).toPrettyString())
}
}
@@ -0,0 +1,32 @@
package net.minecraftforge.forge.tasks
import groovy.transform.EqualsAndHashCode
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Optional
@EqualsAndHashCode
public class ObjectTarget implements Comparable<ObjectTarget> {
@Input
String owner
@Input
String name
@Input
@Optional
String desc
@Override
String toString() {
if (desc == null)
return owner + '.' + name
return owner + '.' + name + desc
}
@Override
int compareTo(ObjectTarget o) {
return toString().compareTo(o.toString())
}
}
@@ -24,6 +24,18 @@ public class Util {
def result = format.format(delegate)
return result[0..21] + ':' + result[22..-1]
}
String.metaClass.rsplit = { String del, int limit = -1 ->
def lst = new ArrayList()
def x = 0, idx
def tmp = delegate
while ((idx = tmp.lastIndexOf(del)) != -1 && (limit == -1 || x++ < limit)) {
lst.add(0, tmp.substring(idx + del.length(), tmp.length()))
tmp = tmp.substring(0, idx)
}
lst.add(0, tmp)
return lst
}
}
public static String[] getClasspath(project, libs, artifact) {
@@ -56,14 +68,15 @@ public class Util {
def path = "${folder}${filename}"
def url = "https://libraries.minecraft.net/${path}"
if (!checkExists(url)) {
url = "https://files.minecraftforge.net/maven/${path}"
url = "https://maven.minecraftforge.net/${path}"
}
//TODO remove when Mojang launcher is updated
if (!classifiers && art.classifier != null) { //Mojang launcher doesn't currently support classifiers, so... move it to part of the version, and force the extension to 'jar'
if (!classifiers && art.classifier != null) {
//Mojang launcher doesn't currently support classifiers, so... move it to part of the version, and force the extension to 'jar'
// However, keep the path normal so that our mirror system works.
art.version = "${art.version}-${art.classifier}"
art.classifier = null
art.extension = 'jar'
path = "${art.group.replace('.', '/')}/${art.name}/${art.version}/${art.name}-${art.version}.jar"
}
ret[key] = [
name: "${art.group}:${art.name}:${art.version}" + (art.classifier == null ? '' : ":${art.classifier}") + (art.extension == 'jar' ? '' : "@${art.extension}"),
@@ -79,6 +92,17 @@ public class Util {
}
return ret
}
public static def getMavenPath(task) {
def classifier = task.archiveClassifier.get()
def dep = "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier)
return "${task.project.group.replace('.', '/')}/${task.project.name}/${task.project.version}/${task.project.name}-${task.project.version}".toString() + (classifier == '' ? '' : '-' + classifier) + '.jar'
}
public static def getMavenDep(task) {
def classifier = task.archiveClassifier.get()
return "${task.project.group}:${task.project.name}:${task.project.version}" + (classifier == '' ? '' : ':' + classifier)
}
public static def iso8601Now() { new Date().iso8601() }
+3 -3
View File
@@ -1,9 +1,9 @@
<img src="assets/Forge_logo.svg">
![Forge Logo](assets/Forge_logo.svg)
MinecraftForge
=============
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/maven/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.16.2-&query=$.promos["1.16.2-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)](https://files.minecraftforge.net)
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/maven/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.16.2-&query=$.promos["1.16.2-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
[![Stable Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Stable&prefix=1.16.5-&query=$.promos["1.16.5-recommended"]&color=brightgreen&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtc3RhciBmYS13LTE4IiBhcmlhLWhpZGRlbj0idHJ1ZSIgZGF0YS1pY29uPSJzdGFyIiBkYXRhLXByZWZpeD0iZmFzIiBmb2N1c2FibGU9ImZhbHNlIiByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCA1NzYgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8cGF0aCBkPSJNMjU5LjMgMTcuOEwxOTQgMTUwLjIgNDcuOSAxNzEuNWMtMjYuMiAzLjgtMzYuNyAzNi4xLTE3LjcgNTQuNmwxMDUuNyAxMDMtMjUgMTQ1LjVjLTQuNSAyNi4zIDIzLjIgNDYgNDYuNCAzMy43TDI4OCA0MzkuNmwxMzAuNyA2OC43YzIzLjIgMTIuMiA1MC45LTcuNCA0Ni40LTMzLjdsLTI1LTE0NS41IDEwNS43LTEwM2MxOS0xOC41IDguNS01MC44LTE3LjctNTQuNkwzODIgMTUwLjIgMzE2LjcgMTcuOGMtMTEuNy0yMy42LTQ1LjYtMjMuOS01Ny40IDB6IiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K)](https://files.minecraftforge.net)
[![Latest Release](https://img.shields.io/badge/dynamic/json?url=https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json&label=Latest&prefix=1.16.5-&query=$.promos["1.16.5-latest"]&color=blue&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtYnVnIGZhLXctMTYiIGFyaWEtaGlkZGVuPSJ0cnVlIiBkYXRhLWljb249ImJ1ZyIgZGF0YS1wcmVmaXg9ImZhcyIgZm9jdXNhYmxlPSJmYWxzZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUxMS45ODggMjg4LjljLS40NzggMTcuNDMtMTUuMjE3IDMxLjEtMzIuNjUzIDMxLjFINDI0djE2YzAgMjEuODY0LTQuODgyIDQyLjU4NC0xMy42IDYxLjE0NWw2MC4yMjggNjAuMjI4YzEyLjQ5NiAxMi40OTcgMTIuNDk2IDMyLjc1OCAwIDQ1LjI1NS0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDBsLTU0LjczNi01NC43MzZDMzQ1Ljg4NiA0NjcuOTY1IDMxNC4zNTEgNDgwIDI4MCA0ODBWMjM2YzAtNi42MjctNS4zNzMtMTItMTItMTJoLTI0Yy02LjYyNyAwLTEyIDUuMzczLTEyIDEydjI0NGMtMzQuMzUxIDAtNjUuODg2LTEyLjAzNS05MC42MzYtMzIuMTA4bC01NC43MzYgNTQuNzM2Yy0xMi40OTggMTIuNDk3LTMyLjc1OSAxMi40OTYtNDUuMjU2IDAtMTIuNDk2LTEyLjQ5Ny0xMi40OTYtMzIuNzU4IDAtNDUuMjU1bDYwLjIyOC02MC4yMjhDOTIuODgyIDM3OC41ODQgODggMzU3Ljg2NCA4OCAzMzZ2LTE2SDMyLjY2NkMxNS4yMyAzMjAgLjQ5MSAzMDYuMzMuMDEzIDI4OC45LS40ODQgMjcwLjgxNiAxNC4wMjggMjU2IDMyIDI1Nmg1NnYtNTguNzQ1bC00Ni42MjgtNDYuNjI4Yy0xMi40OTYtMTIuNDk3LTEyLjQ5Ni0zMi43NTggMC00NS4yNTUgMTIuNDk4LTEyLjQ5NyAzMi43NTgtMTIuNDk3IDQ1LjI1NiAwTDE0MS4yNTUgMTYwaDIyOS40ODlsNTQuNjI3LTU0LjYyN2MxMi40OTgtMTIuNDk3IDMyLjc1OC0xMi40OTcgNDUuMjU2IDAgMTIuNDk2IDEyLjQ5NyAxMi40OTYgMzIuNzU4IDAgNDUuMjU1TDQyNCAxOTcuMjU1VjI1Nmg1NmMxNy45NzIgMCAzMi40ODQgMTQuODE2IDMxLjk4OCAzMi45ek0yNTcgMGMtNjEuODU2IDAtMTEyIDUwLjE0NC0xMTIgMTEyaDIyNEMzNjkgNTAuMTQ0IDMxOC44NTYgMCAyNTcgMHoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo=
)](https://files.minecraftforge.net) [![Discord](https://img.shields.io/discord/313125603924639766.svg?color=%237289da&label=Discord&logo=discord&logoColor=%237289da)](https://discord.gg/UvedJ9m) [![Support](https://img.shields.io/badge/Patreon-Support-orange.svg?logo=Patreon)](https://www.patreon.com/LexManos)
Forge is a free, open-source modding API all of your favourite mods use!
+64
View File
@@ -0,0 +1,64 @@
plugins {
id 'com.github.ben-manes.versions'
id 'org.javamodularity.moduleplugin' version '1.8.3' apply false
}
apply plugin: 'java-library'
apply plugin: 'jacoco'
apply plugin: 'org.javamodularity.moduleplugin'
dependencyUpdates.rejectVersionIf { isNonStable(it.candidate.version) }
dependencies {
compileOnly('org.jetbrains:annotations:21.0.1')
implementation(project(':fmlloader'))
api('net.minecraftforge:eventbus:5.0.+')
implementation('commons-io:commons-io:2.5')
}
task sourcesJar(type: Jar) {
archiveClassifier = 'sources'
from sourceSets.main.allSource
}
ext {
MANIFESTS = [
'': [
'FMLModType': 'LIBRARY',
'Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
'Git-Commit': GIT_INFO.abbreviatedId,
'Git-Branch': GIT_INFO.branch,
'Build-Number': "${System.getenv('BUILD_NUMBER')?:0}"
] as LinkedHashMap,
'net/minecraftforge/fml/loading/': [
'Specification-Title': 'FMLLoader',
'Specification-Vendor': 'Forge Development LLC',
'Specification-Version': '1',
'Implementation-Title': 'FML Loader',
'Implementation-Version': '1.0',
'Implementation-Vendor': 'Forge'
] as LinkedHashMap
]
}
jar.doFirst {
MANIFESTS.each { pkg, values ->
if (pkg == '')
manifest.attributes(values)
else
manifest.attributes(values, pkg)
}
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked'
}
artifacts {
archives jar
archives sourcesJar
}
publishing.publications.mavenJava(MavenPublication) {
from components.java
artifact sourcesJar
}
@@ -0,0 +1,36 @@
package net.minecraftforge.fml;
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
import net.minecraftforge.eventbus.api.BusBuilder;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.config.IConfigEvent;
import net.minecraftforge.fml.loading.FMLLoader;
import java.util.ServiceLoader;
import java.util.function.Supplier;
public class Bindings {
private static final Bindings INSTANCE = new Bindings();
private final IBindingsProvider provider;
private Bindings() {
final var providers = ServiceLoaderUtils.streamServiceLoader(()->ServiceLoader.load(FMLLoader.getGameLayer(), IBindingsProvider.class), sce->{}).toList();
if (providers.size() != 1) {
throw new IllegalStateException("Could not find bindings provider");
}
this.provider = providers.get(0);
}
public static Supplier<IEventBus> getForgeBus() {
return INSTANCE.provider.getForgeBusSupplier();
}
public static Supplier<I18NParser> getMessageParser() {
return INSTANCE.provider.getMessageParser();
}
public static Supplier<IConfigEvent.ConfigConfig> getConfigConfiguration() {
return INSTANCE.provider.getConfigConfiguration();
}
}
@@ -0,0 +1,32 @@
package net.minecraftforge.fml;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
public class CrashReportCallables {
private static final List<ISystemReportExtender> crashCallables = Collections.synchronizedList(new ArrayList<>());
public static void registerCrashCallable(ISystemReportExtender callable)
{
crashCallables.add(callable);
}
public static void registerCrashCallable(String headerName, Supplier<String> reportGenerator) {
registerCrashCallable(new ISystemReportExtender() {
@Override
public String getLabel() {
return headerName;
}
@Override
public String get() {
return reportGenerator.get();
}
});
}
public static List<ISystemReportExtender> allCrashCallables() {
return List.copyOf(crashCallables);
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,20 +21,19 @@ package net.minecraftforge.fml;
import static net.minecraftforge.fml.Logging.LOADING;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import net.minecraftforge.fml.event.lifecycle.ParallelDispatchEvent;
import org.apache.commons.lang3.time.StopWatch;
import com.google.common.base.Stopwatch;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.base.Stopwatch;
import net.minecraftforge.forgespi.language.IModInfo;
/**
@@ -52,26 +51,28 @@ public class DeferredWorkQueue
{
private static final Logger LOGGER = LogManager.getLogger();
private static Map<Class<? extends ParallelDispatchEvent>, DeferredWorkQueue> workQueues = new HashMap<>();
private static final Map<ModLoadingStage, DeferredWorkQueue> workQueues = new HashMap<>();
private final ModLoadingStage modLoadingStage;
private final ConcurrentLinkedDeque<TaskInfo> tasks = new ConcurrentLinkedDeque<>();
private final ModLoadingStage modLoadingStage;
public DeferredWorkQueue(final ModLoadingStage modLoadingStage, Class<? extends ParallelDispatchEvent> eventClass) {
public DeferredWorkQueue(ModLoadingStage modLoadingStage) {
this.modLoadingStage = modLoadingStage;
workQueues.put(eventClass, this);
workQueues.put(modLoadingStage, this);
}
public static Optional<DeferredWorkQueue> lookup(Optional<Class<? extends ParallelDispatchEvent>> parallelClass) {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public static Optional<DeferredWorkQueue> lookup(Optional<ModLoadingStage> parallelClass) {
return Optional.ofNullable(workQueues.get(parallelClass.orElse(null)));
}
void runTasks() {
public void runTasks() {
if (tasks.isEmpty()) return;
LOGGER.debug(LOADING, "Dispatching synchronous work after {}: {} jobs", modLoadingStage, tasks.size());
StopWatch globalTimer = StopWatch.createStarted();
LOGGER.debug(LOADING, "Dispatching synchronous work for work queue {}: {} jobs", modLoadingStage, tasks.size());
Stopwatch timer = Stopwatch.createStarted();
tasks.forEach(t->makeRunnable(t, Runnable::run));
LOGGER.debug(LOADING, "Synchronous work queue completed in {}", globalTimer);
timer.stop();
LOGGER.debug(LOADING, "Synchronous work queue completed in {}", timer);
}
private static void makeRunnable(TaskInfo ti, Executor executor) {
@@ -93,28 +94,5 @@ public class DeferredWorkQueue
return CompletableFuture.supplyAsync(work, r->tasks.add(new TaskInfo(modInfo, r)));
}
/**
* DEPRECATED FOR REMOVAL. Use {@link ParallelDispatchEvent#enqueueWork(Runnable)} or {@link ParallelDispatchEvent#enqueueWork(Supplier)}
*
* @param workToEnqueue Runnable to execute later
* @return a completable future
*/
@Deprecated
public static CompletableFuture<Void> runLater(Runnable workToEnqueue) {
return
Optional.ofNullable(ModLoadingContext.get().getActiveContainer().modLoadingStage.getDeferredWorkQueue())
.map(wq->wq.enqueueWork(ModLoadingContext.get().getActiveContainer().modInfo, workToEnqueue))
.orElseGet(()->CompletableFuture.completedFuture(null));
}
static class TaskInfo
{
public final IModInfo owner;
public final Runnable task;
private TaskInfo(IModInfo owner, Runnable task) {
this.owner = owner;
this.task = task;
}
}
record TaskInfo(IModInfo owner, Runnable task) {}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -0,0 +1,6 @@
package net.minecraftforge.fml;
public interface I18NParser {
String parseMessage(String i18nMessage, Object... args);
String stripControlCodes(String toStrip);
}
@@ -0,0 +1,12 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.config.IConfigEvent;
import java.util.function.Supplier;
public interface IBindingsProvider {
Supplier<IEventBus> getForgeBusSupplier();
Supplier<I18NParser> getMessageParser();
Supplier<IConfigEvent.ConfigConfig> getConfigConfiguration();
}
Whitespace-only changes.
@@ -0,0 +1,62 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml;
import java.util.function.BiPredicate;
import java.util.function.Supplier;
public interface IExtensionPoint<T extends Record>
{
/**
* Compatibility display test for the mod.
* Used for displaying compatibility with remote servers with the same mod, and on disk saves.
*
* The supplier provides my "local" version for sending across the network or writing to disk
* The predicate tests the version from a remote instance or save for acceptability (Boolean is true for network, false for local save)
* and returns true if the version is compatible.
*
* <p>Return {@link net.minecraftforge.fml.network.FMLNetworkConstants#IGNORESERVERONLY} in the supplier, if you wish to be ignored
* as a server side only mod.</p>
* <p>Return true in the predicate for all values of the input string (when network boolean is true) if you are client side,
* and don't care about matching any potential server version.</p>
*
* <p>
* Examples: A server only mod
*
* <code><pre>
* registerExtensionPoint(DISPLAYTEST, ()->Pair.of(
* ()->FMLNetworkConstants.IGNORESERVERONLY, // ignore me, I'm a server only mod
* (s,b)->true // i accept anything from the server or the save, if I'm asked
* )
* </pre></code>
* </p>
* <p>
* Examples: A client only mod
* <code><pre>
* registerExtensionPoint(DISPLAYTEST, ()->Pair.of(
* ()->"anything. i don't care", // if i'm actually on the server, this string is sent but i'm a client only mod, so it won't be
* (remoteversionstring,networkbool)->networkbool // i accept anything from the server, by returning true if it's asking about the server
* )
* </pre></code>
* </p>
*
*/
record DisplayTest(Supplier<String> suppliedVersion, BiPredicate<String, Boolean> remoteVersionTest) implements IExtensionPoint<DisplayTest> {}
}
@@ -0,0 +1,25 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Function;
public interface IModLoadingState {
String name();
String previous();
ModLoadingPhase phase();
Function<ModList, String> message();
Optional<Consumer<ModList>> inlineRunnable();
default <T extends Event & IModBusEvent> Optional<CompletableFuture<List<Throwable>>> buildTransition(final Executor syncExecutor, final Executor parallelExecutor) {
return buildTransition(syncExecutor, parallelExecutor, e->CompletableFuture.runAsync(()->{}, e), e->CompletableFuture.runAsync(()->{}, e));
}
<T extends Event & IModBusEvent> Optional<CompletableFuture<List<Throwable>>> buildTransition(Executor syncExecutor, Executor parallelExecutor, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask);
}
@@ -0,0 +1,7 @@
package net.minecraftforge.fml;
import java.util.List;
public interface IModStateProvider {
List<IModLoadingState> getAllStates();
}
@@ -0,0 +1,87 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
@SuppressWarnings("unchecked")
public interface IModStateTransition {
static IModStateTransition buildNoopTransition() {
return new NoopTransition();
}
default <T extends Event & IModBusEvent> CompletableFuture<List<Throwable>> build(Executor syncExecutor, Executor parallelExecutor, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
List<CompletableFuture<List<Throwable>>> cfs = new ArrayList<>();
this.eventFunctionStream().get()
.map(f->(EventGenerator<T>)f)
.reduce((head, tail)-> addCompletableFutureTaskForModDispatch(syncExecutor, parallelExecutor, cfs, head, ModLoadingStage::currentState, tail))
.ifPresent(last-> addCompletableFutureTaskForModDispatch(syncExecutor, parallelExecutor, cfs, last, nextModLoadingStage(), null));
final CompletableFuture<Void> preSyncTaskCF = preSyncTask.apply(syncExecutor);
final CompletableFuture<List<Throwable>> eventDispatchCF = ModList.gather(cfs).thenCompose(ModList::completableFutureFromExceptionList);
final CompletableFuture<List<Throwable>> postEventDispatchCF = preSyncTaskCF.thenComposeAsync(n -> eventDispatchCF, parallelExecutor).thenApply(r -> {
postSyncTask.apply(syncExecutor);
return r;
});
return this.finalActivityGenerator().apply(syncExecutor, postEventDispatchCF);
}
default BiFunction<ModLoadingStage, Throwable, ModLoadingStage> nextModLoadingStage() {
return ModLoadingStage::nextState;
}
private <T extends Event & IModBusEvent> EventGenerator<T> addCompletableFutureTaskForModDispatch(final Executor syncExecutor, final Executor parallelExecutor, final List<CompletableFuture<List<Throwable>>> completeableFutures, final EventGenerator<T> eventGenerator, BiFunction<ModLoadingStage, Throwable, ModLoadingStage> nextState, final EventGenerator<T> nextGenerator) {
completeableFutures.add(((BiFunction<Executor, EventGenerator<T>, CompletableFuture<List<Throwable>>>)preDispatchHook()).apply(threadSelector().apply(syncExecutor, parallelExecutor), eventGenerator));
completeableFutures.add(ModList.get().futureVisitor(eventGenerator, nextState).apply(threadSelector().apply(syncExecutor, parallelExecutor)));
completeableFutures.add(((BiFunction<Executor, EventGenerator<T>, CompletableFuture<List<Throwable>>>)postDispatchHook()).apply(threadSelector().apply(syncExecutor, parallelExecutor), eventGenerator));
return nextGenerator;
}
Supplier<Stream<EventGenerator<?>>> eventFunctionStream();
ThreadSelector threadSelector();
BiFunction<Executor, CompletableFuture<List<Throwable>>, CompletableFuture<List<Throwable>>> finalActivityGenerator();
BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<List<Throwable>>> preDispatchHook();
BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<List<Throwable>>> postDispatchHook();
interface EventGenerator<T extends Event & IModBusEvent> extends Function<ModContainer, T> {
static <FN extends Event & IModBusEvent> EventGenerator<FN> fromFunction(Function<ModContainer, FN> fn) {
return fn::apply;
}
}
}
record NoopTransition() implements IModStateTransition {
@Override
public Supplier<Stream<EventGenerator<?>>> eventFunctionStream() {
return Stream::of;
}
@Override
public ThreadSelector threadSelector() {
return ThreadSelector.SYNC;
}
@Override
public BiFunction<Executor, CompletableFuture<List<Throwable>>, CompletableFuture<List<Throwable>>> finalActivityGenerator() {
return (e, t) -> t.thenApplyAsync(Function.identity(), e);
}
@Override
public BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<List<Throwable>>> preDispatchHook() {
return (t, f)-> CompletableFuture.completedFuture(Collections.emptyList());
}
@Override
public BiFunction<Executor, ? extends EventGenerator<?>, CompletableFuture<List<Throwable>>> postDispatchHook() {
return (t, f)-> CompletableFuture.completedFuture(Collections.emptyList());
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,11 +17,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common;
package net.minecraftforge.fml;
import net.minecraft.crash.ICrashReportDetail;
import java.util.function.Supplier;
public interface ICrashCallable extends ICrashReportDetail<String>
public interface ISystemReportExtender extends Supplier<String>
{
String getLabel();
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,38 +33,32 @@ import java.util.stream.StreamSupport;
public class InterModComms
{
public static final class IMCMessage {
private final String modId;
private final String method;
private final String senderModId;
private final Supplier<?> thing;
IMCMessage(String senderModId, String modId, String method, Supplier<?> thing)
{
this.senderModId = senderModId;
this.modId = modId;
this.method = method;
this.thing = thing;
}
public record IMCMessage(String senderModId, String modId, String method, Supplier<?> messageSupplier) {
/**
* Deprecated: use {@link #senderModId()}
* @return The modid of the sender. This is supplied by the caller, or by the active mod container context.
* Consider it unreliable.
*/
@Deprecated
public final String getSenderModId() {
return this.senderModId;
}
/**
* Deprecated: use {@link #modId()}
* @return The modid being sent to.
*/
@Deprecated
public final String getModId() {
return this.modId;
}
/**
* Deprecated: use {@link #method()}
* @return The method being sent to.
*/
@Deprecated
public final String getMethod() {
return this.method;
}
@@ -72,10 +66,12 @@ public class InterModComms
/**
* @param <T> The type of the message.
* @return A {@link Supplier} of the message.
* Use {@link #messageSupplier()}
*/
@SuppressWarnings("unchecked")
@Deprecated
public final <T> Supplier<T> getMessageSupplier() {
return (Supplier<T>)this.thing;
return (Supplier<T>) this.messageSupplier;
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -31,6 +31,7 @@ public class Logging
public static final Marker SPLASH = MarkerManager.getMarker("SPLASH");
public static final Marker CAPABILITIES = MarkerManager.getMarker("CAPABILITIES");
public static final Marker MODELLOADING = MarkerManager.getMarker("MODELLOADING");
public static final Marker FORGEMOD = MarkerManager.getMarker("FORGEMOD").addParents(LOADING);
// --log CORE:+DEBUG,SCAN:-OFF
// forge log debug 5
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,10 +20,10 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.config.IConfigEvent;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.forgespi.language.IModInfo;
import org.apache.commons.lang3.tuple.Pair;
import java.util.EnumMap;
import java.util.HashMap;
@@ -58,10 +58,10 @@ public abstract class ModContainer
protected ModLoadingStage modLoadingStage;
protected Supplier<?> contextExtension;
protected final Map<ModLoadingStage, Runnable> activityMap = new HashMap<>();
protected final Map<ExtensionPoint, Supplier<?>> extensionPoints = new IdentityHashMap<>();
protected final Map<Class<? extends IExtensionPoint<?>>, Supplier<?>> extensionPoints = new IdentityHashMap<>();
protected final EnumMap<ModConfig.Type, ModConfig> configs = new EnumMap<>(ModConfig.Type.class);
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
protected Optional<Consumer<ModConfig.ModConfigEvent>> configHandler = Optional.empty();
protected Optional<Consumer<IConfigEvent>> configHandler = Optional.empty();
public ModContainer(IModInfo info)
{
@@ -71,10 +71,20 @@ public abstract class ModContainer
this.modInfo = info;
this.modLoadingStage = ModLoadingStage.CONSTRUCT;
// default displaytest extension checks for version string match
registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(()->this.modInfo.getVersion().toString(),
registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(()->this.modInfo.getVersion().toString(),
(incoming, isNetwork)->Objects.equals(incoming, this.modInfo.getVersion().toString())));
}
/**
* Errored container state, used for filtering. Does nothing.
*/
ModContainer()
{
this.modLoadingStage = ModLoadingStage.ERROR;
modId = "BROKEN";
namespace = "BROKEN";
modInfo = null;
}
/**
* @return the modid for this mod
*/
@@ -101,15 +111,14 @@ public abstract class ModContainer
public static <T extends Event & IModBusEvent> CompletableFuture<Void> buildTransitionHandler(
final ModContainer target,
final ModLoadingStage.EventGenerator<T> eventGenerator,
final ModLoadingStage.EventDispatcher<T> eventDispatcher,
final IModStateTransition.EventGenerator<T> eventGenerator,
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> stateChangeHandler,
final Executor executor) {
return CompletableFuture
.runAsync(() -> {
ModLoadingContext.get().setActiveContainer(target, target.contextExtension.get());
target.activityMap.getOrDefault(target.modLoadingStage, ()->{}).run();
eventDispatcher.apply(target::acceptEvent).accept(eventGenerator.apply(target));
target.acceptEvent(eventGenerator.apply(target));
}, executor)
.whenComplete((mc, exception) -> {
target.modLoadingStage = stateChangeHandler.apply(target.modLoadingStage, exception);
@@ -117,20 +126,17 @@ public abstract class ModContainer
});
}
/**
* @return the modinfo used to create this mod instance
*/
public IModInfo getModInfo()
{
return modInfo;
}
@SuppressWarnings("unchecked")
public <T> Optional<T> getCustomExtension(ExtensionPoint<T> point) {
public <T extends Record> Optional<T> getCustomExtension(Class<? extends IExtensionPoint<T>> point) {
return Optional.ofNullable((T)extensionPoints.getOrDefault(point,()-> null).get());
}
public <T> void registerExtensionPoint(ExtensionPoint<T> point, Supplier<T> extension)
public <T extends Record & IExtensionPoint<T>> void registerExtensionPoint(Class<? extends IExtensionPoint<T>> point, Supplier<T> extension)
{
extensionPoints.put(point, extension);
}
@@ -139,7 +145,7 @@ public abstract class ModContainer
configs.put(modConfig.getType(), modConfig);
}
public void dispatchConfigEvent(ModConfig.ModConfigEvent event) {
public void dispatchConfigEvent(IConfigEvent event) {
configHandler.ifPresent(configHandler->configHandler.accept(event));
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,11 +20,14 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.forgespi.language.IModFileInfo;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.forgespi.language.ModFileScanData;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.forgespi.locating.IModFile;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -58,8 +61,8 @@ public class ModList
{
private static Logger LOGGER = LogManager.getLogger();
private static ModList INSTANCE;
private final List<ModFileInfo> modFiles;
private final List<ModInfo> sortedList;
private final List<IModFileInfo> modFiles;
private final List<IModInfo> sortedList;
private final Map<String, ModFileInfo> fileById;
private List<ModContainer> mods;
private Map<String, ModContainer> indexedMods;
@@ -71,20 +74,23 @@ public class ModList
this.sortedList = sortedList.stream().
map(ModInfo.class::cast).
collect(Collectors.toList());
this.fileById = this.modFiles.stream().map(ModFileInfo::getMods).flatMap(Collection::stream).
this.fileById = this.modFiles.stream().map(IModFileInfo::getMods).flatMap(Collection::stream).
map(ModInfo.class::cast).
collect(Collectors.toMap(ModInfo::getModId, ModInfo::getOwningFile));
CrashReportExtender.registerCrashCallable("Mod List", this::crashReport);
CrashReportCallables.registerCrashCallable("Mod List", this::crashReport);
}
private String getModContainerState(String modId) {
return getModContainerById(modId).map(ModContainer::getCurrentState).map(Object::toString).orElse("NONE");
}
private String fileToLine(ModFile mf) {
return mf.getFileName() + " " + mf.getModInfos().get(0).getDisplayName() + " " +
mf.getModInfos().stream().map(mi -> mi.getModId() + "@" + mi.getVersion() + " " +
getModContainerState(mi.getModId())).collect(Collectors.joining(", ", "{", "}"));
private String fileToLine(IModFile mf) {
return String.format("%-50.50s|%-30.30s|%-30.30s|%-20.20s|%-10.10s|Manifest: %s", mf.getFileName(),
mf.getModInfos().get(0).getDisplayName(),
mf.getModInfos().get(0).getModId(),
mf.getModInfos().get(0).getVersion(),
getModContainerState(mf.getModInfos().get(0).getModId()),
((ModFileInfo)mf.getModFileInfo()).getCodeSigningFingerprint().orElse("NOSIGNATURE"));
}
private String crashReport() {
return "\n"+applyForEachModFile(this::fileToLine).collect(Collectors.joining("\n\t\t", "\t\t", ""));
@@ -108,23 +114,22 @@ public class ModList
return thread;
}
public List<ModFileInfo> getModFiles()
public List<IModFileInfo> getModFiles()
{
return modFiles;
}
public ModFileInfo getModFileById(String modid)
public IModFileInfo getModFileById(String modid)
{
return this.fileById.get(modid);
}
<T extends Event & IModBusEvent> Function<Executor, CompletableFuture<List<Throwable>>> futureVisitor(
final ModLoadingStage.EventGenerator<T> eventGenerator,
final ModLoadingStage.EventDispatcher<T> eventManager,
final IModStateTransition.EventGenerator<T> eventGenerator,
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> stateChange) {
return executor -> gather(
this.mods.stream()
.map(m -> ModContainer.buildTransitionHandler(m, eventGenerator, eventManager, stateChange, executor))
.map(mod -> ModContainer.buildTransitionHandler(mod, eventGenerator, stateChange, executor))
.collect(Collectors.toList()))
.thenComposeAsync(ModList::completableFutureFromExceptionList, executor);
}
@@ -183,7 +188,7 @@ public class ModList
return mods.stream().filter(mc -> mc.getMod() == obj).findFirst();
}
public List<ModInfo> getMods()
public List<IModInfo> getMods()
{
return this.sortedList;
}
@@ -203,24 +208,24 @@ public class ModList
if (modFileScanData == null)
{
modFileScanData = this.sortedList.stream().
map(ModInfo::getOwningFile).
map(IModInfo::getOwningFile).
filter(Objects::nonNull).
map(ModFileInfo::getFile).
map(IModFileInfo::getFile).
distinct().
map(ModFile::getScanResult).
map(IModFile::getScanResult).
collect(Collectors.toList());
}
return modFileScanData;
}
public void forEachModFile(Consumer<ModFile> fileConsumer)
public void forEachModFile(Consumer<IModFile> fileConsumer)
{
modFiles.stream().map(ModFileInfo::getFile).forEach(fileConsumer);
modFiles.stream().map(IModFileInfo::getFile).forEach(fileConsumer);
}
public <T> Stream<T> applyForEachModFile(Function<ModFile, T> function) {
return modFiles.stream().map(ModFileInfo::getFile).map(function);
public <T> Stream<T> applyForEachModFile(Function<IModFile, T> function) {
return modFiles.stream().map(IModFileInfo::getFile).map(function);
}
public void forEachModContainer(BiConsumer<String, ModContainer> modContainerConsumer) {
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,27 +20,16 @@
package net.minecraftforge.fml;
import com.google.common.collect.ImmutableList;
import cpw.mods.modlauncher.TransformingClassLoader;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.config.ConfigTracker;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
import net.minecraftforge.fml.event.IModBusEvent;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.FMLPaths;
import net.minecraftforge.fml.loading.LoadingModList;
import net.minecraftforge.fml.loading.moddiscovery.InvalidModIdentifier;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
import net.minecraftforge.fml.network.FMLNetworkConstants;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.forgespi.language.IModLanguageProvider;
import net.minecraftforge.registries.GameData;
import net.minecraftforge.registries.ObjectHolderRegistry;
import net.minecraftforge.versions.forge.ForgeVersion;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -101,33 +90,37 @@ public class ModLoader
{
private static final Logger LOGGER = LogManager.getLogger();
private static ModLoader INSTANCE;
private final TransformingClassLoader launchClassLoader;
private final LoadingModList loadingModList;
private final List<ModLoadingException> loadingExceptions;
private final List<ModLoadingWarning> loadingWarnings;
private final ModStateManager stateManager;
private boolean loadingStateValid;
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private final Optional<Consumer<String>> statusConsumer = StartupMessageManager.modLoaderConsumer();
private ModList modList;
private ModLoader()
{
INSTANCE = this;
this.launchClassLoader = FMLLoader.getLaunchClassLoader();
this.loadingModList = FMLLoader.getLoadingModList();
this.loadingExceptions = FMLLoader.getLoadingModList().
getErrors().stream().flatMap(ModLoadingException::fromEarlyException).collect(Collectors.toList());
this.loadingWarnings = FMLLoader.getLoadingModList().
getBrokenFiles().stream().map(file -> new ModLoadingWarning(null, ModLoadingStage.VALIDATE,
InvalidModIdentifier.identifyJarProblem(file.getFilePath()).orElse("fml.modloading.brokenfile"), file.getFileName())).collect(Collectors.toList());
LOGGER.debug(CORE, "Loading Network data for FML net version: {}", FMLNetworkConstants.init());
CrashReportExtender.registerCrashCallable("ModLauncher", FMLLoader::getLauncherInfo);
CrashReportExtender.registerCrashCallable("ModLauncher launch target", FMLLoader::launcherHandlerName);
CrashReportExtender.registerCrashCallable("ModLauncher naming", FMLLoader::getNaming);
CrashReportExtender.registerCrashCallable("ModLauncher services", this::computeModLauncherServiceList);
CrashReportExtender.registerCrashCallable("FML", ForgeVersion::getSpec);
CrashReportExtender.registerCrashCallable("Forge", ()->ForgeVersion.getGroup()+":"+ForgeVersion.getVersion());
CrashReportExtender.registerCrashCallable("FML Language Providers", this::computeLanguageList);
this.loadingExceptions = FMLLoader.getLoadingModList().getErrors().stream()
.flatMap(ModLoadingException::fromEarlyException)
.collect(Collectors.toList());
this.loadingWarnings = FMLLoader.getLoadingModList().getBrokenFiles().stream()
.map(file -> new ModLoadingWarning(null, ModLoadingStage.VALIDATE, InvalidModIdentifier.identifyJarProblem(file.getFilePath()).orElse("fml.modloading.brokenfile"), file.getFileName()))
.collect(Collectors.toList());
FMLLoader.getLoadingModList().getModFiles().stream()
.filter(ModFileInfo::missingLicense) //Search for files with missing licenses
.filter(modFileInfo -> modFileInfo.getMods().stream().noneMatch(thisModInfo -> this.loadingExceptions.stream().map(ModLoadingException::getModInfo).anyMatch(otherInfo -> otherInfo == thisModInfo))) //Ignore files where any other mod already encountered an error
.map(modFileInfo -> new ModLoadingException(null, ModLoadingStage.VALIDATE, "fml.modloading.missinglicense", null, modFileInfo.getFile()))
.forEach(this.loadingExceptions::add);
this.stateManager = new ModStateManager();
CrashReportCallables.registerCrashCallable("ModLauncher", FMLLoader::getLauncherInfo);
CrashReportCallables.registerCrashCallable("ModLauncher launch target", FMLLoader::launcherHandlerName);
CrashReportCallables.registerCrashCallable("ModLauncher naming", FMLLoader::getNaming);
CrashReportCallables.registerCrashCallable("ModLauncher services", this::computeModLauncherServiceList);
CrashReportCallables.registerCrashCallable("FML Language Providers", this::computeLanguageList);
}
private String computeLanguageList() {
@@ -159,11 +152,7 @@ public class ModLoader
statusConsumer.ifPresent(c->c.accept("Waiting for scan to complete"));
FMLLoader.backgroundScanHandler.waitForScanToComplete(periodicTask);
statusConsumer.ifPresent(c->c.accept("Loading mods"));
final ModList modList = ModList.of(loadingModList
.getModFiles()
.stream()
.map(ModFileInfo::getFile)
.collect(Collectors.toList()),
final ModList modList = ModList.of(loadingModList.getModFiles().stream().map(ModFileInfo::getFile).toList(),
loadingModList.getMods());
if (!this.loadingExceptions.isEmpty()) {
LOGGER.fatal(CORE, "Error during pre-loading phase", loadingExceptions.get(0));
@@ -172,11 +161,11 @@ public class ModLoader
throw new LoadingFailedException(loadingExceptions);
}
statusConsumer.ifPresent(c->c.accept("Building Mod List"));
final List<ModContainer> modContainers = loadingModList.getModFiles().stream().
map(ModFileInfo::getFile).
map(mf -> buildMods(mf, launchClassLoader)).
flatMap(Collection::stream).
collect(Collectors.toList());
final List<ModContainer> modContainers = loadingModList.getModFiles().stream()
.map(ModFileInfo::getFile)
.map(this::buildMods)
.<ModContainer>mapMulti(Iterable::forEach)
.toList();
if (!loadingExceptions.isEmpty()) {
LOGGER.fatal(CORE, "Failed to initialize mod containers", loadingExceptions.get(0));
modList.setLoadedMods(Collections.emptyList());
@@ -184,61 +173,45 @@ public class ModLoader
throw new LoadingFailedException(loadingExceptions);
}
modList.setLoadedMods(modContainers);
statusConsumer.ifPresent(c->c.accept(String.format("Constructing %d mods", modList.size())));
dispatchAndHandleError(ModLoadingStage.CONSTRUCT, syncExecutor, parallelExecutor, periodicTask);
statusConsumer.ifPresent(c->c.accept("Creating registries"));
dispatchAndHandleError(ModLoadingStage.CREATE_REGISTRIES, syncExecutor, parallelExecutor, periodicTask);
ObjectHolderRegistry.findObjectHolders();
CapabilityManager.INSTANCE.injectCapabilities(modList.getAllScanData());
statusConsumer.ifPresent(c->c.accept("Populating registries"));
dispatchAndHandleError(ModLoadingStage.LOAD_REGISTRIES, syncExecutor, parallelExecutor, periodicTask);
statusConsumer.ifPresent(c->c.accept("Adding custom tag types"));
GameData.setCustomTagTypesFromRegistries();
statusConsumer.ifPresent(c->c.accept("Early mod loading complete"));
this.modList = modList;
statusConsumer.ifPresent(c->c.accept("Dispatching gathering events"));
stateManager.getStates(ModLoadingPhase.GATHER).forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask));
statusConsumer.ifPresent(c->c.accept("Gathering phase complete"));
}
public void loadMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Function<Executor, CompletableFuture<Void>> beforeSidedEvent, final Function<Executor, CompletableFuture<Void>> afterSidedEvent, final Runnable periodicTask) {
statusConsumer.ifPresent(c->c.accept("Loading mod config"));
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, ()->()-> ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.CLIENT, FMLPaths.CONFIGDIR.get()));
ConfigTracker.INSTANCE.loadConfigs(ModConfig.Type.COMMON, FMLPaths.CONFIGDIR.get());
statusConsumer.ifPresent(c->c.accept("Mod setup: SETUP"));
dispatchAndHandleError(ModLoadingStage.COMMON_SETUP, syncExecutor, parallelExecutor, periodicTask);
statusConsumer.ifPresent(c->c.accept("Mod setup: SIDED SETUP"));
dispatchAndHandleError(ModLoadingStage.SIDED_SETUP, syncExecutor, parallelExecutor, periodicTask, beforeSidedEvent, afterSidedEvent);
public void loadMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
statusConsumer.ifPresent(c->c.accept("Performing load phase"));
stateManager.getStates(ModLoadingPhase.LOAD).forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask));
statusConsumer.ifPresent(c->c.accept("Mod setup complete"));
}
public void finishMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask)
{
statusConsumer.ifPresent(c->c.accept("Mod setup: ENQUEUE IMC"));
dispatchAndHandleError(ModLoadingStage.ENQUEUE_IMC, syncExecutor, parallelExecutor, periodicTask);
statusConsumer.ifPresent(c->c.accept("Mod setup: PROCESS IMC"));
dispatchAndHandleError(ModLoadingStage.PROCESS_IMC, syncExecutor, parallelExecutor, periodicTask);
statusConsumer.ifPresent(c->c.accept("Mod setup: Final completion"));
dispatchAndHandleError(ModLoadingStage.COMPLETE, syncExecutor, parallelExecutor, periodicTask);
statusConsumer.ifPresent(c->c.accept("Freezing data"));
GameData.freezeData();
NetworkRegistry.lock();
statusConsumer.ifPresent(c->c.accept(String.format("Mod loading complete - %d mods loaded", ModList.get().size())));
public void finishMods(final ModWorkManager.DrivenExecutor syncExecutor, final Executor parallelExecutor, final Runnable periodicTask) {
statusConsumer.ifPresent(c->c.accept("Performing completion phase"));
stateManager.getStates(ModLoadingPhase.COMPLETE).forEach(mls->dispatchAndHandleError(mls, syncExecutor, parallelExecutor, periodicTask));
statusConsumer.ifPresent(c->c.accept(String.format("Mod loading complete - %d mods loaded", this.modList.size())));
}
private void dispatchAndHandleError(ModLoadingStage state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker) {
private void dispatchAndHandleError(IModLoadingState state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker) {
if (!isLoadingStateValid()) {
LOGGER.error("Cowardly refusing to process mod state change request from {}", state);
return;
}
waitForTransition(state, syncExecutor, ticker, state.buildTransition(syncExecutor, parallelExecutor));
statusConsumer.ifPresent(c->c.accept(state.message().apply(this.modList)));
state.inlineRunnable().ifPresent(a->a.accept(this.modList));
state.buildTransition(syncExecutor, parallelExecutor).ifPresent(t->waitForTransition(state, syncExecutor, ticker, t));
}
private void dispatchAndHandleError(ModLoadingStage state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
private void dispatchAndHandleError(IModLoadingState state, ModWorkManager.DrivenExecutor syncExecutor, Executor parallelExecutor, final Runnable ticker, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
if (!isLoadingStateValid()) {
LOGGER.error("Cowardly refusing to process mod state change request from {}", state);
return;
}
waitForTransition(state, syncExecutor, ticker, state.buildTransition(syncExecutor, parallelExecutor, preSyncTask, postSyncTask));
statusConsumer.ifPresent(c->c.accept(state.message().apply(this.modList)));
state.inlineRunnable().ifPresent(a->a.accept(this.modList));
state.buildTransition(syncExecutor, parallelExecutor, preSyncTask, postSyncTask).ifPresent(t->waitForTransition(state, syncExecutor, ticker, t));
}
private void waitForTransition(final ModLoadingStage state, final ModWorkManager.DrivenExecutor syncExecutor, final Runnable ticker, final CompletableFuture<List<Throwable>> transition) {
private void waitForTransition(final IModLoadingState state, final ModWorkManager.DrivenExecutor syncExecutor, final Runnable ticker, final CompletableFuture<List<Throwable>> transition) {
while (!transition.isDone()) {
syncExecutor.drive(ticker);
}
@@ -259,18 +232,20 @@ public class ModLoader
.filter(ModLoadingException.class::isInstance)
.map(ModLoadingException.class::cast)
.collect(Collectors.toList());
LOGGER.fatal(LOADING,"Failed to complete lifecycle event {}, {} errors found", state, modLoadingExceptions.size());
LOGGER.fatal(LOADING,"Failed to complete lifecycle event {}, {} errors found", state.name(), modLoadingExceptions.size());
throw new LoadingFailedException(modLoadingExceptions);
}
}
private List<ModContainer> buildMods(final ModFile modFile, final TransformingClassLoader modClassLoader)
private List<ModContainer> buildMods(final ModFile modFile)
{
final Map<String, IModInfo> modInfoMap = modFile.getModFileInfo().getMods().stream().collect(Collectors.toMap(IModInfo::getModId, Function.identity()));
LOGGER.debug(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
final List<ModContainer> containers = modFile.getScanResult().getTargets().entrySet().stream().
map(e -> buildModContainerFromTOML(modFile, modClassLoader, modInfoMap, e))
LOGGER.trace(LOADING, "ModContainer is {}", ModContainer.class.getClassLoader());
final List<ModContainer> containers = modFile.getScanResult().getTargets()
.entrySet()
.stream()
.map(e -> buildModContainerFromTOML(modFile, modInfoMap, e))
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (containers.size() != modInfoMap.size()) {
@@ -280,21 +255,23 @@ public class ModLoader
modInfoMap.size(), modInfoMap.values().stream().map(IModInfo::getModId).sorted().collect(Collectors.toList()));
loadingExceptions.add(new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingclasses", null, modFile.getFilePath()));
}
return containers;
// remove errored mod containers
return containers.stream().filter(mc -> mc.modLoadingStage != ModLoadingStage.ERROR).collect(Collectors.toList());
}
private ModContainer buildModContainerFromTOML(final ModFile modFile, final TransformingClassLoader modClassLoader, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
private ModContainer buildModContainerFromTOML(final ModFile modFile, final Map<String, IModInfo> modInfoMap, final Map.Entry<String, ? extends IModLanguageProvider.IModLanguageLoader> idToProviderEntry) {
try {
final String modId = idToProviderEntry.getKey();
final IModLanguageProvider.IModLanguageLoader languageLoader = idToProviderEntry.getValue();
IModInfo info = Optional.ofNullable(modInfoMap.get(modId)).
// throw a missing metadata error if there is no matching modid in the modInfoMap from the mods.toml file
orElseThrow(()->new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingmetadata", null, modId));
return languageLoader.loadMod(info, modClassLoader, modFile.getScanResult());
return languageLoader.loadMod(info, modFile.getScanResult(), FMLLoader.getGameLayer());
} catch (ModLoadingException mle) {
// exceptions are caught and added to the error list for later handling. Null is returned here.
// exceptions are caught and added to the error list for later handling
loadingExceptions.add(mle);
return null;
// return an errored container instance here, because we tried and failed building a container.
return new ErroredModContainer();
}
}
@@ -337,4 +314,20 @@ public class ModLoader
public static boolean isDataGenRunning () {
return runningDataGen;
}
private static class ErroredModContainer extends ModContainer {
public ErroredModContainer() {
super();
}
@Override
public boolean matches(final Object mod) {
return false;
}
@Override
public Object getMod() {
return null;
}
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,14 +19,14 @@
package net.minecraftforge.fml;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.config.IConfigSpec;
import net.minecraftforge.fml.config.ModConfig;
import java.util.function.Supplier;
public class ModLoadingContext
{
private static ThreadLocal<ModLoadingContext> context = ThreadLocal.withInitial(ModLoadingContext::new);
private static final ThreadLocal<ModLoadingContext> context = ThreadLocal.withInitial(ModLoadingContext::new);
private Object languageExtension;
private ModLoadingStage stage;
@@ -50,20 +50,20 @@ public class ModLoadingContext
}
/**
* Register an {@link ExtensionPoint} with the mod container.
* Register an {@link IExtensionPoint} with the mod container.
* @param point The extension point to register
* @param extension An extension operator
* @param <T> The type signature of the extension operator
*/
public <T> void registerExtensionPoint(ExtensionPoint<T> point, Supplier<T> extension) {
public <T extends Record & IExtensionPoint<T>> void registerExtensionPoint(Class<? extends IExtensionPoint<T>> point, Supplier<T> extension) {
getActiveContainer().registerExtensionPoint(point, extension);
}
public void registerConfig(ModConfig.Type type, ForgeConfigSpec spec) {
public void registerConfig(ModConfig.Type type, IConfigSpec<?> spec) {
getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer()));
}
public void registerConfig(ModConfig.Type type, ForgeConfigSpec spec, String fileName) {
public void registerConfig(ModConfig.Type type, IConfigSpec<?> spec, String fileName) {
getActiveContainer().addConfig(new ModConfig(type, spec, getActiveContainer(), fileName));
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -61,7 +61,7 @@ public class ModLoadingException extends RuntimeException
}
static Stream<ModLoadingException> fromEarlyException(final EarlyLoadingException e) {
return e.getAllData().stream().map(ed->new ModLoadingException(null, ModLoadingStage.VALIDATE, ed.getI18message(), e.getCause(), ed.getArgs()));
return e.getAllData().stream().map(ed->new ModLoadingException(ed.getModInfo(), ModLoadingStage.VALIDATE, ed.getI18message(), e.getCause(), ed.getArgs()));
}
public String getI18NMessage() {
@@ -73,7 +73,7 @@ public class ModLoadingException extends RuntimeException
}
public String formatToString() {
return ForgeI18n.parseMessage(i18nMessage, Streams.concat(Stream.of(modInfo, errorStage, getCause()), context.stream()).toArray());
return Bindings.getMessageParser().get().parseMessage(i18nMessage, Streams.concat(Stream.of(modInfo, errorStage, getCause()), context.stream()).toArray());
}
@Override
@@ -85,6 +85,6 @@ public class ModLoadingException extends RuntimeException
return modInfo;
}
public String getCleanMessage() {
return ForgeI18n.stripControlCodes(formatToString());
return Bindings.getMessageParser().get().stripControlCodes(formatToString());
}
}
@@ -0,0 +1,9 @@
package net.minecraftforge.fml;
public enum ModLoadingPhase {
ERROR, // Special state for error handling
GATHER,
LOAD,
COMPLETE,
DONE;
}
@@ -0,0 +1,51 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml;
public enum ModLoadingStage
{
ERROR,
VALIDATE,
CONSTRUCT,
COMMON_SETUP,
SIDED_SETUP,
ENQUEUE_IMC,
PROCESS_IMC,
COMPLETE,
DONE;
private final DeferredWorkQueue deferredWorkQueue;
ModLoadingStage() {
deferredWorkQueue = new DeferredWorkQueue(this);
}
ModLoadingStage nextState(Throwable exception) {
return exception != null ? ERROR : values()[this.ordinal()+1];
}
public ModLoadingStage currentState(Throwable exception) {
return exception != null ? ERROR : this;
}
public DeferredWorkQueue getDeferredWorkQueue() {
return deferredWorkQueue;
}
}
@@ -0,0 +1,33 @@
package net.minecraftforge.fml;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.event.IModBusEvent;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Function;
public record ModLoadingState(String name, String previous, Function<ModList, String> message, ModLoadingPhase phase, Optional<Consumer<ModList>> inlineRunnable, Optional<IModStateTransition> transition) implements IModLoadingState {
@Override
public <T extends Event & IModBusEvent> Optional<CompletableFuture<List<Throwable>>> buildTransition(final Executor syncExecutor, final Executor parallelExecutor, Function<Executor, CompletableFuture<Void>> preSyncTask, Function<Executor, CompletableFuture<Void>> postSyncTask) {
return transition.map(t->t.build(syncExecutor, parallelExecutor, preSyncTask, postSyncTask));
}
public static ModLoadingState empty(final String name, final String previous, final ModLoadingPhase phase) {
return new ModLoadingState(name, previous, ml->"", phase, Optional.empty(), Optional.empty());
}
public static ModLoadingState withTransition(final String name, final String previous, final ModLoadingPhase phase, IModStateTransition transition) {
return new ModLoadingState(name, previous, ml->"Processing transition "+name, phase, Optional.empty(), Optional.of(transition));
}
public static ModLoadingState withTransition(final String name, final String previous, final Function<ModList, String> message, final ModLoadingPhase phase, IModStateTransition transition) {
return new ModLoadingState(name, previous, message, phase, Optional.empty(), Optional.of(transition));
}
public static ModLoadingState withInline(final String name, final String previous, final ModLoadingPhase phase, Consumer<ModList> inline) {
return new ModLoadingState(name, previous, ml->"Processing work "+name, phase, Optional.of(inline), Optional.empty());
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -55,6 +55,6 @@ public class ModLoadingWarning
}
public String formatToString() {
return ForgeI18n.parseMessage(i18nMessage, Streams.concat(Stream.of(modInfo, warningStage), context.stream()).toArray());
return Bindings.getMessageParser().get().parseMessage(i18nMessage, Streams.concat(Stream.of(modInfo, warningStage), context.stream()).toArray());
}
}
@@ -0,0 +1,38 @@
package net.minecraftforge.fml;
import com.google.common.graph.GraphBuilder;
import com.google.common.graph.MutableGraph;
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.toposort.TopologicalSort;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@SuppressWarnings("UnstableApiUsage")
public class ModStateManager {
static ModStateManager INSTANCE;
private final EnumMap<ModLoadingPhase, List<IModLoadingState>> stateMap;
public ModStateManager() {
INSTANCE = this;
final var sp = ServiceLoader.load(FMLLoader.getGameLayer(), IModStateProvider.class);
this.stateMap = ServiceLoaderUtils.streamWithErrorHandling(sp, sce->{})
.map(IModStateProvider::getAllStates)
.<IModLoadingState>mapMulti(Iterable::forEach)
.collect(Collectors.groupingBy(IModLoadingState::phase, ()->new EnumMap<>(ModLoadingPhase.class), Collectors.toUnmodifiableList()));
}
public List<IModLoadingState> getStates(final ModLoadingPhase phase) {
var nodes = stateMap.get(phase);
var lookup = nodes.stream().collect(Collectors.toMap(IModLoadingState::name, Function.identity()));
var graph = GraphBuilder.directed().allowsSelfLoops(false).<IModLoadingState>build();
var dummy = ModLoadingState.empty("", "", phase);
nodes.forEach(graph::addNode);
graph.addNode(dummy);
nodes.forEach(n->graph.putEdge(lookup.getOrDefault(n.previous(), dummy), n));
return TopologicalSort.topologicalSort(graph, Comparator.comparingInt(nodes::indexOf)).stream().filter(st->st!=dummy).toList();
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,8 +19,19 @@
package net.minecraftforge.fml;
import java.util.Optional;
import java.util.function.Consumer;
public class StartupMessageManager {
public static void addModMessage(final String message) {
net.minecraftforge.fml.loading.progress.StartupMessageManager.addModMessage(message);
}
public static Optional<Consumer<String>> modLoaderConsumer() {
return net.minecraftforge.fml.loading.progress.StartupMessageManager.modLoaderConsumer();
}
public static Optional<Consumer<String>> mcLoaderConsumer() {
return net.minecraftforge.fml.loading.progress.StartupMessageManager.mcLoaderConsumer();
}
}
@@ -0,0 +1,20 @@
package net.minecraftforge.fml;
import java.util.concurrent.Executor;
import java.util.function.BinaryOperator;
public enum ThreadSelector implements BinaryOperator<Executor> {
SYNC((sync, parallel) -> sync),
PARALLEL((sync, parallel) -> parallel);
private final BinaryOperator<Executor> selector;
ThreadSelector(final BinaryOperator<Executor> selector) {
this.selector = selector;
}
@Override
public Executor apply(final Executor sync, final Executor parallel) {
return this.selector.apply(sync, parallel);
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,15 +24,16 @@ import com.google.gson.Gson;
import net.minecraftforge.fml.loading.FMLConfig;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.versions.mcp.MCPVersion;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.maven.artifact.versioning.ComparableVersion;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.http.HttpClient;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
@@ -41,8 +42,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static net.minecraftforge.fml.VersionChecker.Status.*;
@@ -103,25 +102,7 @@ public class VersionChecker
}
public static class CheckResult
{
@Nonnull
public final Status status;
@Nullable
public final ComparableVersion target;
@Nullable
public final Map<ComparableVersion, String> changes;
@Nullable
public final String url;
private CheckResult(@Nonnull Status status, @Nullable ComparableVersion target, @Nullable Map<ComparableVersion, String> changes, @Nullable String url)
{
this.status = status;
this.target = target;
this.changes = changes == null ? Collections.<ComparableVersion, String>emptyMap() : Collections.unmodifiableMap(changes);
this.url = url;
}
}
public record CheckResult(VersionChecker.Status status, ComparableVersion target, Map<ComparableVersion, String> changes, String url) {}
public static void startVersionCheck()
{
@@ -175,13 +156,15 @@ public class VersionChecker
private void process(IModInfo mod)
{
// HttpClient.newBuilder().build();
Status status = PENDING;
ComparableVersion target = null;
Map<ComparableVersion, String> changes = null;
String display_url = null;
try
{
URL url = mod.getUpdateURL();
if (mod.getUpdateURL().isEmpty()) return;
URL url = mod.getUpdateURL().get();
LOGGER.info("[{}] Starting version check at {}", mod.getModId(), url.toString());
InputStream con = openUrlStream(url);
@@ -197,7 +180,8 @@ public class VersionChecker
Map<String, String> promos = (Map<String, String>)json.get("promos");
display_url = (String)json.get("homepage");
String mcVersion = MCPVersion.getMCVersion();
// String mcVersion = MCPVersion.getMCVersion();
var mcVersion = "1.17";
String rec = promos.get(mcVersion + "-recommended");
String lat = promos.get(mcVersion + "-latest");
ComparableVersion current = new ComparableVersion(mod.getVersion().toString());
@@ -278,9 +262,8 @@ public class VersionChecker
private static List<IModInfo> gatherMods()
{
List<IModInfo> ret = new LinkedList<>();
for (ModInfo info : ModList.get().getMods()) {
URL url = info.getUpdateURL();
if (url != null)
for (IModInfo info : ModList.get().getMods()) {
if (info.getUpdateURL().isPresent())
ret.add(info);
}
return ret;
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,6 +26,7 @@ import com.electronwill.nightconfig.core.io.ParsingException;
import com.electronwill.nightconfig.core.io.WritingMode;
import net.minecraftforge.fml.loading.FMLConfig;
import net.minecraftforge.fml.loading.FMLPaths;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -91,6 +92,38 @@ public class ConfigFileTypeHandler {
return true;
}
public static void backUpConfig(final CommentedFileConfig commentedFileConfig)
{
backUpConfig(commentedFileConfig, 5); //TODO: Think of a way for mods to set their own preference (include a sanity check as well, no disk stuffing)
}
public static void backUpConfig(final CommentedFileConfig commentedFileConfig, final int maxBackups)
{
Path bakFileLocation = commentedFileConfig.getNioPath().getParent();
String bakFileName = FilenameUtils.removeExtension(commentedFileConfig.getFile().getName());
String bakFileExtension = FilenameUtils.getExtension(commentedFileConfig.getFile().getName()) + ".bak";
Path bakFile = bakFileLocation.resolve(bakFileName + "-1" + "." + bakFileExtension);
try
{
for(int i = maxBackups; i > 0; i--)
{
Path oldBak = bakFileLocation.resolve(bakFileName + "-" + i + "." + bakFileExtension);
if(Files.exists(oldBak))
{
if(i >= maxBackups)
Files.delete(oldBak);
else
Files.move(oldBak, bakFileLocation.resolve(bakFileName + "-" + (i + 1) + "." + bakFileExtension));
}
}
Files.copy(commentedFileConfig.getNioPath(), bakFile);
}
catch (IOException exception)
{
LOGGER.warn(CONFIG, "Failed to back up config file {}", commentedFileConfig.getNioPath(), exception);
}
}
private static class ConfigWatcher implements Runnable {
private final ModConfig modConfig;
private final CommentedFileConfig commentedFileConfig;
@@ -110,13 +143,21 @@ public class ConfigFileTypeHandler {
try
{
this.commentedFileConfig.load();
if(!this.modConfig.getSpec().isCorrect(commentedFileConfig))
{
LOGGER.warn(CONFIG, "Configuration file {} is not correct. Correcting", commentedFileConfig.getFile().getAbsolutePath());
ConfigFileTypeHandler.backUpConfig(commentedFileConfig);
this.modConfig.getSpec().correct(commentedFileConfig);
commentedFileConfig.save();
}
}
catch (ParsingException ex)
{
throw new ConfigLoadingException(modConfig, ex);
}
LOGGER.debug(CONFIG, "Config file {} changed, sending notifies", this.modConfig.getFileName());
this.modConfig.fireEvent(new ModConfig.Reloading(this.modConfig));
this.modConfig.getSpec().afterReload();
this.modConfig.fireEvent(IConfigEvent.reloading(this.modConfig));
}
}
}
@@ -125,7 +166,7 @@ public class ConfigFileTypeHandler {
{
public ConfigLoadingException(ModConfig config, Exception cause)
{
super("Failed loading config file " + config.getFullPath().toString() + " with type " + config.getType() + " for modid " + config.getModId(), cause);
super("Failed loading config file " + config.getFileName() + " of type " + config.getType() + " for modid " + config.getModId(), cause);
}
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,33 +21,14 @@ package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.toml.TomlFormat;
import it.unimi.dsi.fastutil.bytes.Byte2ByteOpenCustomHashMap;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.network.FMLHandshakeMessages;
import net.minecraftforge.fml.network.NetworkEvent;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.EnumMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.rethrowFunction;
public class ConfigTracker {
private static final Logger LOGGER = LogManager.getLogger();
@@ -55,7 +36,7 @@ public class ConfigTracker {
public static final ConfigTracker INSTANCE = new ConfigTracker();
private final ConcurrentHashMap<String, ModConfig> fileMap;
private final EnumMap<ModConfig.Type, Set<ModConfig>> configSets;
private ConcurrentHashMap<String, Map<ModConfig.Type, ModConfig>> configsByMod;
private final ConcurrentHashMap<String, Map<ModConfig.Type, ModConfig>> configsByMod;
private ConfigTracker() {
this.fileMap = new ConcurrentHashMap<>();
@@ -88,22 +69,11 @@ public class ConfigTracker {
this.configSets.get(type).forEach(config -> closeConfig(config, configBasePath));
}
public List<Pair<String, FMLHandshakeMessages.S2CConfigData>> syncConfigs(boolean isLocal) {
final Map<String, byte[]> configData = configSets.get(ModConfig.Type.SERVER).stream().collect(Collectors.toMap(ModConfig::getFileName, mc -> { //TODO: Test cpw's LambdaExceptionUtils on Oracle javac.
try {
return Files.readAllBytes(mc.getFullPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
}));
return configData.entrySet().stream().map(e->Pair.of("Config "+e.getKey(), new FMLHandshakeMessages.S2CConfigData(e.getKey(), e.getValue()))).collect(Collectors.toList());
}
private void openConfig(final ModConfig config, final Path configBasePath) {
LOGGER.trace(CONFIG, "Loading config file type {} at {} for {}", config.getType(), config.getFileName(), config.getModId());
final CommentedFileConfig configData = config.getHandler().reader(configBasePath).apply(config);
config.setConfigData(configData);
config.fireEvent(new ModConfig.Loading(config));
config.fireEvent(IConfigEvent.loading(config));
config.save();
}
@@ -116,21 +86,12 @@ public class ConfigTracker {
}
}
public void receiveSyncedConfig(final FMLHandshakeMessages.S2CConfigData s2CConfigData, final Supplier<NetworkEvent.Context> contextSupplier) {
if (!Minecraft.getInstance().isIntegratedServerRunning()) {
Optional.ofNullable(fileMap.get(s2CConfigData.getFileName())).ifPresent(mc-> {
mc.setConfigData(TomlFormat.instance().createParser().parse(new ByteArrayInputStream(s2CConfigData.getBytes())));
mc.fireEvent(new ModConfig.Reloading(mc));
});
}
}
public void loadDefaultServerConfigs() {
configSets.get(ModConfig.Type.SERVER).forEach(modConfig -> {
final CommentedConfig commentedConfig = CommentedConfig.inMemory();
modConfig.getSpec().correct(commentedConfig);
modConfig.setConfigData(commentedConfig);
modConfig.fireEvent(new ModConfig.Loading(modConfig));
modConfig.fireEvent(IConfigEvent.loading(modConfig));
});
}
@@ -138,4 +99,12 @@ public class ConfigTracker {
return Optional.ofNullable(configsByMod.getOrDefault(modId, Collections.emptyMap()).getOrDefault(type, null)).
map(ModConfig::getFullPath).map(Object::toString).orElse(null);
}
public Map<ModConfig.Type, Set<ModConfig>> configSets() {
return configSets;
}
public ConcurrentHashMap<String, ModConfig> fileMap() {
return fileMap;
}
}
@@ -0,0 +1,24 @@
package net.minecraftforge.fml.config;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.fml.Bindings;
import java.util.function.Function;
public interface IConfigEvent {
record ConfigConfig(Function<ModConfig, IConfigEvent> loading, Function<ModConfig, IConfigEvent> reloading) {}
ConfigConfig CONFIGCONFIG = Bindings.getConfigConfiguration().get();
static IConfigEvent reloading(ModConfig modConfig) {
return CONFIGCONFIG.reloading().apply(modConfig);
}
static IConfigEvent loading(ModConfig modConfig) {
return CONFIGCONFIG.loading().apply(modConfig);
}
ModConfig getConfig();
@SuppressWarnings("unchecked")
default <T extends Event & IConfigEvent> T self() {
return (T) this;
}
}
@@ -0,0 +1,21 @@
package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
public interface IConfigSpec<T extends IConfigSpec<T>> extends UnmodifiableConfig {
@SuppressWarnings("unchecked")
default T self() {
return (T) this;
}
void acceptConfig(CommentedConfig data);
boolean isCorrecting();
boolean isCorrect(CommentedConfig commentedFileConfig);
int correct(CommentedConfig commentedFileConfig);
void afterReload();
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,26 +21,25 @@ package net.minecraftforge.fml.config;
import com.electronwill.nightconfig.core.CommentedConfig;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.eventbus.api.Event;
import com.electronwill.nightconfig.toml.TomlFormat;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.event.lifecycle.IModBusEvent;
import net.minecraftforge.fml.loading.StringUtils;
import java.io.ByteArrayInputStream;
import java.nio.file.Path;
import java.util.concurrent.Callable;
public class ModConfig
{
private final Type type;
private final ForgeConfigSpec spec;
private final IConfigSpec<?> spec;
private final String fileName;
private final ModContainer container;
private final ConfigFileTypeHandler configHandler;
private CommentedConfig configData;
private Callable<Void> saveHandler;
public ModConfig(final Type type, final ForgeConfigSpec spec, final ModContainer container, final String fileName) {
public ModConfig(final Type type, final IConfigSpec<?> spec, final ModContainer container, final String fileName) {
this.type = type;
this.spec = spec;
this.fileName = fileName;
@@ -49,7 +48,7 @@ public class ModConfig
ConfigTracker.INSTANCE.trackConfig(this);
}
public ModConfig(final Type type, final ForgeConfigSpec spec, final ModContainer activeContainer) {
public ModConfig(final Type type, final IConfigSpec<?> spec, final ModContainer activeContainer) {
this(type, spec, activeContainer, defaultConfigName(type, activeContainer.getModId()));
}
@@ -69,8 +68,9 @@ public class ModConfig
return configHandler;
}
public ForgeConfigSpec getSpec() {
return spec;
@SuppressWarnings("unchecked")
public <T extends IConfigSpec<T>> IConfigSpec<T> getSpec() {
return (IConfigSpec<T>) spec;
}
public String getModId() {
@@ -83,10 +83,10 @@ public class ModConfig
void setConfigData(final CommentedConfig configData) {
this.configData = configData;
this.spec.setConfig(this.configData);
this.spec.acceptConfig(this.configData);
}
void fireEvent(final ModConfigEvent configEvent) {
void fireEvent(final IConfigEvent configEvent) {
this.container.dispatchConfigEvent(configEvent);
}
@@ -98,6 +98,11 @@ public class ModConfig
return ((CommentedFileConfig)this.configData).getNioPath();
}
public void acceptSyncedConfig(byte[] bytes) {
setConfigData(TomlFormat.instance().createParser().parse(new ByteArrayInputStream(bytes)));
fireEvent(IConfigEvent.reloading(this));
}
public enum Type {
/**
* Common mod config for configuration that needs to be loaded on both environments.
@@ -133,28 +138,4 @@ public class ModConfig
return StringUtils.toLowerCase(name());
}
}
public static class ModConfigEvent extends Event implements IModBusEvent {
private final ModConfig config;
ModConfigEvent(final ModConfig config) {
this.config = config;
}
public ModConfig getConfig() {
return config;
}
}
public static class Loading extends ModConfigEvent {
Loading(final ModConfig config) {
super(config);
}
}
public static class Reloading extends ModConfigEvent {
Reloading(final ModConfig config) {
super(config);
}
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.event.lifecycle;
package net.minecraftforge.fml.event;
/**
* Marker interface for events dispatched on the ModLifecycle event bus instead of the primary event bus
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common;
package net.minecraftforge.fml.util;
import com.google.common.collect.ImmutableList;
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common;
package net.minecraftforge.fml.util;
import java.io.PrintStream;
import java.io.PrintWriter;
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,8 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common;
import net.minecraftforge.fml.common.EnhancedRuntimeException.WrappedPrintStream;
package net.minecraftforge.fml.util;
public class LoaderException extends EnhancedRuntimeException
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common;
package net.minecraftforge.fml.util;
/**
* Prevent LoaderException from adding its own stack trace to the wrapped throwable's stack trace.
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,15 +17,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common;
package net.minecraftforge.fml.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.StringJoiner;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import cpw.mods.modlauncher.api.INameMappingService;
import net.minecraftforge.fml.loading.FMLLoader;
import org.apache.logging.log4j.LogManager;
@@ -34,6 +31,8 @@ import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import com.google.common.base.Preconditions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Some reflection helper code.
@@ -58,7 +57,7 @@ public class ObfuscationReflectionHelper
* @param name The name to try and remap.
* @return The remapped name, or the original name if it couldn't be remapped.
*/
@Nonnull
@NotNull
public static String remapName(INameMappingService.Domain domain, String name)
{
return FMLLoader.getNameFunction("srg").map(f->f.apply(domain, name)).orElse(name);
@@ -72,7 +71,7 @@ public class ObfuscationReflectionHelper
*
* @param classToAccess The class to find the field on.
* @param instance The instance of the {@code classToAccess}.
* @param fieldName The SRG (unmapped) name of the field to find (e.g. "field_181725_a").
* @param fieldName The SRG (unmapped) name of the field to find (e.g. "f_46443_").
* @param <T> The type of the value.
* @param <E> The type of the {@code classToAccess}.
* @return The value of the field with the specified name in the {@code classToAccess}.
@@ -113,7 +112,7 @@ public class ObfuscationReflectionHelper
* @throws UnableToFindFieldException If there was a problem getting the field.
* @throws UnableToAccessFieldException If there was a problem setting the value of the field.
*/
public static <T, E> void setPrivateValue(@Nonnull final Class<? super T> classToAccess, @Nonnull final T instance, @Nullable final E value, @Nonnull final String fieldName)
public static <T, E> void setPrivateValue(@NotNull final Class<? super T> classToAccess, @NotNull final T instance, @Nullable final E value, @NotNull final String fieldName)
{
try
{
@@ -138,7 +137,7 @@ public class ObfuscationReflectionHelper
* Throws an exception if the method is not found.
*
* @param clazz The class to find the method on.
* @param methodName The SRG (unmapped) name of the method to find (e.g. "func_12820_D").
* @param methodName The SRG (unmapped) name of the method to find (e.g. "m_5776_").
* @param parameterTypes The parameter types of the method to find.
* @return The method with the specified name and parameters in the given class.
* @throws NullPointerException If {@code clazz} is null.
@@ -147,8 +146,8 @@ public class ObfuscationReflectionHelper
* @throws NullPointerException If {@code parameterTypes} is null.
* @throws UnableToFindMethodException If the method could not be found.
*/
@Nonnull
public static Method findMethod(@Nonnull final Class<?> clazz, @Nonnull final String methodName, @Nonnull final Class<?>... parameterTypes)
@NotNull
public static Method findMethod(@NotNull final Class<?> clazz, @NotNull final String methodName, @NotNull final Class<?>... parameterTypes)
{
Preconditions.checkNotNull(clazz, "Class to find method on cannot be null.");
Preconditions.checkNotNull(methodName, "Name of method to find cannot be null.");
@@ -181,8 +180,8 @@ public class ObfuscationReflectionHelper
* @throws NullPointerException If {@code parameterTypes} is null.
* @throws UnknownConstructorException If the constructor could not be found.
*/
@Nonnull
public static <T> Constructor<T> findConstructor(@Nonnull final Class<T> clazz, @Nonnull final Class<?>... parameterTypes)
@NotNull
public static <T> Constructor<T> findConstructor(@NotNull final Class<T> clazz, @NotNull final Class<?>... parameterTypes)
{
Preconditions.checkNotNull(clazz, "Class to find constructor on cannot be null.");
Preconditions.checkNotNull(parameterTypes, "Parameter types of constructor to find cannot be null.");
@@ -216,7 +215,7 @@ public class ObfuscationReflectionHelper
* Throws an exception if the field is not found.
*
* @param clazz The class to find the field on.
* @param fieldName The SRG (unmapped) name of the field to find (e.g. "field_181725_a").
* @param fieldName The SRG (unmapped) name of the field to find (e.g. "f_46443_").
* @param <T> The type.
* @return The constructor with the specified parameters in the given class.
* @throws NullPointerException If {@code clazz} is null.
@@ -224,8 +223,8 @@ public class ObfuscationReflectionHelper
* @throws IllegalArgumentException If {@code fieldName} is empty.
* @throws UnableToFindFieldException If the field could not be found.
*/
@Nonnull
public static <T> Field findField(@Nonnull final Class<? super T> clazz, @Nonnull final String fieldName)
@NotNull
public static <T> Field findField(@NotNull final Class<? super T> clazz, @NotNull final String fieldName)
{
Preconditions.checkNotNull(clazz, "Class to find field on cannot be null.");
Preconditions.checkNotNull(fieldName, "Name of field to find cannot be null.");
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common.thread;
package net.minecraftforge.fml.util.thread;
import net.minecraftforge.fml.LogicalSide;
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,14 +17,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common.thread;
package net.minecraftforge.fml.util.thread;
import net.minecraftforge.fml.LogicalSide;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ThreadFactory;
import javax.annotation.Nonnull;
/**
* A thread group and factory combination which belongs to a {@link LogicalSide}.
*/
@@ -49,7 +48,7 @@ public final class SidedThreadGroup extends ThreadGroup implements ThreadFactory
}
@Override
public Thread newThread(@Nonnull final Runnable runnable)
public Thread newThread(@NotNull final Runnable runnable)
{
return new Thread(this, runnable);
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.common.thread;
package net.minecraftforge.fml.util.thread;
import net.minecraftforge.fml.LogicalSide;
+80
View File
@@ -0,0 +1,80 @@
plugins {
id 'com.github.ben-manes.versions'
id 'org.javamodularity.moduleplugin' version '1.8.3' apply false
}
apply plugin: 'java-library'
apply plugin: 'jacoco'
apply plugin: 'org.javamodularity.moduleplugin'
dependencyUpdates.rejectVersionIf { isNonStable(it.candidate.version) }
configurations.forEach{ it.transitive = false }
dependencies {
implementation('net.sf.jopt-simple:jopt-simple:5.0.4')
compileOnly('org.jetbrains:annotations:21.0.0')
api("org.ow2.asm:asm:${ASM_VERSION}")
api("org.ow2.asm:asm-tree:${ASM_VERSION}")
api("org.ow2.asm:asm-commons:${ASM_VERSION}")
api('net.minecraftforge:forgespi:4.0.+')
api('org.apache.logging.log4j:log4j-api:2.14.1')
api('com.google.guava:guava:21.0')
api('com.google.code.gson:gson:2.8.0')
api('org.apache.maven:maven-artifact:3.8.1')
api('org.apache.commons:commons-lang3:3.8.1')
api('com.electronwill.night-config:core:3.6.3')
api('com.electronwill.night-config:toml:3.6.3')
api('cpw.mods:modlauncher:9.0.+')
api('net.minecraftforge:coremods:5.0.+')
implementation("cpw.mods:securejarhandler:${SECUREJARHANDLER_VERSION}")
implementation('org.apache.logging.log4j:log4j-core:2.14.1')
annotationProcessor('org.apache.logging.log4j:log4j-core:2.14.1')
implementation('net.minecraftforge:accesstransformers:8.0.4')
implementation('net.minecrell:terminalconsoleappender:1.2.0')
// implementation('org.jline:jline:3.12.+')
testCompileOnly('org.jetbrains:annotations:21.0.0')
testRuntimeOnly("cpw.mods:bootstraplauncher:${BOOTSTRAPLAUNCHER_VERSION}")
}
task sourcesJar(type: Jar) {
archiveClassifier = 'sources'
from sourceSets.main.allSource
}
ext {
MANIFESTS = [
'/': [
'Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
'Git-Commit': GIT_INFO.abbreviatedId,
'Git-Branch': GIT_INFO.branch,
'Build-Number': "${System.getenv('BUILD_NUMBER')?:0}",
] as LinkedHashMap,
'net/minecraftforge/fml/loading/': [
'Specification-Title': 'FMLLoader',
'Specification-Vendor': 'Forge Development LLC',
'Specification-Version': '1',
'Implementation-Title': 'FML Loader',
'Implementation-Version': '1.0',
'Implementation-Vendor': 'Forge'
] as LinkedHashMap
]
}
jar.doFirst {
MANIFESTS.each { pkg, values ->
manifest.attributes(values, pkg)
}
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked'
}
artifacts {
archives jar
archives sourcesJar
}
publishing.publications.mavenJava(MavenPublication) {
from components.java
artifact sourcesJar
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,7 @@
package net.minecraftforge.fml.loading;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -35,5 +36,13 @@ public class BackgroundWaiter {
} catch (InterruptedException ignored) {
}
} while (!work.isDone());
try {
runner.shutdown();
work.get();
} catch (ExecutionException ee) {
throw new RuntimeException(ee.getCause());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,8 @@
package net.minecraftforge.fml.loading;
import net.minecraftforge.forgespi.language.IModInfo;
import java.util.List;
/**
@@ -27,12 +29,17 @@ import java.util.List;
*/
public class EarlyLoadingException extends RuntimeException {
public static class ExceptionData {
private final IModInfo modInfo;
private final String i18message;
private final Object[] args;
public ExceptionData(final String message, Object... args) {
this(message, null, args);
}
public ExceptionData(final String message, final IModInfo modInfo, Object... args) {
this.i18message = message;
this.modInfo = modInfo;
this.args = args;
}
@@ -43,6 +50,10 @@ public class EarlyLoadingException extends RuntimeException {
public Object[] getArgs() {
return args;
}
public IModInfo getModInfo() {
return modInfo;
}
}
private final List<ExceptionData> errorMessages;
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,6 +21,7 @@ package net.minecraftforge.fml.loading;
import com.electronwill.nightconfig.core.ConfigSpec;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.core.file.FileNotFoundAction;
import com.electronwill.nightconfig.core.io.ParsingException;
import com.electronwill.nightconfig.core.io.WritingMode;
import net.minecraftforge.api.distmarker.Dist;
@@ -30,6 +31,7 @@ import org.apache.logging.log4j.Logger;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
@@ -50,11 +52,11 @@ public class FMLConfig
private void loadFrom(final Path configFile)
{
configData = CommentedFileConfig.builder(configFile).sync().
defaultResource("/META-INF/defaultfmlconfig.toml").
autosave().autoreload().
writingMode(WritingMode.REPLACE).
build();
configData = CommentedFileConfig.builder(configFile).sync()
.onFileNotFound(FileNotFoundAction.copyData(Objects.requireNonNull(getClass().getResourceAsStream("/META-INF/defaultfmlconfig.toml"))))
.autosave().autoreload()
.writingMode(WritingMode.REPLACE)
.build();
try
{
configData.load();
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -31,6 +31,7 @@ public class FMLEnvironment
public static final Dist dist = FMLLoader.getDist();
public static final String naming = FMLLoader.getNaming();
public static final boolean production = FMLLoader.isProduction() || System.getProperties().containsKey("production");
public static final boolean secureJarsEnabled = FMLLoader.isSecureJarEnabled();
static void setupInteropEnvironment(IEnvironment environment) {
environment.computePropertyIfAbsent(IEnvironment.Keys.NAMING.get(), v->naming);
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,40 +20,25 @@
package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.Launcher;
import cpw.mods.modlauncher.ServiceLoaderStreamUtils;
import cpw.mods.modlauncher.TransformingClassLoader;
import cpw.mods.modlauncher.api.IEnvironment;
import cpw.mods.modlauncher.api.ILaunchHandlerService;
import cpw.mods.modlauncher.api.INameMappingService;
import cpw.mods.modlauncher.api.ITransformationService;
import cpw.mods.modlauncher.api.ITransformingClassLoader;
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
import cpw.mods.modlauncher.api.*;
import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
import net.minecraftforge.accesstransformer.service.AccessTransformerService;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fml.loading.moddiscovery.BackgroundScanHandler;
import net.minecraftforge.fml.loading.moddiscovery.ModDiscoverer;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.*;
import net.minecraftforge.fml.loading.progress.EarlyProgressVisualization;
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
import net.minecraftforge.fml.loading.targets.CommonLaunchHandler;
import net.minecraftforge.forgespi.Environment;
import net.minecraftforge.forgespi.coremod.ICoreModProvider;
import net.minecraftforge.forgespi.locating.IModFile;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
@@ -70,21 +55,16 @@ public class FMLLoader
private static Dist dist;
private static String naming;
private static LoadingModList loadingModList;
private static TransformingClassLoader launchClassLoader;
private static RuntimeDistCleaner runtimeDistCleaner;
private static Path gamePath;
private static Path forgePath;
private static Path[] mcPaths;
static String mcVersion;
private static String mcpVersion;
static String forgeVersion;
private static String forgeGroup;
private static Predicate<String> classLoaderExclusions;
private static VersionInfo versionInfo;
private static String launchHandlerName;
private static FMLCommonLaunchHandler commonLaunchHandler;
private static CommonLaunchHandler commonLaunchHandler;
public static Runnable progressWindowTick;
private static ModValidator modValidator;
public static BackgroundScanHandler backgroundScanHandler;
private static boolean production;
private static IModuleLayerManager moduleLayerManager;
static void onInitialLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
{
@@ -96,8 +76,6 @@ public class FMLLoader
LOGGER.fatal(CORE,"Found incompatible ModLauncher specification : {}, version {} from {}", modLauncherPackage.getSpecificationVersion(), modLauncherPackage.getImplementationVersion(), modLauncherPackage.getImplementationVendor());
throw new IncompatibleEnvironmentException("Incompatible modlauncher found "+modLauncherPackage.getSpecificationVersion());
}
LOGGER.debug(CORE, "Initializing modjar URL handler");
URL.setURLStreamHandlerFactory(p->p.equals("modjar") ? new ModJarURLHandler() : null);
accessTransformer = (AccessTransformerService) environment.findLaunchPlugin("accesstransformer").orElseThrow(()-> {
LOGGER.fatal(CORE,"Access Transformer library is missing, we need this to run");
@@ -129,8 +107,7 @@ public class FMLLoader
});
LOGGER.debug(CORE, "Found Runtime Dist Cleaner");
final ArrayList<ICoreModProvider> coreModProviders = new ArrayList<>();
ServiceLoaderStreamUtils.errorHandlingServiceLoader(ICoreModProvider.class, serviceConfigurationError -> LOGGER.fatal(CORE, "Failed to load a coremod library, expect problems", serviceConfigurationError)).forEach(coreModProviders::add);
var coreModProviders = ServiceLoaderUtils.streamWithErrorHandling(ServiceLoader.load(FMLLoader.class.getModule().getLayer(), ICoreModProvider.class), sce -> LOGGER.fatal(CORE, "Failed to load a coremod library, expect problems", sce)).toList();
if (coreModProviders.isEmpty()) {
LOGGER.fatal(CORE, "Found no coremod provider. Cannot run");
@@ -159,7 +136,6 @@ public class FMLLoader
LOGGER.fatal(CORE, "Failed to load NightConfig");
throw new IncompatibleEnvironmentException("Missing NightConfig");
}
FixSSL.fixup();
}
static void setupLaunchHandler(final IEnvironment environment, final Map<String, ?> arguments)
@@ -167,54 +143,48 @@ public class FMLLoader
final String launchTarget = environment.getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).orElse("MISSING");
final Optional<ILaunchHandlerService> launchHandler = environment.findLaunchHandler(launchTarget);
LOGGER.debug(CORE, "Using {} as launch service", launchTarget);
if (!launchHandler.isPresent()) {
if (launchHandler.isEmpty()) {
LOGGER.fatal(CORE,"Missing LaunchHandler {}, cannot continue", launchTarget);
throw new RuntimeException("Missing launch handler");
throw new RuntimeException("Missing launch handler: " + launchTarget);
}
if (!(launchHandler.get() instanceof FMLCommonLaunchHandler)) {
if (!(launchHandler.get() instanceof CommonLaunchHandler)) {
LOGGER.fatal(CORE, "Incompatible Launch handler found - type {}, cannot continue", launchHandler.get().getClass().getName());
throw new RuntimeException("Incompatible launch handler found");
}
commonLaunchHandler = (CommonLaunchHandler)launchHandler.get();
launchHandlerName = launchHandler.get().name();
gamePath = environment.getProperty(IEnvironment.Keys.GAMEDIR.get()).orElse(Paths.get(".").toAbsolutePath());
commonLaunchHandler = (FMLCommonLaunchHandler)launchHandler.get();
naming = commonLaunchHandler.getNaming();
dist = commonLaunchHandler.getDist();
production = commonLaunchHandler.isProduction();
progressWindowTick = EarlyProgressVisualization.INSTANCE.accept(dist, commonLaunchHandler.isData());
versionInfo = new VersionInfo(arguments);
StartupMessageManager.modLoaderConsumer().ifPresent(c->c.accept("Early Loading!"));
accessTransformer.getExtension().accept(Pair.of(naming, "srg"));
mcVersion = (String) arguments.get("mcVersion");
mcpVersion = (String) arguments.get("mcpVersion");
forgeVersion = (String) arguments.get("forgeVersion");
forgeGroup = (String) arguments.get("forgeGroup");
LOGGER.debug(CORE,"Received command line version data : MC Version: '{}' MCP Version: '{}' Forge Version: '{}' Forge group: '{}'", mcVersion, mcpVersion, forgeVersion, forgeGroup);
forgePath = commonLaunchHandler.getForgePath(mcVersion, forgeVersion, forgeGroup);
mcPaths = commonLaunchHandler.getMCPaths(mcVersion, mcpVersion, forgeVersion, forgeGroup);
commonLaunchHandler.validatePaths(forgePath, mcPaths, forgeVersion, mcVersion, mcpVersion);
commonLaunchHandler.setup(environment, arguments);
classLoaderExclusions = commonLaunchHandler.getPackagePredicate();
languageLoadingProvider = new LanguageLoadingProvider();
languageLoadingProvider.addForgeLanguage(forgePath);
LOGGER.debug(CORE,"Received command line version data : {}", versionInfo);
runtimeDistCleaner.getExtension().accept(dist);
progressWindowTick.run();
}
public static Map<IModFile.Type, List<ModFile>> beginModScan(final Map<String,?> arguments)
public static List<ITransformationService.Resource> beginModScan(final Map<String,?> arguments)
{
LOGGER.debug(SCAN,"Scanning for Mod Locators");
modDiscoverer = new ModDiscoverer(arguments);
backgroundScanHandler = modDiscoverer.discoverMods();
modValidator = modDiscoverer.discoverMods();
var pluginResources = modValidator.getPluginResources();
return List.of(pluginResources);
}
public static List<ITransformationService.Resource> completeScan(IModuleLayerManager layerManager) {
progressWindowTick = EarlyProgressVisualization.INSTANCE.accept(dist, commonLaunchHandler.isData(), versionInfo.mcVersion());
moduleLayerManager = layerManager;
languageLoadingProvider = new LanguageLoadingProvider();
backgroundScanHandler = modValidator.stage2Validation();
loadingModList = backgroundScanHandler.getLoadingModList();
commonLaunchHandler.addLibraries(backgroundScanHandler.getModFiles().getOrDefault(IModFile.Type.LIBRARY, Collections.emptyList()));
progressWindowTick.run();
return backgroundScanHandler.getModFiles();
return List.of(modValidator.getModResources());
}
public static ICoreModProvider getCoreModProvider() {
@@ -230,6 +200,10 @@ public class FMLLoader
return modDiscoverer;
}
public static CommonLaunchHandler getLaunchHandler() {
return commonLaunchHandler;
}
public static void addAccessTransformer(Path atPath, ModFile modName)
{
LOGGER.debug(SCAN, "Adding Access Transformer in {}", modName.getFilePath());
@@ -241,9 +215,8 @@ public class FMLLoader
return dist;
}
public static void beforeStart(ITransformingClassLoader launchClassLoader)
public static void beforeStart(ClassLoader launchClassLoader)
{
FMLLoader.launchClassLoader = (TransformingClassLoader) launchClassLoader.getInstance();
StartupMessageManager.modLoaderConsumer().ifPresent(c->c.accept("Launching minecraft"));
progressWindowTick.run();
}
@@ -253,28 +226,11 @@ public class FMLLoader
return loadingModList;
}
public static TransformingClassLoader getLaunchClassLoader()
{
return launchClassLoader;
}
public static Path getGamePath()
{
return gamePath;
}
public static Path getForgePath() {
return forgePath;
}
public static Path[] getMCPaths() {
return mcPaths;
}
public static Predicate<String> getClassLoaderExclusions() {
return classLoaderExclusions;
}
public static String getNaming() {
return naming;
}
@@ -283,10 +239,6 @@ public class FMLLoader
return Launcher.INSTANCE.environment().findNameMapping(naming);
}
public static String getMcpVersion() {
return mcpVersion;
}
public static String getLauncherInfo() {
return Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.MLIMPL_VERSION.get()).orElse("MISSING");
}
@@ -302,4 +254,16 @@ public class FMLLoader
public static boolean isProduction() {
return production;
}
public static boolean isSecureJarEnabled() {
return true;
}
public static ModuleLayer getGameLayer() {
return moduleLayerManager.getLayer(IModuleLayerManager.Layer.GAME).orElseThrow();
}
public static VersionInfo versionInfo() {
return versionInfo;
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,10 +19,8 @@
package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.api.IEnvironment;
import cpw.mods.modlauncher.api.ITransformationService;
import cpw.mods.modlauncher.api.ITransformer;
import cpw.mods.modlauncher.api.IncompatibleEnvironmentException;
import cpw.mods.jarhandling.SecureJar;
import cpw.mods.modlauncher.api.*;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionSpecBuilder;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
@@ -30,14 +28,16 @@ import net.minecraftforge.forgespi.Environment;
import net.minecraftforge.forgespi.locating.IModFile;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.nio.file.Path;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
@@ -47,7 +47,6 @@ import static net.minecraftforge.fml.loading.LogMarkers.CORE;
public class FMLServiceProvider implements ITransformationService
{
private static final Logger LOGGER = LogManager.getLogger();
private ArgumentAcceptingOptionSpec<String> modsOption;
private ArgumentAcceptingOptionSpec<String> modListsOption;
@@ -67,6 +66,12 @@ public class FMLServiceProvider implements ITransformationService
private String targetForgeGroup;
private Map<String, Object> arguments;
public FMLServiceProvider()
{
final String markerselection = System.getProperty("forge.logging.markers", "");
Arrays.stream(markerselection.split(",")).forEach(marker -> System.setProperty("forge.logging.marker." + marker.toLowerCase(Locale.ROOT), "ACCEPT"));
}
@Override
public String name()
{
@@ -97,28 +102,22 @@ public class FMLServiceProvider implements ITransformationService
}
@Override
public void beginScanning(final IEnvironment environment) {
throw new IllegalStateException("WHY ARE YOU HERE??????");
public List<Resource> beginScanning(final IEnvironment environment) {
LOGGER.debug(CORE,"Initiating mod scan");
return FMLLoader.beginModScan(arguments);
}
@Override
public List<Map.Entry<String, Path>> runScan(final IEnvironment environment) {
LOGGER.debug(CORE,"Initiating mod scan");
final Map<IModFile.Type, List<ModFile>> foundFiles = FMLLoader.beginModScan(arguments);
return foundFiles
.values()
.stream()
.flatMap(Collection::stream)
.map(modFile -> new AbstractMap.SimpleImmutableEntry<>(modFile.getFileName(), modFile.getFilePath()))
.collect(Collectors.toList());
public List<Resource> completeScan(final IModuleLayerManager layerManager) {
return FMLLoader.completeScan(layerManager);
}
@Override
public void onLoad(IEnvironment environment, Set<String> otherServices) throws IncompatibleEnvironmentException
{
LOGGER.debug("Injecting tracing printstreams for STDOUT/STDERR.");
System.setOut(new TracingPrintStream(LogManager.getLogger("STDOUT"), System.out));
System.setErr(new TracingPrintStream(LogManager.getLogger("STDERR"), System.err));
// LOGGER.debug("Injecting tracing printstreams for STDOUT/STDERR.");
// System.setOut(new TracingPrintStream(LogManager.getLogger("STDOUT"), System.out));
// System.setErr(new TracingPrintStream(LogManager.getLogger("STDERR"), System.err));
FMLLoader.onInitialLoad(environment, otherServices);
}
@@ -148,9 +147,8 @@ public class FMLServiceProvider implements ITransformationService
targetMcpMappings = option.value(mappingsOption);
}
@Nonnull
@Override
public List<ITransformer> transformers()
public @NotNull List<ITransformer> transformers()
{
LOGGER.debug(CORE, "Loading coremod transformers");
return new ArrayList<>(FMLLoader.getCoreModProvider().getCoreModTransformers());
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,7 +19,9 @@
package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.ServiceLoaderStreamUtils;
import cpw.mods.modlauncher.Launcher;
import cpw.mods.modlauncher.api.IModuleLayerManager;
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
import net.minecraftforge.fml.loading.progress.StartupMessageManager;
import net.minecraftforge.forgespi.language.IModLanguageProvider;
import net.minecraftforge.fml.loading.moddiscovery.ExplodedDirectoryLocator;
@@ -49,13 +51,12 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import static cpw.mods.modlauncher.api.LamdbaExceptionUtils.rethrowFunction;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
public class LanguageLoadingProvider
{
private static final Logger LOGGER = LogManager.getLogger();
private final LanguageClassLoader languageClassLoader;
private final List<IModLanguageProvider> languageProviders = new ArrayList<>();
private final ServiceLoader<IModLanguageProvider> serviceLoader;
private final Map<String, ModLanguageWrapper> languageProviderMap = new HashMap<>();
@@ -71,7 +72,6 @@ public class LanguageLoadingProvider
}
private static class ModLanguageWrapper {
private final IModLanguageProvider modLanguageProvider;
private final ArtifactVersion version;
@@ -92,26 +92,14 @@ public class LanguageLoadingProvider
}
private static class LanguageClassLoader extends URLClassLoader
{
public LanguageClassLoader() {
super(new URL[0]);
}
@Override
public void addURL(final URL url) {
LOGGER.debug(CORE, "Adding {} to languageloader classloader", url);
super.addURL(url);
}
}
LanguageLoadingProvider() {
languageClassLoader = new LanguageClassLoader();
serviceLoader = ServiceLoader.load(IModLanguageProvider.class, languageClassLoader);
var sl = Launcher.INSTANCE.environment().findModuleLayerManager().flatMap(lm->lm.getLayer(IModuleLayerManager.Layer.PLUGIN)).orElseThrow();
serviceLoader = ServiceLoader.load(sl, IModLanguageProvider.class);
loadLanguageProviders();
}
private void loadLanguageProviders() {
LOGGER.debug(CORE, "Found {} language providers", ServiceLoaderStreamUtils.toList(serviceLoader).size());
LOGGER.debug(CORE, "Found {} language providers", ServiceLoaderUtils.streamServiceLoader(()->serviceLoader, sce->LOGGER.fatal("Problem with language loaders")).count());
serviceLoader.forEach(languageProviders::add);
languageProviders.forEach(lp -> {
@@ -122,7 +110,7 @@ public class LanguageLoadingProvider
throw new RuntimeException("Huh?", e);
}
Optional<String> implementationVersion = JarVersionLookupHandler.getImplementationVersion(lp.getClass());
String impl = implementationVersion.orElse(Files.isDirectory(lpPath) ? FMLLoader.forgeVersion.split("\\.")[0] : null);
String impl = implementationVersion.orElse(Files.isDirectory(lpPath) ? FMLLoader.versionInfo().forgeVersion().split("\\.")[0] : null);
if (impl == null) {
LOGGER.fatal(CORE, "Found unversioned language provider {}", lp.name());
throw new RuntimeException("Failed to find implementation version for language provider "+ lp.name());
@@ -147,7 +135,7 @@ public class LanguageLoadingProvider
private void addLanguagePaths(final Stream<Path> langPaths) {
languageProviders.clear();
languageProviderMap.clear();
langPaths.peek(languagePaths::add).map(Path::toFile).map(File::toURI).map(rethrowFunction(URI::toURL)).forEach(languageClassLoader::addURL);
// langPaths.peek(languagePaths::add).map(Path::toFile).map(File::toURI).map(rethrowFunction(URI::toURL)).forEach(languageClassLoader::addURL);
}
public void addAdditionalLanguages(List<ModFile> modFiles)
@@ -167,11 +155,11 @@ public class LanguageLoadingProvider
final String languageFileName = mf.getLocator() instanceof ExplodedDirectoryLocator ? "in-development" : mf.getFileName();
final ModLanguageWrapper mlw = languageProviderMap.get(modLoader);
if (mlw == null) {
LOGGER.error("Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName);
LOGGER.error(LOADING,"Missing language {} version {} wanted by {}", modLoader, modLoaderVersion, languageFileName);
throw new EarlyLoadingException("Missing language "+modLoader, null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, "null")));
}
if (!modLoaderVersion.containsVersion(mlw.getVersion())) {
LOGGER.error("Missing language {} version {} wanted by {}, found {}", modLoader, modLoaderVersion, languageFileName, mlw.getVersion());
if (!VersionSupportMatrix.testVersionSupportMatrix(modLoaderVersion, modLoader, "languageloader", (llid, range) -> range.containsVersion(mlw.getVersion()))) {
LOGGER.error(LOADING,"Missing language {} version {} wanted by {}, found {}", modLoader, modLoaderVersion, languageFileName, mlw.getVersion());
throw new EarlyLoadingException("Missing language "+ modLoader + " matching range "+modLoaderVersion + " found "+mlw.getVersion(), null, Collections.singletonList(new EarlyLoadingException.ExceptionData("fml.language.missingversion", modLoader, modLoaderVersion, languageFileName, mlw.getVersion())));
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,11 +36,10 @@ public class LibraryFinder {
private static Path libsPath;
static Path findLibsPath() {
if (libsPath == null) {
final Path asm = findJarPathFor("org/objectweb/asm/Opcodes.class", "asm");
// go up SIX parents to find the libs dir
final Path libs = asm.getParent().getParent().getParent().getParent().getParent().getParent();
LOGGER.debug(CORE, "Found probable library path {}", libs);
libsPath = libs;
libsPath = Path.of(System.getProperty("libraryDirectory","crazysnowmannonsense/cheezwhizz"));
if (!Files.isDirectory(libsPath)) {
throw new IllegalStateException("Missing libraryDirectory system property, cannot continue");
}
}
return libsPath;
}
@@ -54,8 +53,9 @@ public class LibraryFinder {
try {
Path path;
final URI uri = resource.toURI();
if (uri.getRawSchemeSpecificPart().contains("!")) {
path = Paths.get(new URI(uri.getRawSchemeSpecificPart().split("!")[0]));
if (uri.getScheme().equals("jar") && uri.getRawSchemeSpecificPart().contains("!/")) {
int lastExcl = uri.getRawSchemeSpecificPart().lastIndexOf("!/");
path = Paths.get(new URI(uri.getRawSchemeSpecificPart().substring(0, lastExcl)));
} else {
path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-resourceName.length())));
}
@@ -86,4 +86,14 @@ public class LibraryFinder {
LOGGER.debug(CORE,"Forge patches at {} is {}", patchedBinariesPath.toString(), pathStatus(patchedBinariesPath));
return new Path[] { patchedBinariesPath, mcExtrasPath, srgMcPath };
}
public static Path findPathForMaven(final String group, final String artifact, final String extension, final String classifier, final String version) {
return findLibsPath().resolve(MavenCoordinateResolver.get(group, artifact, extension, classifier, version));
}
public static Path findPathForMaven(final String maven) {
return findLibsPath().resolve(MavenCoordinateResolver.get(maven));
}
public static Path getFMLCorePath() {
return findLibsPath().resolve(MavenCoordinateResolver.get("net.minecraftforge:fmlcore:1.0"));
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -41,8 +41,6 @@ public class LoadingModList
private final List<ModFileInfo> modFiles;
private final List<ModInfo> sortedList;
private final Map<String, ModFileInfo> fileById;
@SuppressWarnings("unused")
private BackgroundScanHandler scanner;
private final List<EarlyLoadingException> preLoadErrors;
private List<ModFile> brokenFiles;
@@ -94,7 +92,6 @@ public class LoadingModList
public void addForScanning(BackgroundScanHandler backgroundScanHandler)
{
this.scanner = backgroundScanHandler;
backgroundScanHandler.setLoadingModList(this);
modFiles.stream()
.map(ModFileInfo::getFile)
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -27,5 +27,4 @@ public class LogMarkers {
public static final Marker LOADING = MarkerManager.getMarker("LOADING");
public static final Marker SCAN = MarkerManager.getMarker("SCAN");
public static final Marker SPLASH = MarkerManager.getMarker("SPLASH");
public static final Marker FORGEMOD = MarkerManager.getMarker("FORGEMOD").addParents(LOADING);
}
@@ -1,23 +1,4 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.userdev;
package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.api.INameMappingService;
import org.apache.commons.lang3.tuple.Pair;
@@ -47,7 +28,7 @@ public class MCPNamingService implements INameMappingService {
@Override
public String mappingVersion() {
return "1234";
return "1234"; //TODO: Minecraft Version?
}
@Override
@@ -92,19 +73,14 @@ public class MCPNamingService implements INameMappingService {
return fields.getOrDefault(origin, origin);
}
private static void loadMappings(final String mappingFileName, BiConsumer<String, String> mapStore)
{
URL path = ClassLoader.getSystemResource(mappingFileName); //We EXPLICITLY go throught the SystemClassLoader here because this is dev-time only. And will be on the root classpath.
private static void loadMappings(final String mappingFileName, BiConsumer<String, String> mapStore) {
URL path = ClassLoader.getSystemResource(mappingFileName); //We EXPLICITLY go through the SystemClassLoader here because this is dev-time only. And will be on the root classpath.
if (path == null)
return;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(path.openStream())))
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader(path.openStream()))) {
reader.lines().skip(1).map(e -> e.split(",")).forEach(e -> mapStore.accept(e[0], e[1]));
}
catch (IOException e1)
{
} catch (IOException e1) {
LOGGER.error(CORE, "Error reading mappings", e1);
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,6 +20,7 @@
package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import cpw.mods.modlauncher.api.NamedPath;
import cpw.mods.modlauncher.serviceapi.ITransformerDiscoveryService;
import org.apache.logging.log4j.LogManager;
@@ -29,40 +30,30 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import java.util.zip.ZipFile;
public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService {
@Override
public List<Path> candidates(final Path gameDirectory) {
public List<NamedPath> candidates(final Path gameDirectory) {
ModDirTransformerDiscoverer.scan(gameDirectory);
return ModDirTransformerDiscoverer.transformers;
return List.copyOf(found);
}
private static List<Path> transformers = new ArrayList<>();
private static List<Path> locators = new ArrayList<>();
private final static List<NamedPath> found = new ArrayList<>();
public static List<Path> allExcluded() {
ArrayList<Path> paths = new ArrayList<>();
paths.addAll(transformers);
paths.addAll(locators);
return paths;
}
public static List<Path> getExtraLocators() {
return locators;
return found.stream().map(np->np.paths()[0]).toList();
}
private static void scan(final Path gameDirectory) {
final Path modsDir = gameDirectory.resolve(FMLPaths.MODSDIR.relative()).toAbsolutePath().normalize();
transformers = new ArrayList<>();
locators = new ArrayList<>();
if (!Files.exists(modsDir)) {
// Skip if the mods dir doesn't exist yet.
return;
}
try {
Files.createDirectories(modsDir);
Files.walk(modsDir, 1).forEach(ModDirTransformerDiscoverer::visitFile);
try (var walk = Files.walk(modsDir, 1)){
walk.forEach(ModDirTransformerDiscoverer::visitFile);
} catch (IOException | IllegalStateException ioe) {
LogManager.getLogger().error("Error during early discovery", ioe);
}
@@ -74,9 +65,9 @@ public class ModDirTransformerDiscoverer implements ITransformerDiscoveryService
if (LamdbaExceptionUtils.uncheck(() -> Files.size(path)) == 0) return;
try (ZipFile zf = new ZipFile(new File(path.toUri()))) {
if (zf.getEntry("META-INF/services/cpw.mods.modlauncher.api.ITransformationService") != null) {
transformers.add(path);
found.add(new NamedPath(zf.getName(), path));
} else if (zf.getEntry("META-INF/services/net.minecraftforge.forgespi.locating.IModLocator") != null) {
locators.add(path);
found.add(new NamedPath(zf.getName(), path));
}
} catch (IOException ioe) {
LogManager.getLogger().error("Zip Error when loading jar file {}", path, ioe);
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,7 @@
package net.minecraftforge.fml.loading;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -29,6 +30,7 @@ import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.jar.Manifest;
@@ -43,6 +45,18 @@ public class ModJarURLHandler extends URLStreamHandler
return new ModJarURLConnection(url);
}
@Override
protected int hashCode(final URL u) {
return Objects.hash(u.getHost(), u.getFile());
}
@Override
protected boolean equals(final URL u1, final URL u2) {
return Objects.equals(u1.getProtocol(), u2.getProtocol())
&& Objects.equals(u1.getHost(), u2.getHost())
&& Objects.equals(u1.getFile(), u2.getFile());
}
static class ModJarURLConnection extends URLConnection {
private Path resource;
private String modpath;
@@ -56,13 +70,13 @@ public class ModJarURLHandler extends URLStreamHandler
@Override
public void connect()
{
if (resource == null) {
modid = url.getHost();
// trim first char
modpath = url.getPath().substring(1);
resource = FMLLoader.getLoadingModList().getModFileById(modid).getFile().findResource(modpath);
manifest = FMLLoader.getLoadingModList().getModFileById(modid).getManifest();
}
// if (resource == null) {
// modid = url.getHost();
// // trim first char
// modpath = url.getPath().substring(1);
// resource = FMLLoader.getLoadingModList().getModFileById(modid).getFile().findResource(modpath);
// manifest = FMLLoader.getLoadingModList().getModFileById(modid).getManifest();
// }
}
@Override
@@ -83,6 +97,12 @@ public class ModJarURLHandler extends URLStreamHandler
}
}
// Used to cache protectiondomains by "top level object" aka the modid
@Override
public URL getURL() {
return LamdbaExceptionUtils.uncheck(()->new URL("modjar://"+modid));
}
public Optional<Manifest> getManifest() {
return manifest;
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,17 +36,13 @@ import org.apache.logging.log4j.util.StringBuilderFormattable;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
public class ModSorter
@@ -55,30 +51,37 @@ public class ModSorter
private List<ModFile> modFiles;
private List<ModInfo> sortedList;
private Map<String, ModInfo> modIdNameLookup;
private List<ModFile> forgeAndMC;
private ModSorter(final List<ModFile> modFiles)
{
this.modFiles = modFiles;
}
public static LoadingModList sort(List<ModFile> mods)
public static LoadingModList sort(List<ModFile> mods, final List<ExceptionData> errors)
{
final ModSorter ms = new ModSorter(mods);
EarlyLoadingException earlyLoadingException = null;
try {
ms.findLanguages();
ms.buildUniqueList();
ms.verifyDependencyVersions();
ms.sort();
} catch (EarlyLoadingException ele) {
earlyLoadingException = ele;
ms.sortedList = Collections.emptyList();
} catch (EarlyLoadingException e) {
// We cannot build any list with duped mods. We have to abort immediately and report it
return LoadingModList.of(ms.forgeAndMC, ms.forgeAndMC.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(toList()), e);
}
// try and validate dependencies
final List<ExceptionData> failedList = Stream.concat(ms.verifyDependencyVersions().stream(), errors.stream()).toList();
// if we miss one or the other, we abort now
if (!failedList.isEmpty()) {
return LoadingModList.of(ms.forgeAndMC, ms.forgeAndMC.stream().map(mf->(ModInfo)mf.getModInfos().get(0)).collect(toList()), new EarlyLoadingException("failure to validate mod list", null, failedList));
} else {
// Otherwise, lets try and sort the modlist and proceed
EarlyLoadingException earlyLoadingException = null;
try {
ms.sort();
} catch (EarlyLoadingException e) {
earlyLoadingException = e;
}
return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException);
}
return LoadingModList.of(ms.modFiles, ms.sortedList, earlyLoadingException);
}
private void findLanguages() {
modFiles.forEach(ModFile::identifyLanguage);
}
@SuppressWarnings("UnstableApiUsage")
@@ -87,17 +90,15 @@ public class ModSorter
// lambdas are identity based, so sorting them is impossible unless you hold reference to them
final MutableGraph<ModFileInfo> graph = GraphBuilder.directed().build();
AtomicInteger counter = new AtomicInteger();
Map<IModFileInfo, Integer> infos = modFiles
.stream()
Map<IModFileInfo, Integer> infos = modFiles.stream()
.map(ModFile::getModFileInfo)
.collect(Collectors.toMap(Function.identity(), e -> counter.incrementAndGet()));
.collect(toMap(Function.identity(), e -> counter.incrementAndGet()));
infos.keySet().forEach(i -> graph.addNode((ModFileInfo) i));
modFiles
.stream()
modFiles.stream()
.map(ModFile::getModInfos)
.flatMap(Collection::stream)
.<IModInfo>mapMulti(Iterable::forEach)
.map(IModInfo::getDependencies)
.flatMap(Collection::stream)
.<IModInfo.ModVersion>mapMulti(Iterable::forEach)
.forEach(dep -> addDependency(graph, dep));
final List<ModFileInfo> sorted;
@@ -108,33 +109,27 @@ public class ModSorter
catch (CyclePresentException e)
{
Set<Set<ModFileInfo>> cycles = e.getCycles();
LOGGER.error(LOADING, () -> ((StringBuilderFormattable) (buffer -> {
buffer.append("Mod Sorting failed.\n");
buffer.append("Detected Cycles: ");
buffer.append(cycles);
buffer.append('\n');
})));
List<ExceptionData> dataList = cycles.stream()
.map(Set::stream)
.map(stream -> stream
.flatMap(modFileInfo -> modFileInfo.getMods()
.stream()
.map(IModInfo::getModId))
.collect(Collectors.toList()))
LOGGER.error(LOADING, () -> new AdvancedLogMessageAdapter(buffer ->
buffer.append("Mod Sorting failed.\n")
.append("Detected Cycles: ")
.append(cycles)
.append('\n')));
var dataList = cycles.stream()
.<ModFileInfo>mapMulti(Iterable::forEach)
.<IModInfo>mapMulti((mf,c)->mf.getMods().forEach(c))
.map(IModInfo::getModId)
.map(list -> new ExceptionData("fml.modloading.cycle", list))
.collect(Collectors.toList());
.toList();
throw new EarlyLoadingException("Sorting error", e, dataList);
}
this.sortedList = sorted
.stream()
this.sortedList = sorted.stream()
.map(ModFileInfo::getMods)
.flatMap(Collection::stream)
.<IModInfo>mapMulti(Iterable::forEach)
.map(ModInfo.class::cast)
.collect(Collectors.toList());
this.modFiles = sorted
.stream()
.collect(toList());
this.modFiles = sorted.stream()
.map(ModFileInfo::getFile)
.collect(Collectors.toList());
.collect(toList());
}
@SuppressWarnings("UnstableApiUsage")
@@ -148,58 +143,55 @@ public class ModSorter
if (self == target)
return; // in case a jar has two mods that have dependencies between
switch (dep.getOrdering()) {
case BEFORE:
topoGraph.putEdge(self, target);
break;
case AFTER:
topoGraph.putEdge(target, self);
break;
case NONE:
break;
case BEFORE -> topoGraph.putEdge(self, target);
case AFTER -> topoGraph.putEdge(target, self);
}
}
private void buildUniqueList()
{
// Collect mod files by first modid in the file. This will be used for deduping purposes
final Map<String, List<IModFile>> modFilesByFirstId = modFiles
.stream()
.collect(Collectors.groupingBy(mf -> mf.getModInfos().get(0).getModId()));
final Map<String, List<IModFile>> modFilesByFirstId = modFiles.stream()
.collect(groupingBy(mf -> mf.getModInfos().get(0).getModId()));
// Capture forge and MC here, so we can keep them for later
forgeAndMC = new ArrayList<>();
var mc = modFilesByFirstId.get("minecraft");
if (mc != null && !mc.isEmpty())
forgeAndMC.add((ModFile) mc.get(0));
else
throw new IllegalStateException("Failed to find minecraft somehow?");
// Select the newest by artifact version sorting of non-unique files thus identified
this.modFiles = modFilesByFirstId.entrySet().stream()
.map(this::selectNewestModInfo)
.map(Map.Entry::getValue)
.map(ModFile.class::cast)
.collect(Collectors.toList());
.collect(toList());
// Transform to the full mod id list
final Map<String, List<ModInfo>> modIds = modFiles.stream()
.map(ModFile::getModInfos)
.flatMap(Collection::stream)
.map(ModInfo.class::cast)
.collect(Collectors.groupingBy(IModInfo::getModId));
.collect(groupingBy(IModInfo::getModId));
// Its theoretically possible that some mod has somehow moved an id to a secondary place, thus causing a dupe.
// We can't handle this
final List<Map.Entry<String, List<ModInfo>>> dupedMods = modIds
.entrySet()
.stream()
.filter(e -> e.getValue().size() > 1)
.collect(Collectors.toList());
final List<ModInfo> dupedMods = modIds.values().stream()
.filter(modInfos -> modInfos.size() > 1)
.map(modInfos -> modInfos.get(0))
.toList();
if (!dupedMods.isEmpty()) {
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods
.stream()
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod", dm.getValue().get(0)))
.collect(Collectors.toList());
final List<EarlyLoadingException.ExceptionData> duplicateModErrors = dupedMods.stream()
.map(dm -> new EarlyLoadingException.ExceptionData("fml.modloading.dupedmod",
dm, Objects.toString(dm))).toList();
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
}
modIdNameLookup = modIds
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
modIdNameLookup = modIds.entrySet().stream()
.collect(toMap(Map.Entry::getKey, e -> e.getValue().get(0)));
}
private Map.Entry<String, IModFile> selectNewestModInfo(Map.Entry<String, List<IModFile>> fullList) {
@@ -209,51 +201,47 @@ public class ModSorter
modInfoList.sort(Comparator.<IModFile, ArtifactVersion>comparing(mf -> mf.getModInfos().get(0).getVersion()).reversed());
LOGGER.debug("Selected file {} for modid {} with version {}", modInfoList.get(0).getFileName(), fullList.getKey(), modInfoList.get(0).getModInfos().get(0).getVersion());
}
return new AbstractMap.SimpleImmutableEntry<>(fullList.getKey(), modInfoList.get(0));
return Map.entry(fullList.getKey(), modInfoList.get(0));
}
private void verifyDependencyVersions()
private List<EarlyLoadingException.ExceptionData> verifyDependencyVersions()
{
final Map<String, ArtifactVersion> modVersions = modFiles
.stream()
final var modVersions = modFiles.stream()
.map(ModFile::getModInfos)
.flatMap(Collection::stream)
.collect(Collectors.toMap(IModInfo::getModId, IModInfo::getVersion));
.<IModInfo>mapMulti(Iterable::forEach)
.collect(toMap(IModInfo::getModId, IModInfo::getVersion));
final Map<IModInfo, List<IModInfo.ModVersion>> modVersionDependencies = modFiles
.stream()
final var modVersionDependencies = modFiles.stream()
.map(ModFile::getModInfos)
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(Function.identity(), Java9BackportUtils.flatMapping(e -> e.getDependencies().stream(), Collectors.toList())));
.<IModInfo>mapMulti(Iterable::forEach)
.collect(groupingBy(Function.identity(), flatMapping(e -> e.getDependencies().stream(), toList())));
final Set<IModInfo.ModVersion> mandatoryModVersions = modVersionDependencies
.values()
.stream()
.flatMap(Collection::stream)
.filter(mv -> mv.isMandatory() && mv.getSide().isCorrectSide())
.collect(Collectors.toSet());
final var modRequirements = modVersionDependencies.values().stream()
.<IModInfo.ModVersion>mapMulti(Iterable::forEach)
.filter(mv -> mv.getSide().isCorrectSide())
.collect(toSet());
LOGGER.debug(LOADING, "Found {} mandatory requirements", mandatoryModVersions.size());
final Set<IModInfo.ModVersion> missingVersions = mandatoryModVersions
.stream()
.filter(mv->this.modVersionMatches(mv, modVersions))
.collect(Collectors.toSet());
LOGGER.debug(LOADING, "Found {} mandatory mod requirements missing", missingVersions.size());
final long mandatoryRequired = modRequirements.stream().filter(IModInfo.ModVersion::isMandatory).count();
LOGGER.debug(LOADING, "Found {} mod requirements ({} mandatory, {} optional)", modRequirements.size(), mandatoryRequired, modRequirements.size() - mandatoryRequired);
final var missingVersions = modRequirements.stream()
.filter(mv -> (mv.isMandatory() || modVersions.containsKey(mv.getModId())) && this.modVersionNotContained(mv, modVersions))
.collect(toSet());
final long mandatoryMissing = missingVersions.stream().filter(IModInfo.ModVersion::isMandatory).count();
LOGGER.debug(LOADING, "Found {} mod requirements missing ({} mandatory, {} optional)", missingVersions.size(), mandatoryMissing, missingVersions.size() - mandatoryMissing);
if (!missingVersions.isEmpty()) {
final List<EarlyLoadingException.ExceptionData> exceptionData = missingVersions
.stream()
.map(mv -> new EarlyLoadingException.ExceptionData("fml.modloading.missingdependency",
mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(),
return missingVersions.stream()
.map(mv -> new ExceptionData(mv.isMandatory() ? "fml.modloading.missingdependency" : "fml.modloading.missingdependency.optional",
mv.getOwner(), mv.getModId(), mv.getOwner().getModId(), mv.getVersionRange(),
modVersions.getOrDefault(mv.getModId(), new DefaultArtifactVersion("null"))))
.collect(Collectors.toList());
throw new EarlyLoadingException("Missing mods", null, exceptionData);
.toList();
}
return Collections.emptyList();
}
private boolean modVersionMatches(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
{
return !(modVersions.containsKey(mv.getModId()) &&
(mv.getVersionRange().containsVersion(modVersions.get(mv.getModId())) || modVersions.get(mv.getModId()).toString().equals("NONE")));
return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) &&
(range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("NONE"))));
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -196,7 +196,7 @@ public class RuntimeDistCleaner implements ILaunchPluginService
private final List<Handle> dynamicLambdaHandles = new ArrayList<>();
public LambdaGatherer() {
super(Opcodes.ASM7);
super(Opcodes.ASM9);
}
public void accept(MethodNode method) {
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,8 +30,8 @@ import java.util.Map;
public class StringSubstitutor
{
private static final Map<String,String> globals = ImmutableMap.of(
"mcVersion", FMLLoader.mcVersion,
"forgeVersion", FMLLoader.forgeVersion
"mcVersion", FMLLoader.versionInfo().mcVersion(),
"forgeVersion", FMLLoader.versionInfo().forgeVersion()
);
public static String replace(final String in, final ModFile file) {
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -26,8 +26,7 @@ import java.net.URL;
import java.util.Locale;
import java.util.Map;
public class StringUtils
{
public class StringUtils {
public static String toLowerCase(final String str) {
return str.toLowerCase(Locale.ROOT);
}
@@ -42,12 +41,12 @@ public class StringUtils
}
public static URL toURL(final String string) {
try
{
return new URL(string);
}
catch (MalformedURLException e)
{
if (string == null || string.trim().isEmpty() || string.contains("myurl.me") || string.contains("example.invalid"))
return null;
try {
return new URL(string); }
catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
@@ -55,4 +54,13 @@ public class StringUtils
public static String parseStringFormat(final String input, final Map<String, String> properties) {
return StrSubstitutor.replace(input, properties);
}
public static String binToHex(final byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toHexString((bytes[i]&0xf0) >>4));
sb.append(Integer.toHexString(bytes[i]&0x0f));
}
return sb.toString();
}
}
@@ -1,6 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2020.
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -0,0 +1,17 @@
package net.minecraftforge.fml.loading;
import java.util.Map;
public record VersionInfo(String forgeVersion, String mcVersion, String mcpVersion, String forgeGroup) {
VersionInfo(Map<String, ?> arguments) {
this((String) arguments.get("forgeVersion"), (String) arguments.get("mcVersion"), (String) arguments.get("mcpVersion"), (String) arguments.get("forgeGroup"));
}
public String mcAndForgeVersion() {
return mcVersion+"-"+forgeVersion;
}
public String mcAndMCPVersion() {
return mcVersion + "-" + mcpVersion;
}
}
@@ -0,0 +1,55 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.loading;
import net.minecraftforge.forgespi.language.MavenVersionAdapter;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.VersionRange;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.function.BiPredicate;
public class VersionSupportMatrix {
private static final HashMap<String, List<ArtifactVersion>> overrideVersions = new HashMap<>();
static {
final ArtifactVersion version = new DefaultArtifactVersion(FMLLoader.versionInfo().mcVersion());
// if (MavenVersionAdapter.createFromVersionSpec("[1.16.4,1.16.5]").containsVersion(version)) {
// // 1.16.4 is Compatible with 1.16.3
// add("languageloader.javafml", "34");
// add("mod.minecraft", "1.16.3");
// add("mod.forge", "34.1.42");
// // 1.16.5 is Compatible with 1.16.4, and thus 1.16.3
// add("languageloader.javafml", "35");
// add("mod.minecraft", "1.16.4");
// add("mod.forge", "35.1.37");
// }
}
private static void add(String key, String value) {
overrideVersions.computeIfAbsent(key, k -> new ArrayList<>()).add(new DefaultArtifactVersion(value));
}
public static <T> boolean testVersionSupportMatrix(VersionRange declaredRange, String lookupId, String type, BiPredicate<String, VersionRange> standardLookup) {
if (standardLookup.test(lookupId, declaredRange)) return true;
List<ArtifactVersion> custom = overrideVersions.get(type +"." +lookupId);
return custom == null ? false : custom.stream().anyMatch(declaredRange::containsVersion);
}
}
@@ -0,0 +1,73 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.loading.log4j;
import net.minecrell.terminalconsole.HighlightErrorConverter;
import net.minecrell.terminalconsole.TerminalConsoleAppender;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.pattern.ConverterKeys;
import org.apache.logging.log4j.core.pattern.HighlightConverter;
import org.apache.logging.log4j.core.pattern.PatternConverter;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.PerformanceSensitive;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A wrapper for {@link HighlightConverter} that auto-disables ANSI when the terminal doesn't support it.
* Ansi support is determined by TerminalConsoleAppender
*/
@Plugin(name = "highlightForge", category = PatternConverter.CATEGORY)
@ConverterKeys("highlightForge")
@PerformanceSensitive("allocation")
public class ForgeHighlight {
protected static final Logger LOGGER = StatusLogger.getLogger();
/**
* Gets a new instance of the {@link HighlightErrorConverter} with the
* specified options.
*
* @param config The current configuration
* @param options The pattern options
* @return The new instance
*/
public static @Nullable HighlightConverter newInstance(Configuration config, String[] options) {
try {
Method method = TerminalConsoleAppender.class.getDeclaredMethod("initializeTerminal");
method.setAccessible(true);
method.invoke(null);
} catch (ReflectiveOperationException e) {
LOGGER.warn("Failed to invoke initializeTerminal on TCA", e);
}
if (!TerminalConsoleAppender.isAnsiSupported() && Arrays.stream(options).noneMatch(s -> s.equals("disableAnsi=true"))) {
List<String> optionList = new ArrayList<>();
optionList.add(options[0]);
optionList.add("disableAnsi=true");
options = optionList.toArray(new String[0]);
}
return HighlightConverter.newInstance(config, options);
}
}
@@ -0,0 +1,67 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.loading.moddiscovery;
import cpw.mods.jarhandling.SecureJar;
import net.minecraftforge.forgespi.locating.IModFile;
import net.minecraftforge.forgespi.locating.IModLocator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static net.minecraftforge.fml.loading.LogMarkers.SCAN;
public abstract class AbstractJarFileLocator implements IModLocator {
private static final Logger LOGGER = LogManager.getLogger();
@Override
public void scanFile(final IModFile file, final Consumer<Path> pathConsumer) {
LOGGER.debug(SCAN,"Scan started: {}", file);
final Function<Path, SecureJar.Status> status = p->file.getSecureJar().verifyPath(p);
try (Stream<Path> files = Files.find(file.getSecureJar().getRootPath(), Integer.MAX_VALUE, (p, a) -> p.getNameCount() > 0 && p.getFileName().toString().endsWith(".class"))) {
file.setSecurityStatus(files.peek(pathConsumer).map(status).reduce((s1, s2)-> SecureJar.Status.values()[Math.min(s1.ordinal(), s2.ordinal())]).orElse(SecureJar.Status.INVALID));
} catch (IOException e) {
e.printStackTrace();
}
LOGGER.debug(SCAN,"Scan finished: {}", file);
}
@Override
public List<IModFile> scanMods() {
return scanCandidates()
.map(mc -> ModFile.newFMLInstance(this, mc))
.collect(Collectors.toList());
}
public abstract Stream<Path> scanCandidates();
@Override
public boolean isValid(final IModFile modFile) {
return true;
}
}
Loaded 100 of 2060 files, more files were not shown because too many files have changed in this diff. Show more