Compare commits

...
322 Commits
Author SHA1 Message Date
40a174310d Initial port to 1.18
Co-authored-by: David Quintana <[email protected]>
Co-authored-by: SizableShrimp <[email protected]>
2021-11-30 17:42:18 +00:00
LexManos be0a6819ac Bump version for final RB of 1.17's lifecycle. Move on to 1.18! 2021-11-30 08:54:18 -08:00
LexManos 82a7ee1416 Fix LiquidBlock's fluid field not being redirected to the supplier getFluid. Closes #7922 2021-11-30 08:43:37 -08:00
sciwhiz12 b4feee8046 [1.17.x Omnibus] Fix typos and javadocs across code base (#8144) 2021-11-25 13:09:56 -08:00
AterAnimAvis df8954869a Fix /forge setdimension command arguments not parsing/suggesting correctly. 2021-11-25 12:27:26 -08:00
uSkizzik 8a552136a2 Fix Spectating Part Entity (MC-46486) (#8206) 2021-11-25 12:17:15 -08:00
Paint_Ninja 34ec627457 Use HttpClient for VersionChecker (#8148) 2021-11-25 12:14:11 -08:00
Harley O'Connor 28dd76ebbf Changed control flow of post mouse events to allow listening to events handled by vanilla. (#8133) 2021-11-25 12:03:05 -08:00
sciwhiz12 b639bcb5c7 Deprecate durability bar methods in Item extension (#8214)
To retain compatibility with existing mods, the vanilla methods redirect
to the extension methods for now.

Users should now use and override the vanilla methods as directed in
the javadocs of the now-deprecated methods, as the extension methods
will be removed in the future.

Fixes #8201
2021-11-25 20:09:40 +01:00
sciwhiz12 7538cf5501 Reorder image tooltip component to match vanilla (#8213)
Fixes #8212
2021-11-25 19:58:55 +01:00
Sekwah 1112819fc8 Fix render pipeline lighting issue with small cubes (#8158)
This will also allow other mods which need to calculate small normalised vectors to be able to use the default classes without needing to write their own, while not effecting any side effects created by how the base game uses this function.
2021-11-25 11:14:12 +01:00
ChampionAsh5357 cdd38270e9 Fixes infinite loop when dismounting in EntityMountEvent (#8114) 2021-11-24 18:03:12 -08:00
ichttt 20e309c339 Fix onChunkUnloaded not gettting called correctly (#8103) 2021-11-24 13:53:51 -08:00
Take Weiland 5f87bde00e Fix death message for tamed animals not having proper cause of death. (#8196) 2021-11-23 17:11:03 -08:00
DaemonUmbra a4e574fa6b Fix potential issue with BackgroundScanHandler for users with slow disc IO (#8176) 2021-11-23 17:05:45 -08:00
TelepathicGrunt ec7cb00f86 Make WorldEvent.Load run for Overworld before chunk creation like other dimensions (#8167) 2021-11-23 17:02:23 -08:00
Robert Kämpf ebe375dac0 Deprecate net.minecraftforge.common.util.Constants and inner classes to encourage usage of vanilla constants (#8140) 2021-11-23 16:47:43 -08:00
SuperMartijn642 4a2572d545 [1.17.x] Change expected type of LootTable fields to arrays (#8194)
#8184 reverted some LootTable patches, including the types of fields `f_79023_` and `f_79024_`. However, `ForgeLootTableProvider` still expects a list, however the type of the fields is an array now.
This PR changes the expected type in `ForgeLootTableProvider` to an array as well.
2021-11-21 10:26:31 -08:00
MelanX 55db597baa Apply window resizing to all gui layers (#8207) 2021-11-21 13:28:56 +01:00
Minecraftschurli c24d05173f [1.17.x] make ScrollPanel better usable by modders (#8179) 2021-11-20 16:54:12 +01:00
LexManos d711982a1c Update installer to 2.1.+ so we don't have to bump it in the future. 2021-11-12 17:25:37 -08:00
ChampionAsh5357 8a38416e0f Remove Old LootPool Patches (#8184) 2021-11-10 12:17:53 -08:00
ichttt a784bdb0d0 Remove the remnants of the selective reload listener (#8072) 2021-11-09 14:30:45 -08:00
Minecraftschurli dc9a7f6ad5 Fix the hopefully last issue with GAMELIBRARY loading (#8162) 2021-11-09 14:27:17 -08:00
uSkizzik 417798f2eb Fix part entities not working at all (#8177) 2021-11-09 14:16:40 -08:00
Dennis C 394e76eed3 Pass IModelData through IForgeBakedModel#getModelData() before asking the BakedModel for the particle texture (#8106) 2021-10-31 12:26:32 +01:00
Dennis C 9e476551be Fix blocks with flammable material catching fire from lava when they are marked as non-flammable (#8160) 2021-10-20 12:15:43 -07:00
Alex O'Neill 1dc421e6a4 Add BiomeDictionary#hasType(String) (#8157) 2021-10-20 12:10:13 -07:00
Silver_David e431bb1caa Add "forge:enchanting_materials" tag in place of Lapis in the Enchanting Table (#8149) 2021-10-20 12:08:53 -07:00
ChampionAsh5357 8bd517ca91 Fix Breaking waterlogged blocks occasionally displays air for a frame Closes #7253 (#8128) 2021-10-20 12:01:48 -07:00
Dennis C 69ddf58600 Add accessor to an unmodifiable view of the fullPots map in FlowerPotBlock (#8108) 2021-10-20 11:57:33 -07:00
ChampionAsh5357 1e040c9f1f Fix Behavior With Unknown Items in Recipes (#8105) 2021-10-20 11:56:23 -07:00
LexManos 11bdf592c8 Disable jenkins cache system until a functional system is in place. 2021-10-17 16:28:45 -07:00
Take Weiland f4a827ab01 Fix another crash with new tooltip events (#8155)
* Fix another crash with new tooltip events
* Add ItemStack context to ghost recipe tooltip events
* Expand Tooltip Event test mod to add a screen to test all tooltip render methods
2021-10-18 00:22:42 +02:00
ChampionAsh5357 827ca83cfd Add entity source to PotionAddedEvent (#8147) 2021-10-14 20:13:18 -07:00
Dipo e9f8acd191 Add helper methods to generate blockstate and models for button, pressure plate, sign to BlockStateProvider/ModelProvider (#8139) 2021-10-14 20:11:20 -07:00
Max Becker febfd5ab62 Fix Entity#onAddedToWorld not being called for non-player entities server-side (#8134) 2021-10-14 20:09:16 -07:00
Alex O'Neill 4ca2a8058f Add ATs for world generation extensibility, focusing on NoiseBasedChunkGenerator, NoiseSampler, NoiseBasedAquifer, and Beardifier (#8087) 2021-10-14 20:07:08 -07:00
Unbekannt1998 4acafcccfd Make AdvancementProvider extensible by modders (#8120) 2021-10-14 20:00:18 -07:00
LexManos 937b719e24 Skip loading jars with neither a manifest, nore a mods.toml.
Deprecate helper functions related to ModFile/Metadata.
Mark ModFileFactory as to be removed from our usage.
It may be useful for other loaders, but introduces a weird level of indirection that makes things a pain.
If there are consumers of this API please leave feedback before the next major mc version so we can be sure to provide something useful.
2021-10-13 12:51:16 -07:00
LexManos 2b5bfd923c Fix mods with both a manifest and a mods.toml have mismatched module names. 2021-10-13 12:19:22 -07:00
Take Weiland 249aaa5806 Fix missing toolTip methods in Screen (#8154) 2021-10-13 14:02:31 +02:00
Take Weiland 46f57e6a9a Fix render tooltip render patch (#8153) 2021-10-13 10:06:25 +02:00
LexManos cfd79130de Attempt to fix non-mods.toml jar files. Closes #8136 #8146 #8152
Make jenkins copy gradle cache to address concurrent build issues.
2021-10-12 18:49:14 -07:00
Take Weiland 6a25c99097 Tooltip event rewrite (#8038)
Redesigns the tooltip events, and adds a feature where mods can register factories for ClientTooltipComponents, which are used for custom rendering in tooltips. The old events are maintained for binary compatibility.
2021-10-11 20:37:14 +02:00
Dennis C 95be0d87d9 Add ForgeSpawnEggItem to lazily handle EntityTypes (#8044) 2021-10-07 23:50:18 -07:00
Dennis C 6125ec3bc8 Reimplement IForgeBlockEntity#onLoad() hook (#7946) 2021-10-07 13:31:56 -07:00
gigaherz 9944a8252a Implement GUI Stacking feature. (#8130)
You can now use `mc.pushGuiLayer` and `mc.popGuiLayer` to manage the layers.
mc.setScreen behaves such that if called with a non-null screen it replaces the entire stack, and if called with null it closes the entire stack.
2021-10-04 19:15:56 -07:00
gigaherz fd544dd414 Add ability for people to add custom pack finders (RepositorySources) (#8121)
Added AddPackFindersEvent which lets you add additional resource/data pack sources to the game.
Added PathResourcePack as a utility to allow easy providing of a subfolder in a mod as a resource pack.
2021-10-04 15:10:05 -07:00
Take Weiland c00777e6ea Added EntityEvent.EnteringSection event to replace EnteringChunk event. (#8078) 2021-10-04 14:43:07 -07:00
OneLemonyBoi b2cea78006 Prevent Block/Entity data side leak on integrated servers by copying custom data before writing. #8111 2021-10-04 12:40:58 -07:00
sciwhiz12 79272361f0 Re-implement linear filtering text render types (#8052)
* Re-implement linear filtering text render types

Implements and closes #7996
2021-10-03 20:05:19 +02:00
percivalalb fe4be54774 Fix breaking block particles not respecting IModelData (#8065)
The sprite used for the block particles needs updating after the constructor otherwise it defaults to the texture sprite returned from passing ModelData.INSTANCE to get IForgeBakedModel#getParticleIcon. Calling updateSprite fetches the real IModelData instance for that blockstate/pos and sets the texture to the desired one
2021-10-03 20:03:28 +02:00
Sydney eecb8cc783 Fix Signs breaking with custom WoodTypes (#8132) 2021-10-03 20:00:07 +02:00
LexManos 5e2e404828 Bump SJH version. Closes #8127
Attempt addressing loading libraries during dev time, and bump SPI version introducing GAMELIBRARY type. #7976 #7957 #8090
2021-10-01 13:21:00 -07:00
LexManos 96303f6570 Capability rework to get rid of @CapabilityInject and use CapabilityToken as the identifier, deprecated old system for removal in 1.18. (#8116) 2021-09-30 22:54:23 -07:00
OneLemonyBoi 166feefc02 Fix pet death message being sent when pet death event is canceled. (#8110) 2021-09-27 12:59:06 -07:00
Rikka0_0小六花 cd67762bee [1.17.x] implements canConnectRedstone(), Redstone dust now defers to the blockstate for determining connectivity (#8014) 2021-09-27 12:26:17 -07:00
sciwhiz12 347a0b3c0d Prevent call to Item#initializeClient when in datagen (#8097)
When running under data-generation, the Minecraft singleton is unavailable
even though the operating env is under the CLIENT dist. Adding this check
prevents crashes from devs unaware of this, as most uses of
IItemRenderProperties (usually for a custom BEWLR) make use of the
Minecraft singleton and therefore will cause NPEs if not guarded against.

A similar thing happens in MobEffect and Block.
2021-09-24 23:10:34 +02:00
sciwhiz12 be1698bb15 Move ItemStack#forgeInit call earlier to allow earlier capability queries (#8096) 2021-09-19 16:35:55 -07:00
sciwhiz12 a3e9d7a397 Remove incorrect FallingBlock patch (#8092)
The patch accidentally replaces the minimum build height (set by the
dimension via e.g. datapacks) with 0, causing falling blocks placed
below Y level 0 to never fall.

Fixes #8091
2021-09-18 19:42:30 -07:00
sciwhiz12 b2dbe9de51 Fix inverted hooks for PermissionsChangedEvent (#8089)
Because IEventBus#post returns true on cancellation and the patched-in
hooks inverts the return of the ForgeHooks method, if the player
whose permission level is being changed is online and the event is not
cancelled, the permission change _is_ cancelled.

The fix is inverting the patched-in hooks and the default return value
of the ForgeHooks method, so that the permission change is cancelled
only if the player is online, the event is fired, and the event is cancelled.

Fixes #8088
2021-09-18 14:58:27 -07:00
Marc Hermans a31adc2823 Add the missing patch for ItemStack for last build. (#8085) 2021-09-17 13:26:05 -07:00
Marc Hermans 30a33f5c3e Support Lazy capabilities on itemstacks, for better ItemStack copy performance. (#7945) 2021-09-17 11:23:12 -07:00
gigaherz b01a217f45 Fix EntityJoinWorldEvent not firing as expected: (#8033)
- Fix entities loaded from disk not getting the event.
- Fix vehicles with passengers getting the event twice.
2021-09-16 17:11:04 -07:00
sciwhiz12 69136fce19 Re-add patch to release buffer in custom payload packet (#8042) 2021-09-16 16:54:25 -07:00
noeppi_noeppi ee21224fff Propagate all arguments passed to the server start scripts to the game (#8060) 2021-09-16 16:52:55 -07:00
ichttt 804f390064 Remove old Log4j thread cache invalidation (#8068) 2021-09-16 16:37:16 -07:00
LexManos ca2023fa80 Fix pick-block for items that map to multiple blocks. Closes #8080 2021-09-15 12:09:03 -07:00
gigaherz 4e562664f4 Update nashorn to 15.3, which fixes crashing when run on Java 17.
Please note that due to https://bugs.mojang.com/browse/MCL-18306, the vanilla launcher will not let you use Java 17 yet without workarounds.
2021-09-15 01:54:08 +02:00
SizableShrimp c8d3ad1d1c Add mixin full release to install list. (#8076) 2021-09-11 22:20:40 -07:00
sciwhiz12 b7379953d5 Add new tool action for shield blocking, replacing IForgeItem#isShield (#8055) 2021-09-08 13:14:47 -07:00
sciwhiz12 9d7f5dd32a Add workaround for pairs of ' being stripped (#8050)
Fixes #7396, where if a translated string with balanced pairs of single
quote characters passes through ForgeI18n, the quotes are stripped
because of ExtendedMessageFormat. This is most notable in languages
where `'` is used frequently, like Canadian French from the bug report.

Note that unbalanced pairs cause an IllegalArgumentException in
ExtendedMessageFormat, which means the message is not affected.
2021-09-08 11:36:00 -07:00
sciwhiz12 049ed79e7b Re-add missing patch for IForgeItem#getEquipmentSlot (#8041) 2021-09-08 11:20:12 -07:00
Mysticdrew 675bf8bde2 Added PlayerPermissionChangedEvent(#8023) 2021-09-08 10:39:27 -07:00
DavidQF555 8dc58ad469 Changed Monster Requirement to Mob in RangedBowAttackGoal (#7960) 2021-09-08 10:22:28 -07:00
noeppi_noeppi 827c963d7e Add shebang to run.sh in server files (#8058) 2021-09-02 14:23:53 -07:00
LexManos 2ac616b293 Fix incorrect parameter being sent to AbstractContainerScreen#getSlotColor. 2021-09-02 10:45:01 -07:00
sciwhiz12 dcfbc08504 Patch ModSorter to include forge mod in forgeAndMC list (#8043) 2021-09-01 07:26:29 -07:00
Sara Freimer 19f470ee8c Fix GuiUtils#drawContinuousTexturedBox making assumptions about what shader is currently active, and fix buttons and header not showing on LoadingErrorScreen (#8022) 2021-08-31 17:51:42 +02:00
iTitus a96d078a7a Fix ScrollPanel render calls and usage (#8012) 2021-08-31 16:57:08 +02:00
sciwhiz12 b375da6962 Fix all layers of ItemLayerModel being fullbright (#8039)
Fixes #8007
2021-08-31 11:33:27 +02:00
Cyborgmas d17f10d80c Cleanup Tag Loading, this migrates thins to more of a vanilla style. (#7898) 2021-08-30 14:58:30 -07:00
cech12 a336e443f7 Add Shears ToolActions (#7997)
Make shear interactions extend to subclasses
Add Shears actions for beehive harvesting, pumpkin carving and trip wire disarming
2021-08-30 13:42:37 -07:00
SizableShrimp c5a1c90366 Fix broken fmlonly installer and promote it to page gen (#8029)
Update gradle wrapper to 7.2
2021-08-27 02:03:40 -07:00
Cyborgmas 95c0aa1e98 Minor resource pack related fixes (#7884) 2021-08-23 10:52:17 -07:00
LexManos 559b801cc4 Fix misaligned patch causing monsters to not spawn in nether fortresses correctly. 2021-08-21 18:30:13 -07:00
Take Weiland aa97ddad8b Add RegisterCapabilitiesEvent (#8021) 2021-08-20 12:38:43 -07:00
Commoble d612dc3a6d Move static ITEM_TIER_ORDERING_JSON resourcelocation declaration from anonymous class into outer class to work around eclipse compiler error. (#8018) 2021-08-19 14:31:05 -07:00
SizableShrimp 9165d4c3a1 Fix entities not spawning in structures (#8020)
This affects swamp huts, pillager outposts, ocean monuments, and nether fortresses
2021-08-18 22:44:26 -07:00
Commoble 12d0f96fc2 Add support for forge's "remove" list to tag datagenerators (#7911) 2021-08-18 13:49:29 -07:00
Sirttas bec9d6f534 Add hook to allow items to customize the attack sweep range. (#7981) 2021-08-18 13:05:19 -07:00
Jonathan Coates 892c3669e0 Track the active mod within DeferredWorkQueue (#7973) 2021-08-18 12:46:33 -07:00
StrikerRocker (Tharik Sherief) ce13efbac9 Allow to check spawner block entity in events (#7941) 2021-08-18 02:15:57 -07:00
Cyborgmas 1018b077dc Remove neutral mob patches as the bug was fixed upstream. (#8001) 2021-08-17 22:02:38 -07:00
malte0811 9746db5129 Ensure that all render targets in a PostChain use the same format (#7978)
closes #6995
2021-08-15 16:18:34 +02:00
SizableShrimp c4de1f33ba Fix update checker to use runtime minecraft version (#8000) 2021-08-12 01:44:29 -07:00
vemerion a8a4623d24 Correct incorrect arguments for render hand event (#7987) 2021-08-10 18:53:14 -07:00
David Quintana 10b51f257f Redesign the tool system to rely on the new vanilla tags. (#7970)
Changed:
- ToolType is replaced with ToolAction, which can selectively represent which actions are supported by an item.
- Added a canPerformAction method to query ToolActions.
- Renamed canHarvestBlock to isCorrectToolForDrops to match vanilla.
- Added TierSortingRegistry, which can be used to add custom tiers and supports sorting between vanilla or with other mods.

How to use:

For the breaking system there's 2 methods:
- getDestroySpeed decides if an item *can* mine the block fast. Override if you have multiple tags or your item isn't a DiggerItem.
- isCorrectToolForDrops decides if an item will get drops. Returning false will also slow down mining, regardless of getDestroySpeed. Override if you have type-dependant tiers or your item isn't a DiggerItem.

For the tier system mods can just call `TierSortingRegistry.registerTier(tier, "name", List.of(lesser tiers), List.of(better tiers));` to register their tiers.
There's helper methods to query tiers such as TierSortingRegsitry.isCorrectTierForDrops.

The ToolActions solve 2 problems:
1. distinguishing which kind of digger an item can be
2. querying if the item can perform specific secondary actions.
Any item can override `canPerformAction` to customize which actions it performs.
2021-08-10 15:45:08 -07:00
LexManos 52d7df06da Fixed reference to registryAccess in dimension fix, and marked for removal in next MC version. Closes #7961 2021-08-10 13:10:50 -07:00
LexManos fcc819584a Bump BootStrapLauncher, and make sure Capability providers call parent revive. 2021-08-10 00:11:20 -07:00
Sirttas 4721d4c461 Fix custom ingredients not being read correctly over the network. (#7980) 2021-08-09 12:09:24 -07:00
Silver_David dbdc345d4a Add a OnDatapackSyncEvent, useful as a notification for modders to send extra data to the client (#7912) 2021-08-06 10:18:12 -07:00
Choonster TheMage 14c6fc3388 Add access transformer to make Features.Decorators class public (#7974) 2021-08-06 09:42:27 -07:00
LexManos 33419ed5b1 Fix NullPointerException in DetercorRailBlock patch. 2021-08-04 01:43:38 -07:00
LexManos 9ec1e24dc5 Remove entity.remove(keepData) functions because Mojang changed entity removal mechanics.
If a modder wishes to use the capabilities from a invalid entity. They must manually call reviveCaps/invalidateCaps themselves.
2021-08-04 01:08:04 -07:00
LexManos 06804675be Add forceSystemNanoTime config option to the client.
Normally glfwGetTime is used, but in some cases it may have performance issues.
2021-08-04 01:05:02 -07:00
Johannes Jäger 2f43f9910d Rename potion registry fields to match the mojang names (#7939) 2021-08-02 15:32:14 -07:00
bl4ckscor3 ea9a72af85 Fix patch issue that removed SimpleWaterloggedBlock from BaseRailBlock (#7937) 2021-08-02 14:58:06 -07:00
Striker Rocker 9a92363e15 Fix EntityInteractSpecific Event not being fired in server (#7936) 2021-08-02 14:34:42 -07:00
ChampionAsh5357 94389d0efd Add BlockEntityRenderer registering to RegisterRenderers (#7975) 2021-08-02 01:00:16 +02:00
DaemonUmbra 9080886c1a Fix installer issue with spaces in paths. (#7972) 2021-07-31 22:02:41 -07:00
Alex O'Neill 13ca55f34d Remove unused config entries. (#7954) 2021-07-30 17:43:45 -07:00
Alex O'Neill 5dbea18e30 Re-add call to Ingredient#invalidateAll() (#7953) 2021-07-30 17:42:52 -07:00
DaemonUmbra 30cfd848d8 Remove Generic from ProjectileImpactEvent (#7959)
Generification of this event was half-done and has been aborted, leaving the generic parameter in place just creates confusion and crashes
2021-07-29 19:10:35 -07:00
gigaherz 80d08dbf3a Introduce RegisterShadersEvent to register shaders with the proper timing (runs every client resource reload).
Fix ShaderInstance to allow resourcelocations with namespaces as input.
Fix shader parsing to respect resource domains.
Fix ForgeRenderTypes to use the right shader in each situation.
Add custom forge shader for unlit translucent entity rendering, equivalent to the vanilla entity translucent shader.
2021-07-30 01:48:20 +02:00
SizableShrimp 7d4c238165 Fix userdev mod deps on the classpath (#7919) 2021-07-27 22:43:36 -07:00
iTitus 0ea9401d90 Fix typo in FluidBlockWrapper (#7931) 2021-07-26 15:22:37 -07:00
LexManos 4bdfd8674d Fix rounding related errors with small entity pathfinding. Closes #7730 2021-07-26 14:24:24 -07:00
eerussianguy 3e9e0a6447 Add modder-friendly way to edit the boat model / texture in custom boats (#7897) 2021-07-26 10:54:51 +02:00
Commoble 76da41dd46 Fix EntityRendererEventsTest crashing dedicated server when running forge_test_server in forgedev (#7930) 2021-07-25 22:48:28 +02:00
gigaherz 6ddf56ef15 Added RegisterClientReloadListenersEvent which lets you register reload listeners with appropriate timing.
Added new entity rendering events.
- EntityRenderersEvent.RegisterLayerDefinitions: Used to register layer definitions for entity models.
- EntityRenderersEvent.RegisterRenderers: Used to register entity renderers.
- EntityRenderersEvent.AddLayers: Called during resource reload after all renderers have been constructed and it's safe to add layers.
Removed RenderingRegistry, which is now not necessary.
Removed a few unused things.
Fixes #7920
2021-07-25 12:06:36 +02:00
SuperMartijn642 eeec737188 Pass the 'includeName' flag to the ItemTossEvent (#7894) 2021-07-24 16:52:19 +02:00
Cyborgmas 119ac8f4ab remove old direct GL call (#7907) 2021-07-24 16:45:11 +02:00
Cyborgmas bdf0d9cf22 1.17 Fix InitGuiEvent (#7906) 2021-07-24 16:40:51 +02:00
SuperMartijn642 bd58ced0e4 Expose RenderStateShard inner classes (#7895)
In 1.17, all of the inner classes of `RenderStateShard` (`RenderStateShard.OverlayStateShard`, `RenderStateShard.WriteMaskStateShard`, etc.) have been changed to protected. These classes are needed however to create new `RenderType.CompositeRenderType`'s using `RenderType.CompositeState.CompositeStateBuilder`.
Since these are protected inner classes, their constructors also can't be directly be obtained using `ObfuscationReflectionHelper`.

Currently, any mod using custom `RenderType`'s will have to either:
- add their own access transformer for the inner classes, or
- extend `RenderStateShard` to access `RenderStateShard`'s inner classes, and extend `RenderType` to access `RenderType.CompositeRenderType`

This PR changes the visibility of `RenderStateShard`'s inner classes to public in Forge's `accesstransformer.cfg`.
2021-07-24 16:39:00 +02:00
Cyborgmas 5af6649435 added back attribute patches (#7886) 2021-07-24 16:30:21 +02:00
LexManos 695e1fbb94 Bump SecureJarHandler, and fix life cycle event's deferred work being on the incorrect thread/boot classloader. 2021-07-23 17:25:47 -07:00
LexManos b027a92dd2 Bump SecureJarHandler to fix package meta issue. Closes #7881
Fix version.json having duplicate libraries.
2021-07-22 14:52:17 -07:00
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
2153 changed files with 55940 additions and 46218 deletions

No files matched your search

+9 -10
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/
@@ -32,6 +37,7 @@ src/generated/resources/.cache/
#Patch rejects
/patches-/
*.patch.rej
/projects/*/rejects/
# FML changelog
changelog.txt
@@ -39,10 +45,3 @@ changelog.txt
*.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
+30 -8
View File
@@ -6,8 +6,8 @@ pipeline {
}
agent {
docker {
image 'gradle:jdk8'
args '-v forgegc:/home/gradle/.gradle/'
image 'gradle:7-jdk16'
//args '-v forgegc:/home/gradle/.gradle_cache/'
}
}
environment {
@@ -34,11 +34,23 @@ pipeline {
)
}
}
/*
stage('pull_cache') {
steps {
sh 'cp -r /home/gradle/.gradle_cache/jdks/ /home/gradle/.gradle/jdks/'
sh 'cp -r /home/gradle/.gradle_cache/wrapper/ /home/gradle/.gradle/wrapper/'
sh 'cp -r /home/gradle/.gradle_cache/caches/ /home/gradle/.gradle/caches/'
}
}
*/
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()
env.FMLONLY_VERSION = sh(returnStdout: true, script: './gradlew :fmlonly:properties -q | grep "^version:" | cut -d" " -f2').trim()
}
}
}
@@ -59,15 +71,23 @@ 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
build job: 'filegenerator', parameters: [string(name: 'COMMAND', value: "promote net.minecraftforge:fmlonly ${env.FMLONLY_VERSION} 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 +98,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
+975 -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,22 +1,21 @@
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 = []
@@ -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,74 @@
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 = []
def libs = [:]
getArtifacts(project, project.configurations.installer, false).each { key, lib -> libs[key] = lib }
getArtifacts(project, project.configurations.moduleonly, false).each { key, lib -> libs[key] = lib }
packedDependencies.get().collect{ project.rootProject.tasks.findByPath(it) }.forEach {
def path = Util.getMavenPath(it)
def key = Util.getMavenDep(it)
libs[key] = [
name: key,
downloads: [
artifact: [
path: path,
url: "https://maven.minecraftforge.net/${path}",
sha1: it.archiveFile.get().asFile.sha1(),
size: it.archiveFile.get().asFile.length()
]
]
]
}
libs.each { key, lib -> json.libraries.add(lib) }
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() }
-4
View File
@@ -15,8 +15,4 @@ Contributor License Agreement
- You grant Forge a license to use your code contributed to the primary codebase (everything **not** under patches) in Forge, under the LGPLv2.1 license.
- You assign copyright ownership of your contributions to the patches codebase (everything under patches) to Forge, where it will be licensed under the LGPLv2.1 license.
Additionally, while 1.9.4 is being maintained, you will be asked to acknowledge these two additional clauses.
- You grant Forge a license to use your code contributed to the primary codebase (everything **not** under patches) in Forge, under the MinecraftForge license.
- You grant assign copyright ownership of your contributions to the patches codebase (everything under patches) to Forge, where it will be licensed under the MinecraftForge license.
"Forge" is Forge Development LLC, a legally incorporated entity in Oregon, USA.
+5 -5
View File
@@ -2,16 +2,16 @@
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.3-&query=$.promos["1.16.3-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.3-&query=$.promos["1.16.3-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.17.1-&query=$.promos["1.17.1-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.17.1-&query=$.promos["1.17.1-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!
| Version | Support |
| Version | Support |
| ------------- | ------------- |
| 1.16.x | Active |
| 1.15.x | LTS |
| 1.17.x | Active |
| 1.16.x | LTS |
* [Download]
* [Forum]
+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,35 @@
package net.minecraftforge.fml;
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
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,29 +21,26 @@ 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;
/**
* Utility for running code on the main launch thread at the next available
* opportunity. There is no guaranteed order that work from various mods will be
* run, but your own work will be run sequentially.
* <p>
* <strong>Use of this class after startup is not possible.</strong> At that
* point, {@link IThreadListener} should be used instead.
* point, {@code ReentrantBlockableEventLoop} should be used instead.
* <p>
* Exceptions from tasks will be handled gracefully, causing a mod loading
* error. Tasks that take egregiously long times to run will be logged.
@@ -52,32 +49,39 @@ 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) {
executor.execute(() -> {
Stopwatch timer = Stopwatch.createStarted();
ti.task.run();
ModLoadingContext.get().setActiveContainer(ti.owner);
try {
ti.task.run();
} finally {
ModLoadingContext.get().setActiveContainer(null);
}
timer.stop();
if (timer.elapsed(TimeUnit.SECONDS) >= 1) {
LOGGER.warn(LOADING, "Mod '{}' took {} to run a deferred task.", ti.owner.getModId(), timer);
@@ -85,36 +89,13 @@ public class DeferredWorkQueue
});
}
public CompletableFuture<Void> enqueueWork(final IModInfo modInfo, final Runnable work) {
public CompletableFuture<Void> enqueueWork(final ModContainer modInfo, final Runnable work) {
return CompletableFuture.runAsync(work, r->tasks.add(new TaskInfo(modInfo, r)));
}
public <T> CompletableFuture<T> enqueueWork(final IModInfo modInfo, final Supplier<T> work) {
public <T> CompletableFuture<T> enqueueWork(final ModContainer modInfo, final Supplier<T> work) {
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(ModContainer 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
@@ -46,7 +46,7 @@ public final class DistExecutor
private DistExecutor() {}
/**
* Run the callable in the supplier only on the specified {@link Side}.
* Run the callable in the supplier only on the specified {@link Dist}.
* This method is NOT sided-safe and special care needs to be taken in code using this method that implicit class
* loading is not triggered by the Callable.
*
@@ -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 impl or writing to disk
* The predicate tests the version from a remote instance or save for acceptability (Boolean is true for impl, false for local save)
* and returns true if the version is compatible.
*
* <p>Return {@code net.minecraftforge.impl.impl.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 impl 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
* </p>
* <pre>{@code
* 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>
*
* <p>
* Examples: A client only mod
* </p>
* <pre>{@code
* 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>
*
*/
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,35 +111,32 @@ public abstract class ModContainer
public static <T extends Event & IModBusEvent> CompletableFuture<Void> buildTransitionHandler(
final ModContainer target,
final ModLoadingStage.EventGenerator<T> eventGenerator,
final IModStateTransition.EventGenerator<T> eventGenerator,
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> stateChangeHandler,
final Executor executor) {
return CompletableFuture
.runAsync(() -> {
ModLoadingContext.get().setActiveContainer(target, target.contextExtension.get());
ModLoadingContext.get().setActiveContainer(target);
target.activityMap.getOrDefault(target.modLoadingStage, ()->{}).run();
target.acceptEvent(eventGenerator.apply(target));
}, executor)
.whenComplete((mc, exception) -> {
target.modLoadingStage = stateChangeHandler.apply(target.modLoadingStage, exception);
ModLoadingContext.get().setActiveContainer(null, null);
ModLoadingContext.get().setActiveContainer(null);
});
}
/**
* @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);
}
@@ -138,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,18 +74,18 @@ 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 String.format("%-50.50s|%-30.30s|%-30.30s|%-20.20s|%-10.10s|%s", mf.getFileName(),
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(),
@@ -111,18 +114,18 @@ 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 IModStateTransition.EventGenerator<T> eventGenerator,
final BiFunction<ModLoadingStage, Throwable, ModLoadingStage> stateChange) {
return executor -> gather(
this.mods.stream()
@@ -185,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;
}
@@ -205,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,31 +20,25 @@
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;
import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.Executor;
@@ -58,7 +52,7 @@ import static net.minecraftforge.fml.Logging.LOADING;
/**
* Loads mods.
*
* Dispatch cycle is seen in {@link #loadMods()} and {@link #finishMods()}
* Dispatch cycle is seen in {@code #loadMods()} and {@code #finishMods()}
*
* Overall sequence for loadMods is:
* <dl>
@@ -66,28 +60,28 @@ import static net.minecraftforge.fml.Logging.LOADING;
* <dd>Constructs the mod instance. Mods can typically setup basic environment such as Event listeners
* and Configuration specifications here.</dd>
* <dt>Automated dispatches</dt>
* <dd>Dispatches automated elements : {@link net.minecraftforge.fml.common.Mod.EventBusSubscriber},
* {@link net.minecraftforge.event.RegistryEvent}, {@link net.minecraftforge.common.capabilities.CapabilityInject}
* <dd>Dispatches automated elements : {@code net.minecraftforge.fml.common.Mod.EventBusSubscriber},
* {@code net.minecraftforge.event.RegistryEvent}, {@code net.minecraftforge.common.capabilities.CapabilityInject}
* and others</dd>
* <dt>CONFIG_LOAD</dt>
* <dd>Dispatches ConfigLoadEvent to mods</dd>
* <dt>COMMON_SETUP</dt>
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent} to mods</dd>
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent} to mods</dd>
* <dt>SIDED_SETUP</dt>
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent} or
* {@link net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent} to mods</dd>
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent} or
* {@code net.minecraftforge.fml.event.lifecycle.FMLDedicatedServerSetupEvent} to mods</dd>
* </dl>
*
* Overall sequence for finishMods is:
* <dl>
* <dt>ENQUEUE_IMC</dt>
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent} to mods,
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent} to mods,
* for enqueuing {@link InterModComms} messages for other mods to receive subsequently</dd>
* <dt>PROCESS_IMC</dt>
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.InterModProcessEvent} to mods,
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.InterModProcessEvent} to mods,
* for processing {@link InterModComms} messages received from other mods prior to this event</dd>
* <dt>COMPLETE</dt>
* <dd>Dispatches {@link net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent} to mods,
* <dd>Dispatches {@code net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent} to mods,
* and completes the mod loading sequence.</dd>
* </dl>
*/
@@ -95,38 +89,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());
FMLLoader.getLoadingModList()
.getModFiles().stream().filter(ModFileInfo::missingLicense) //Search for files with missing licenses
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);
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.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() {
@@ -158,11 +151,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));
@@ -171,11 +160,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());
@@ -183,61 +172,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("Adding custom tag types"));
GameData.setCustomTagTypesFromRegistries();
statusConsumer.ifPresent(c->c.accept("Populating registries"));
dispatchAndHandleError(ModLoadingStage.LOAD_REGISTRIES, syncExecutor, parallelExecutor, periodicTask);
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);
}
@@ -258,18 +231,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()) {
@@ -279,21 +254,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();
}
}
@@ -336,4 +313,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;
@@ -36,9 +36,9 @@ public class ModLoadingContext
private ModContainer activeContainer;
public void setActiveContainer(final ModContainer container, final Object languageExtension) {
public void setActiveContainer(final ModContainer container) {
this.activeContainer = container;
this.languageExtension = languageExtension;
this.languageExtension = container == null ? null : container.contextExtension.get();
}
public ModContainer getActiveContainer() {
@@ -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
@@ -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,37 @@
package net.minecraftforge.fml;
import com.google.common.graph.GraphBuilder;
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
@@ -19,21 +19,24 @@
package net.minecraftforge.fml;
import com.google.common.io.ByteStreams;
import com.google.gson.Gson;
import net.minecraftforge.fml.loading.FMLConfig;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.fml.loading.FMLLoader;
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.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -41,8 +44,8 @@ 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 java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import static net.minecraftforge.fml.VersionChecker.Status.*;
@@ -50,6 +53,7 @@ public class VersionChecker
{
private static final Logger LOGGER = LogManager.getLogger();
private static final int MAX_HTTP_REDIRECTS = Integer.getInteger("http.maxRedirects", 20);
private static final int HTTP_TIMEOUT_SECS = Integer.getInteger("http.timeoutSecs", 15);
public enum Status
{
@@ -103,30 +107,14 @@ 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()
{
new Thread("Forge Version Check")
{
private HttpClient client;
@Override
public void run()
{
@@ -136,39 +124,46 @@ public class VersionChecker
return;
}
client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(HTTP_TIMEOUT_SECS)).build();
gatherMods().forEach(this::process);
}
/**
* Opens stream for given URL while following redirects
* Returns the response body as a String for the given URL while following redirects
*/
private InputStream openUrlStream(URL url) throws IOException
{
private String openUrlString(URL url) throws IOException, URISyntaxException, InterruptedException {
URL currentUrl = url;
for (int redirects = 0; redirects < MAX_HTTP_REDIRECTS; redirects++)
{
URLConnection c = currentUrl.openConnection();
if (c instanceof HttpURLConnection)
var request = HttpRequest.newBuilder()
.uri(currentUrl.toURI())
.timeout(Duration.ofSeconds(HTTP_TIMEOUT_SECS))
.setHeader("Accept-Encoding", "gzip")
.GET()
.build();
final HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
int responseCode = response.statusCode();
if (responseCode >= 300 && responseCode <= 399)
{
HttpURLConnection huc = (HttpURLConnection) c;
huc.setInstanceFollowRedirects(false);
int responseCode = huc.getResponseCode();
if (responseCode >= 300 && responseCode <= 399)
{
try
{
String loc = huc.getHeaderField("Location");
currentUrl = new URL(currentUrl, loc);
continue;
}
finally
{
huc.disconnect();
}
}
String newLocation = response.headers().firstValue("Location")
.orElseThrow(() -> new IOException("Got a 3xx response code but Location header was null while trying to fetch " + url));
currentUrl = new URL(currentUrl, newLocation);
continue;
}
return c.getInputStream();
final boolean isGzipEncoded = response.headers().firstValue("Content-Encoding").orElse("").equals("gzip");
final String bodyStr;
try (InputStream inStream = isGzipEncoded ? new GZIPInputStream(response.body()) : response.body())
{
try (var bufferedReader = new BufferedReader(new InputStreamReader(inStream)))
{
bodyStr = bufferedReader.lines().collect(Collectors.joining("\n"));
}
}
return bodyStr;
}
throw new IOException("Too many redirects while trying to fetch " + url);
}
@@ -181,12 +176,11 @@ public class VersionChecker
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);
String data = new String(ByteStreams.toByteArray(con), StandardCharsets.UTF_8);
con.close();
String data = openUrlString(url);
LOGGER.debug("[{}] Received version check data:\n{}", mod.getModId(), data);
@@ -197,7 +191,7 @@ public class VersionChecker
Map<String, String> promos = (Map<String, String>)json.get("promos");
display_url = (String)json.get("homepage");
String mcVersion = MCPVersion.getMCVersion();
var mcVersion = FMLLoader.versionInfo().mcVersion();
String rec = promos.get(mcVersion + "-recommended");
String lat = promos.get(mcVersion + "-latest");
ComparableVersion current = new ComparableVersion(mod.getVersion().toString());
@@ -278,9 +272,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));
}
}
}
@@ -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
}
@@ -0,0 +1,134 @@
/*
* 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.common.asm;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.EnumSet;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
/**
* Implements getType() in CapabilityToken subclasses.
*
* Using the class's signature to determine the generic type of TypeToken, and then implements getType() using that value.
* <pre>
* Example:
*
* <code>new CapabilityToken&lt;String>(){}</code>
* Has the signature <code>"CapabilityToken&lt;Ljava/lang/String;>"</code>
*
* Implements the method:
* <code>public String getType() {
* return "java/lang/String";
* }</code>
* </pre>
*/
public class CapabilityTokenSubclass implements ILaunchPluginService {
private final String FUNC_NAME = "getType";
private final String FUNC_DESC = "()Ljava/lang/String;";
private final String CAP_INJECT = "net/minecraftforge/common/capabilities/CapabilityToken"; //Don't directly reference this to prevent class loading.
@Override
public String name() {
return "capability_token_subclass";
}
private static final EnumSet<Phase> YAY = EnumSet.of(Phase.AFTER);
private static final EnumSet<Phase> NAY = EnumSet.noneOf(Phase.class);
@Override
public EnumSet<Phase> handlesClass(Type classType, boolean isEmpty)
{
return isEmpty ? NAY : YAY;
}
@Override
public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason)
{
if (CAP_INJECT.equals(classNode.name))
{
for (MethodNode mtd : classNode.methods)
{
if (FUNC_NAME.equals(mtd.name) && FUNC_DESC.equals(mtd.desc))
{
mtd.access &= ~Opcodes.ACC_FINAL; // We have it final in code so people don't override it, cuz that'd be stupid, and make our transformer more complicated.
}
}
return ComputeFlags.SIMPLE_REWRITE;
}
else if (CAP_INJECT.equals(classNode.superName))
{
Holder cls = new Holder();
SignatureReader reader = new SignatureReader(classNode.signature); // Having a node version of this would probably be useful.
reader.accept(new SignatureVisitor(Opcodes.ASM9)
{
Deque<String> stack = new ArrayDeque<>();
@Override
public void visitClassType(final String name)
{
stack.push(name);
}
@Override
public void visitInnerClassType(final String name)
{
stack.push(stack.pop() + '$' + name);
}
@Override
public void visitEnd()
{
var val = stack.pop();
if (!stack.isEmpty() && CAP_INJECT.equals(stack.peek()))
cls.value = val;
}
});
if (cls.value == null)
throw new IllegalStateException("Could not find signature for CapabilityToken on " + classNode.name + " from " + classNode.signature);
var mtd = classNode.visitMethod(Opcodes.ACC_PUBLIC, FUNC_NAME, FUNC_DESC, null, new String[0]);
mtd.visitLdcInsn(cls.value);
mtd.visitInsn(Opcodes.ARETURN);
mtd.visitEnd();
return ComputeFlags.COMPUTE_MAXS;
}
else
{
return ComputeFlags.NO_REWRITE;
}
}
private static class Holder {
String value;
}
}
@@ -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,9 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.asm;
package net.minecraftforge.fml.common.asm;
import java.nio.file.Path;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -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,9 +17,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.asm;
package net.minecraftforge.fml.common.asm;
import java.nio.file.Path;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;
@@ -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
@@ -29,8 +29,6 @@ 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;
@@ -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,16 +21,15 @@ 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;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.Objects;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
@@ -50,11 +49,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
@@ -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,28 @@
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 net.minecraftforge.accesstransformer.service.AccessTransformerService;
import net.minecraftforge.api.distmarker.Dist;
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
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.ModValidator;
import net.minecraftforge.accesstransformer.service.AccessTransformerService;
import net.minecraftforge.api.distmarker.Dist;
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 +58,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 +79,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 +110,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,62 +139,56 @@ 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)
static void setupLaunchHandler(final IEnvironment environment, final Map<String, Object> arguments)
{
final String launchTarget = environment.getProperty(IEnvironment.Keys.LAUNCHTARGET.get()).orElse("MISSING");
arguments.put("launchTarget", launchTarget);
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 +204,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 +219,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 +230,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 +243,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");
}
@@ -304,6 +260,14 @@ public class FMLLoader
}
public static boolean isSecureJarEnabled() {
return Launcher.INSTANCE.environment().getProperty(IEnvironment.Keys.SECURED_JARS_ENABLED.get()).orElse(false);
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,35 +19,27 @@
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.modlauncher.api.*;
import joptsimple.ArgumentAcceptingOptionSpec;
import joptsimple.OptionSpecBuilder;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
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.Collection;
import java.util.Arrays;
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;
import java.util.stream.Collectors;
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 +59,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()
{
@@ -80,7 +78,7 @@ public class FMLServiceProvider implements ITransformationService
LOGGER.debug(CORE, "Loading configuration");
FMLConfig.load();
LOGGER.debug(CORE, "Preparing ModFile");
environment.computePropertyIfAbsent(Environment.Keys.MODFILEFACTORY.get(), k->ModFile.buildFactory());
environment.computePropertyIfAbsent(Environment.Keys.MODFILEFACTORY.get(), k->ModFile::new);
arguments = new HashMap<>();
arguments.put("modLists", modListsArgumentList);
arguments.put("mods", modsArgumentList);
@@ -97,28 +95,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 +140,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;
@@ -30,11 +32,7 @@ import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.VersionRange;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -49,13 +47,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 +68,6 @@ public class LanguageLoadingProvider
}
private static class ModLanguageWrapper {
private final IModLanguageProvider modLanguageProvider;
private final ArtifactVersion version;
@@ -92,26 +88,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 +106,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 +131,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 +151,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
@@ -22,54 +22,25 @@ package net.minecraftforge.fml.loading;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
public class LibraryFinder {
private static final Logger LOGGER = LogManager.getLogger();
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;
}
public static Path findJarPathFor(final String className, final String jarName) {
final URL resource = LibraryFinder.class.getClassLoader().getResource(className);
return findJarPathFor(className, jarName, resource);
}
public static Path findJarPathFor(final String resourceName, final String jarName, final URL resource) {
try {
Path path;
final URI uri = resource.toURI();
if (uri.getRawSchemeSpecificPart().contains("!")) {
path = Paths.get(new URI(uri.getRawSchemeSpecificPart().split("!")[0]));
} else {
path = Paths.get(new URI("file://"+uri.getRawSchemeSpecificPart().substring(0, uri.getRawSchemeSpecificPart().length()-resourceName.length())));
}
LOGGER.debug(CORE, "Found JAR {} at path {}", jarName, path.toString());
return path;
} catch (NullPointerException | URISyntaxException e) {
LOGGER.fatal(CORE, "Failed to find JAR for class {} - {}", resourceName, jarName);
throw new RuntimeException("Unable to locate "+resourceName+" - "+jarName, e);
}
}
static Path getForgeLibraryPath(final String mcVersion, final String forgeVersion, final String forgeGroup) {
Path forgePath = findLibsPath().resolve(MavenCoordinateResolver.get(forgeGroup, "forge", "", "universal", mcVersion+"-"+forgeVersion));
LOGGER.debug(CORE, "Found forge path {} is {}", forgePath, pathStatus(forgePath));
LOGGER.debug(LogMarkers.CORE, "Found forge path {} is {}", forgePath, pathStatus(forgePath));
return forgePath;
}
@@ -81,9 +52,16 @@ public class LibraryFinder {
Path srgMcPath = findLibsPath().resolve(MavenCoordinateResolver.get("net.minecraft", type, "", "srg", mcVersion+"-"+mcpVersion));
Path mcExtrasPath = findLibsPath().resolve(MavenCoordinateResolver.get("net.minecraft", type, "", "extra", mcVersion+"-"+mcpVersion));
Path patchedBinariesPath = findLibsPath().resolve(MavenCoordinateResolver.get(forgeGroup, "forge", "", type, mcVersion+"-"+forgeVersion));
LOGGER.debug(CORE,"SRG MC at {} is {}", srgMcPath.toString(), pathStatus(srgMcPath));
LOGGER.debug(CORE,"MC Extras at {} is {}", mcExtrasPath.toString(), pathStatus(mcExtrasPath));
LOGGER.debug(CORE,"Forge patches at {} is {}", patchedBinariesPath.toString(), pathStatus(patchedBinariesPath));
LOGGER.debug(LogMarkers.CORE,"SRG MC at {} is {}", srgMcPath.toString(), pathStatus(srgMcPath));
LOGGER.debug(LogMarkers.CORE,"MC Extras at {} is {}", mcExtrasPath.toString(), pathStatus(mcExtrasPath));
LOGGER.debug(LogMarkers.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));
}
}
@@ -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;
@@ -33,8 +14,6 @@ import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import static net.minecraftforge.fml.loading.LogMarkers.CORE;
public class MCPNamingService implements INameMappingService {
private static final Logger LOGGER = LogManager.getLogger();
private HashMap<String, String> methods;
@@ -47,7 +26,7 @@ public class MCPNamingService implements INameMappingService {
@Override
public String mappingVersion() {
return "1234";
return "1234"; //TODO: Minecraft Version?
}
@Override
@@ -77,7 +56,7 @@ public class MCPNamingService implements INameMappingService {
HashMap<String,String> tmpmethods = new HashMap<>(1000);
loadMappings("methods.csv", tmpmethods::put);
methods = tmpmethods;
LOGGER.debug(CORE, "Loaded {} method mappings from methods.csv", methods.size());
LOGGER.debug(LogMarkers.CORE, "Loaded {} method mappings from methods.csv", methods.size());
}
return methods.getOrDefault(origin, origin);
}
@@ -87,25 +66,20 @@ public class MCPNamingService implements INameMappingService {
HashMap<String,String> tmpfields = new HashMap<>(1000);
loadMappings("fields.csv", tmpfields::put);
fields = tmpfields;
LOGGER.debug(CORE, "Loaded {} field mappings from fields.csv", fields.size());
LOGGER.debug(LogMarkers.CORE, "Loaded {} field mappings from fields.csv", fields.size());
}
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)
{
LOGGER.error(CORE, "Error reading mappings", e1);
} catch (IOException e1) {
LOGGER.error(LogMarkers.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;
@@ -33,36 +34,25 @@ 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 +64,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
@@ -70,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
@@ -0,0 +1,250 @@
/*
* 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 com.google.common.graph.GraphBuilder;
import com.google.common.graph.MutableGraph;
import net.minecraftforge.forgespi.language.IModFileInfo;
import net.minecraftforge.forgespi.language.IModInfo;
import net.minecraftforge.fml.loading.EarlyLoadingException.ExceptionData;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
import net.minecraftforge.fml.loading.toposort.CyclePresentException;
import net.minecraftforge.fml.loading.toposort.TopologicalSort;
import net.minecraftforge.forgespi.locating.IModFile;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
import static net.minecraftforge.fml.loading.LogMarkers.LOADING;
public class ModSorter
{
private static final Logger LOGGER = LogManager.getLogger();
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, final List<ExceptionData> errors)
{
final ModSorter ms = new ModSorter(mods);
try {
ms.buildUniqueList();
} 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);
}
}
@SuppressWarnings("UnstableApiUsage")
private void sort()
{
// 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(ModFile::getModFileInfo)
.filter(ModFileInfo.class::isInstance)
.collect(toMap(Function.identity(), e -> counter.incrementAndGet()));
infos.keySet().forEach(i -> graph.addNode((ModFileInfo) i));
modFiles.stream()
.map(ModFile::getModInfos)
.<IModInfo>mapMulti(Iterable::forEach)
.map(IModInfo::getDependencies)
.<IModInfo.ModVersion>mapMulti(Iterable::forEach)
.forEach(dep -> addDependency(graph, dep));
final List<ModFileInfo> sorted;
try
{
sorted = TopologicalSort.topologicalSort(graph, Comparator.comparing(infos::get));
}
catch (CyclePresentException e)
{
Set<Set<ModFileInfo>> cycles = e.getCycles();
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))
.toList();
throw new EarlyLoadingException("Sorting error", e, dataList);
}
this.sortedList = sorted.stream()
.map(ModFileInfo::getMods)
.<IModInfo>mapMulti(Iterable::forEach)
.map(ModInfo.class::cast)
.collect(toList());
this.modFiles = sorted.stream()
.map(ModFileInfo::getFile)
.collect(toList());
}
@SuppressWarnings("UnstableApiUsage")
private void addDependency(MutableGraph<ModFileInfo> topoGraph, IModInfo.ModVersion dep)
{
final ModFileInfo self = (ModFileInfo)dep.getOwner().getOwningFile();
final ModInfo targetModInfo = modIdNameLookup.get(dep.getModId());
// soft dep that doesn't exist. Just return. No edge required.
if (targetModInfo == null) return;
final ModFileInfo target = targetModInfo.getOwningFile();
if (self == target)
return; // in case a jar has two mods that have dependencies between
switch (dep.getOrdering()) {
case BEFORE -> topoGraph.putEdge(self, target);
case AFTER -> topoGraph.putEdge(target, self);
}
}
private void buildUniqueList()
{
// Collect mod files by module name. This will be used for deduping purposes
final Map<String, List<IModFile>> modFilesByFirstId = modFiles.stream()
.collect(groupingBy(mf -> mf.getModFileInfo().moduleName()));
// 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?");
// TODO: remove this hardcoding and make it more flexible
var forge = modFilesByFirstId.get("forge");
if (forge != null && !forge.isEmpty())
forgeAndMC.add((ModFile) forge.get(0)); // Silently ignore if Forge isn't present
// 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(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(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<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, Objects.toString(dm))).toList();
throw new EarlyLoadingException("Duplicate mods found", null, duplicateModErrors);
}
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) {
List<IModFile> modInfoList = fullList.getValue();
if (modInfoList.size() > 1) {
LOGGER.debug("Found {} mods for first modid {}, selecting most recent based on version data", modInfoList.size(), fullList.getKey());
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 Map.entry(fullList.getKey(), modInfoList.get(0));
}
private List<EarlyLoadingException.ExceptionData> verifyDependencyVersions()
{
final var modVersions = modFiles.stream()
.map(ModFile::getModInfos)
.<IModInfo>mapMulti(Iterable::forEach)
.collect(toMap(IModInfo::getModId, IModInfo::getVersion));
final var modVersionDependencies = modFiles.stream()
.map(ModFile::getModInfos)
.<IModInfo>mapMulti(Iterable::forEach)
.collect(groupingBy(Function.identity(), flatMapping(e -> e.getDependencies().stream(), toList())));
final var modRequirements = modVersionDependencies.values().stream()
.<IModInfo.ModVersion>mapMulti(Iterable::forEach)
.filter(mv -> mv.getSide().isCorrectSide())
.collect(toSet());
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()) {
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"))))
.toList();
}
return Collections.emptyList();
}
private boolean modVersionNotContained(final IModInfo.ModVersion mv, final Map<String, ArtifactVersion> modVersions)
{
return !(VersionSupportMatrix.testVersionSupportMatrix(mv.getVersionRange(), mv.getModId(), "mod", (modId, range) -> modVersions.containsKey(modId) &&
(range.containsVersion(modVersions.get(modId)) || modVersions.get(modId).toString().equals("0.0NONE"))));
}
}
@@ -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);
}
}
@@ -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,54 @@
/*
* 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 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);
}
}
@@ -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
@@ -29,8 +29,8 @@ 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 javax.annotation.Nullable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
Loaded 100 of 2153 files, more files were not shown because too many files have changed in this diff. Show more