<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://forge.gemwire.uk/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ferri+Arnus</id>
	<title>Forge Community Wiki - User contributions [en-gb]</title>
	<link rel="self" type="application/atom+xml" href="https://forge.gemwire.uk/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ferri+Arnus"/>
	<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/wiki/Special:Contributions/Ferri_Arnus"/>
	<updated>2026-06-02T05:43:22Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.35.0</generator>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=SimpleChannel&amp;diff=3409</id>
		<title>SimpleChannel</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=SimpleChannel&amp;diff=3409"/>
		<updated>2023-08-28T21:21:11Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* Registering Packets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;SimpleChannel is the name given to the packet system that revolves around the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;SimpleChannel&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; class. Using this system is by far the easiest way to send custom data between clients and the server.&lt;br /&gt;
&lt;br /&gt;
== Getting Started ==&lt;br /&gt;
&lt;br /&gt;
First you need to create your &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;SimpleChannel&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; object. We recommend that you do this in a separate class, possibly something like &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;ModidPacketHandler&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. Create your &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;SimpleChannel&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; as a static field in this class, like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
private static final String PROTOCOL_VERSION = &amp;quot;1&amp;quot;;&lt;br /&gt;
public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(&lt;br /&gt;
    new ResourceLocation(&amp;quot;mymodid&amp;quot;, &amp;quot;main&amp;quot;),&lt;br /&gt;
    () -&amp;gt; PROTOCOL_VERSION,&lt;br /&gt;
    PROTOCOL_VERSION::equals,&lt;br /&gt;
    PROTOCOL_VERSION::equals&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first argument is a name for the channel. The second argument is a &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;Supplier&amp;lt;String&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; returning the current network protocol version. The third and fourth arguments respectively are &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;Predicate&amp;lt;String&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; checking whether an incoming connection protocol version is network-compatible with the client or server, respectively.&lt;br /&gt;
Here, we simply compare with the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;PROTOCOL_VERSION&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; field directly, meaning that the client and server &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;PROTOCOL_VERSION&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;s must always match or FML will deny login.&lt;br /&gt;
&lt;br /&gt;
== Protocol Versions ==&lt;br /&gt;
If your mod does not require the other side to have a specific network channel, or to be a Forge instance at all, you should take care that you properly define your version compatibility checkers (the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;Predicate&amp;lt;String&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; parameters) to handle additional &amp;quot;meta-versions&amp;quot; (defined in &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;NetworkRegistry&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;) that can be received by the version checker. These are:&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;ABSENT&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; - if this channel is missing on the other endpoint. Note that in this case, the endpoint is still a Forge endpoint, and may have other mods.&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;ACCEPTVANILLA&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; - if the endpoint is a vanilla (or non-Forge) endpoint.&lt;br /&gt;
&lt;br /&gt;
Returning &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;false&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; for both means that this channel must be present on the other endpoint. If you just copy the code above, this is what it does. Note that these values are also used during the list ping compatibility check, which is responsible for showing the green check / red cross in the multiplayer server select screen.&lt;br /&gt;
&lt;br /&gt;
== Registering Packets ==&lt;br /&gt;
&lt;br /&gt;
Next, we must declare the types of messages that we would like to send and receive. This is done using the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;INSTANCE.registerMessage&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; method, which takes 5 parameters.&lt;br /&gt;
&lt;br /&gt;
* The first parameter is the discriminator for the packet. This is a per-channel unique ID for the packet. We recommend you use a local variable to hold the ID, and then call registerMessage using &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;id++&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. This will guarantee 100% unique IDs.&lt;br /&gt;
* The second parameter is the actual packet class &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;MSG&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
* The third parameter is a &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;BiConsumer&amp;lt;MSG, FriendlyByteBuf&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; responsible for encoding the message into the provided &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;FriendlyByteBuf&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* The fourth parameter is a &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;Function&amp;lt;FriendlyByteBuf, MSG&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; responsible for decoding the message from the provided &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;FriendlyByteBuf&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
* The final parameter is a &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;BiConsumer&amp;lt;MSG, Supplier&amp;lt;NetworkEvent.Context&amp;gt;&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; responsible for handling the message itself&lt;br /&gt;
&lt;br /&gt;
The last three parameters can be method references to either static or instance methods in Java. Remember that an instance method &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;MSG.encode(FriendlyByteBuf)&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; still satisfies &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;BiConsumer&amp;lt;MSG, FriendlyByteBuf&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;MSG&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; simply becomes the implicit first argument.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
class MessagePacket {&lt;br /&gt;
   public void encoder(FriendlyByteBuf buffer) {&lt;br /&gt;
      // Write to buffer&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   public static MessagePacket decoder(FriendlyByteBuf buffer) {&lt;br /&gt;
      // Create packet from buffer data&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   public void messageConsumer(Supplier&amp;lt;NetworkEvent.Context&amp;gt; ctx) {&lt;br /&gt;
      // Handle message&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Original direct registration syntax&lt;br /&gt;
INSTANCE.registerMessage(id, MessagePacket.class,&lt;br /&gt;
   MessagePacket::encoder,&lt;br /&gt;
   MessagePacket::decoder,&lt;br /&gt;
   MessagePacket::messageConsumer);&lt;br /&gt;
   // Consumer here must use enqueueWork and setPacketHandled&lt;br /&gt;
&lt;br /&gt;
// New builder-based definition&lt;br /&gt;
INSTANCE.messageBuilder(MessagePacket.class, id)&lt;br /&gt;
   .encoder(MessagePacket::encoder)&lt;br /&gt;
   .decoder(MessagePacket::decoder)&lt;br /&gt;
   .consumerMainThread(MessagePacket::messageConsumer)&lt;br /&gt;
   .add();&lt;br /&gt;
// You can use consumerMainThread or consumerNetworkThread.&lt;br /&gt;
// If you use consumerMainThread, the builder will take care of the enqueueWork and setPacketHandled.&lt;br /&gt;
// With consumerNetworkThread, you can return a value instead of calling setPacketHandled.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Handling Packets ==&lt;br /&gt;
&lt;br /&gt;
There are a couple things to highlight in a packet handler. A packet handler has both the message object and the network context available to it. The context allows access to the player that sent the packet (if on the server), and a way to enqueue threadsafe work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static void handle(MyMessage msg, Supplier&amp;lt;NetworkEvent.Context&amp;gt; ctx) {&lt;br /&gt;
    ctx.get().enqueueWork(() -&amp;gt; {&lt;br /&gt;
        // Work that needs to be threadsafe (most work)&lt;br /&gt;
        ServerPlayer sender = ctx.get().getSender(); // the client that sent this packet&lt;br /&gt;
        // do stuff&lt;br /&gt;
    });&lt;br /&gt;
    ctx.get().setPacketHandled(true);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Packets sent from the server to the client should be handled in another class and wrapped via &amp;lt;code&amp;gt;DistExecutor#unsafeRunWhenOn&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
// In Packet class&lt;br /&gt;
public static void handle(MyClientMessage msg, Supplier&amp;lt;NetworkEvent.Context&amp;gt; ctx) {&lt;br /&gt;
    ctx.get().enqueueWork(() -&amp;gt;&lt;br /&gt;
        // Make sure it's only executed on the physical client&lt;br /&gt;
        DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -&amp;gt; () -&amp;gt; ClientPacketHandlerClass.handlePacket(msg, ctx))&lt;br /&gt;
    );&lt;br /&gt;
    ctx.get().setPacketHandled(true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// In ClientPacketHandlerClass&lt;br /&gt;
public static void handlePacket(MyClientMessage msg, Supplier&amp;lt;NetworkEvent.Context&amp;gt; ctx) {&lt;br /&gt;
    // Do stuff&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the presence of &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#setPacketHandled&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, which used to tell the network system that the packet has successfully completed handling.&lt;br /&gt;
&lt;br /&gt;
=== Common Packet Handling Pitfalls ===&lt;br /&gt;
&lt;br /&gt;
{{Colored box|title=Know that packets are by default handled on the network thread.|content=&lt;br /&gt;
That means that your handler can ''not'' interact with most game objects directly.&lt;br /&gt;
Forge provides a convenient way to make your code execute on the main thread through the supplied &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;NetworkEvent$Context&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;.&lt;br /&gt;
Simply call &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;NetworkEvent$Context#enqueueWork(Runnable)&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, which will call the given &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;Runnable&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; on the main thread at the next opportunity.}}&lt;br /&gt;
&lt;br /&gt;
{{Colored box|title=Be defensive when handling packets on the server.|content=&lt;br /&gt;
A client could attempt to exploit the packet handling by sending unexpected data.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
A common problem is vulnerability to &amp;lt;code&amp;gt;arbitrary chunk generation&amp;lt;/code&amp;gt;. This typically happens when the server is trusting a block position sent by a client to access blocks and block entities. When accessing blocks and block entities in unloaded areas of the level, the server will either generate or load this area from disk, then promply write it to disk. This can be exploited to cause &amp;lt;code&amp;gt;catastrophic damage&amp;lt;/code&amp;gt; to a server's performance and storage space without leaving a trace.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To avoid this problem, a general rule of thumb is to only access blocks and block entities if &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;Level#hasChunkAt&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; is true.}}&lt;br /&gt;
&lt;br /&gt;
{{Colored box|title=Register encoders on the physical client, as well as the physical server.|content=&lt;br /&gt;
If you only register an encoder for a clientbound packet on the physical server, your mod will likely crash or present unintended behaviour in single-player worlds. ''Forge will happily send packets that have no encoder defined, '''without a warning or error message!''''' They will be encoded as a 256-long byte buffer filled only with null bytes, by default.&lt;br /&gt;
&amp;lt;br&amp;gt;}}&lt;br /&gt;
&lt;br /&gt;
== Sending Packets ==&lt;br /&gt;
&lt;br /&gt;
=== Sending to the Server ===&lt;br /&gt;
&lt;br /&gt;
There is but one way to send a packet to the server. This is because there is only ever *one* server the client can be connected to at once. To do so, we must again use that &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;SimpleChannel&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; that was defined earlier. Simply call &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;INSTANCE.sendToServer(new MyMessage())&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. The message will be sent to the handler for its type, if one exists.&lt;br /&gt;
&lt;br /&gt;
=== Sending to Clients ===&lt;br /&gt;
&lt;br /&gt;
Packets can be sent directly to a client using the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;SimpleChannel&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;HANDLER.sendTo(MSG, serverPlayer.connection.getConnection(), NetworkDirection.PLAY_TO_CLIENT)&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. However, this can be quite inconvenient. Forge has some convenience functions that can be used:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
// Sending to one player&lt;br /&gt;
INSTANCE.send(PacketDistributor.PLAYER.with(serverPlayer), new MyMessage());&lt;br /&gt;
&lt;br /&gt;
// Send to all players tracking this level chunk&lt;br /&gt;
INSTANCE.send(PacketDistributor.TRACKING_CHUNK.with(levelChunk), new MyMessage());&lt;br /&gt;
&lt;br /&gt;
// Sending to all connected players&lt;br /&gt;
INSTANCE.send(PacketDistributor.ALL.noArg(), new MyMessage());&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are additional &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;PacketDistributor&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; types available, check the documentation on the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;PacketDistributor&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; class for more details.&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Networking_with_Entities&amp;diff=3124</id>
		<title>Networking with Entities</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Networking_with_Entities&amp;diff=3124"/>
		<updated>2022-02-21T21:49:38Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* IEntityAdditionalSpawnData */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to regular network messages, there are various other systems provided to handle synchronizing entity data.&lt;br /&gt;
&lt;br /&gt;
== Spawn Data ==&lt;br /&gt;
&lt;br /&gt;
In general, the spawning of modded entities is handled seperately, by Forge.&lt;br /&gt;
&lt;br /&gt;
{{Colored box|title=Info|content=This means that simply extending a vanilla entity class may not inherit all its behaviour here. You may need to implement certain vanilla behaviours yourself.}}&lt;br /&gt;
&lt;br /&gt;
You can add extra data to the spawn packet Forge sends by implementing the following interface.&lt;br /&gt;
&lt;br /&gt;
===IEntityAdditionalSpawnData===&lt;br /&gt;
If your entity has data that is needed on the client, but doesn't change over time, then it can be added to the entity spawn packet using this interface. &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;writeSpawnData()&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;readSpawnData()&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; control how the data should be en/decoded to/from the network buffer. Also override &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;getAddEntityPacket()&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; to return &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;NetworkHooks.getEntitySpawningPacket(...)&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; for the data to be send.&lt;br /&gt;
&lt;br /&gt;
== Dynamic Data ==&lt;br /&gt;
&lt;br /&gt;
=== Data Parameters ===&lt;br /&gt;
&lt;br /&gt;
This is the main vanilla system for synchronizing entity data from the server to the client. As such, a number of vanilla examples are available to refer to.&lt;br /&gt;
&lt;br /&gt;
Firstly you need a &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;EntityDataAccessor&amp;lt;T&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; for the data you wish to keep synchronized. This should be stored as a static final field in your entity class, obtained by calling &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;SynchedEntityData.defineId()&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and passing the entity class and a serializer for that type of data. The available serializer implementations can be found as static constants within the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;EntityDataSerializers&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
{{Colored box|title=Alert|content=You should '''only''' create data parameters for your own entities, ''within that entity's class''. Adding parameters to entities you do not control can cause the IDs used to send that data over the network to become desynchronized, causing difficult to debug crashes.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then, override &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;Entity#defineSynchedData()&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; and call &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;this.entityData.define(...)&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; for each of your data parameters, passing the parameter and an initial value to use. Remember to always call &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;super.defineSynchedData()&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; first!&lt;br /&gt;
&lt;br /&gt;
You can then get and set these values via your entity's &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;entityData&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; instance. Changes made will be synchronized to the client automatically.&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2678</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2678"/>
		<updated>2021-07-16T14:45:10Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
==Preperation==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; method you would then first call the method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&lt;br /&gt;
===The LootPool Builder===&lt;br /&gt;
This is where you actually make a loottable. You start with an empty &amp;lt;code&amp;gt;LootPool&amp;lt;/code&amp;gt; and add the necessary attributes to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;.name&amp;lt;/code&amp;gt; is used for the pool name.&lt;br /&gt;
* &amp;lt;code&amp;gt;.setRolls&amp;lt;/code&amp;gt; is used for the amount.&lt;br /&gt;
* &amp;lt;code&amp;gt;.add&amp;lt;/code&amp;gt; is used to add an &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt;. You can have multiple entries.&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt; defines what item is returned, and which functions and/or conditions are applied (see [https://minecraft.fandom.com/wiki/Loot_table Loot table] for the vanilla functions and conditions).&lt;br /&gt;
* &amp;lt;code&amp;gt;.lootTableItem&amp;lt;/code&amp;gt; is used to define which item is returned.&lt;br /&gt;
* &amp;lt;code&amp;gt;.apply&amp;lt;/code&amp;gt; is used to apply a function or condition. These themselves can have multiple operations.&lt;br /&gt;
&lt;br /&gt;
After all attributes have been added the &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; can be used to make a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt; of the proper &amp;lt;code&amp;gt;LootParameterSets&amp;lt;/code&amp;gt;. This builder can then be added to an entry in the &amp;lt;code&amp;gt;lootTables&amp;lt;/code&amp;gt; map made in the previous section (you should do this in the overwritten abstract method).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
    .name(...)&lt;br /&gt;
    .setRolls(...)&lt;br /&gt;
    .add(ItemLootEntry.lootTableItem(...)&lt;br /&gt;
        .apply(Function1)&lt;br /&gt;
        .apply(Function2&lt;br /&gt;
            .operation(operation1)&lt;br /&gt;
            .operation(operation2))&lt;br /&gt;
    );&lt;br /&gt;
LootTable.lootTable().withPool(builder).setParamSet(...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2677</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2677"/>
		<updated>2021-07-16T14:39:14Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
==Preperation==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; method you would then first call the method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&lt;br /&gt;
===The LootPool Builder===&lt;br /&gt;
This is where you actually make a loottable. You start with an empty &amp;lt;code&amp;gt;LootPool&amp;lt;/code&amp;gt; and add the necessary attributes to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;.name&amp;lt;/code&amp;gt; is used for the pool name.&lt;br /&gt;
* &amp;lt;code&amp;gt;.setRolls&amp;lt;/code&amp;gt; is used for the amount.&lt;br /&gt;
* &amp;lt;code&amp;gt;.add&amp;lt;/code&amp;gt; is used to add an &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt;. You can have multiple entries.&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt; defines what item is returned, and which functions and/or conditions are applied (see [https://minecraft.fandom.com/wiki/Loot_table Loot table] for the vanilla functions and conditions).&lt;br /&gt;
* &amp;lt;code&amp;gt;.lootTableItem&amp;lt;/code&amp;gt; is used to define which item is returned.&lt;br /&gt;
* &amp;lt;code&amp;gt;.apply&amp;lt;/code&amp;gt; is used to apply a function or condition. These themselves can have multiple operations.&lt;br /&gt;
&lt;br /&gt;
After all attributes have been added the &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; can be used to make a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt; of the proper &amp;lt;code&amp;gt;LootParameterSets&amp;lt;/code&amp;gt;. This builder can then be added to the &amp;lt;code&amp;gt;lootTables&amp;lt;/code&amp;gt; map made in the previous section (in the overwritten abstract method).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
    .name(...)&lt;br /&gt;
    .setRolls(...)&lt;br /&gt;
    .add(ItemLootEntry.lootTableItem(...)&lt;br /&gt;
        .apply(Function1)&lt;br /&gt;
        .apply(Function2&lt;br /&gt;
            .operation(operation1)&lt;br /&gt;
            .operation(operation2))&lt;br /&gt;
    );&lt;br /&gt;
LootTable.lootTable().withPool(builder).setParamSet(...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2676</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2676"/>
		<updated>2021-07-16T14:34:50Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
==Preperation==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; method you would then first call the method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&lt;br /&gt;
===The LootPool Builder===&lt;br /&gt;
This is where you actually make a loottable. You start with an empty&amp;lt;code&amp;gt;LootPool&amp;lt;/code&amp;gt;and add the necessary attributes to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;.name&amp;lt;/code&amp;gt; is used for the pool name.&lt;br /&gt;
* &amp;lt;code&amp;gt;.setRolls&amp;lt;/code&amp;gt; is used for the amount.&lt;br /&gt;
* &amp;lt;code&amp;gt;.add&amp;lt;/code&amp;gt; is used to add an &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt; defines what is returned, and which functions and/or conditions are applied (see [https://minecraft.fandom.com/wiki/Loot_table Loot table] for the vanilla functions and conditions).&lt;br /&gt;
* &amp;lt;code&amp;gt;.lootTableItem&amp;lt;/code&amp;gt; is used to define which item is returned.&lt;br /&gt;
* &amp;lt;code&amp;gt;.apply&amp;lt;/code&amp;gt; is used to apply a function or condition&lt;br /&gt;
&lt;br /&gt;
After all attributes have been added the &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; can be used to make a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt; of the proper &amp;lt;code&amp;gt;LootParameterSets&amp;lt;/code&amp;gt;. This builder can then be added to the &amp;lt;code&amp;gt;lootTables&amp;lt;/code&amp;gt; map made in the previous section (in the overwritten abstract method).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(...)&lt;br /&gt;
                .setRolls(...)&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(...)&lt;br /&gt;
                        .apply(Function1)&lt;br /&gt;
                        .apply(Function2&lt;br /&gt;
                                .options(option1)&lt;br /&gt;
                                .options(option2))&lt;br /&gt;
                );&lt;br /&gt;
        LootTable.lootTable().withPool(builder).setParamSet(...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2675</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2675"/>
		<updated>2021-07-16T14:21:22Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
==Preperation==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; method you would then first call the method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&lt;br /&gt;
===The LootPool Builder===&lt;br /&gt;
This is where you actually make a loottable. You start with a an empty&amp;lt;code&amp;gt;LootPool&amp;lt;/code&amp;gt;and add the necessary attributes to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;.name&amp;lt;/code&amp;gt; is used for the pool name.&lt;br /&gt;
* &amp;lt;code&amp;gt;.setRolls&amp;lt;/code&amp;gt; is used for the amount.&lt;br /&gt;
* &amp;lt;code&amp;gt;.add&amp;lt;/code&amp;gt; is used to add an &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt; defines what is returned, and which functions and/or conditions are applied (see [https://minecraft.fandom.com/wiki/Loot_table Loot table] for the vanilla functions and conditions).&lt;br /&gt;
* &amp;lt;code&amp;gt;.lootTableItem&amp;lt;/code&amp;gt; is used to define which item is returned.&lt;br /&gt;
* &amp;lt;code&amp;gt;.apply&amp;lt;/code&amp;gt; is used to apply a function or condition&lt;br /&gt;
&lt;br /&gt;
After all attributes have been added the &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; can be used to make a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt; of the proper &amp;lt;code&amp;gt;LootParameterSets&amp;lt;/code&amp;gt;. This builder can then be added to the &amp;lt;code&amp;gt;lootTables&amp;lt;/code&amp;gt; map made in the previous section (in the overwritten abstract method).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(...)&lt;br /&gt;
                .setRolls(...)&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(...)&lt;br /&gt;
                        .apply(Function1)&lt;br /&gt;
                        .apply(Function2&lt;br /&gt;
                                .options(option1)&lt;br /&gt;
                                .options(option2))&lt;br /&gt;
                );&lt;br /&gt;
        LootTable.lootTable().withPool(builder).setParamSet(...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2674</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2674"/>
		<updated>2021-07-16T14:20:15Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* Preperation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
==Preperation==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; method you would then first call the method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable. You start with a &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; and add the necessary attributes to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;.name&amp;lt;/code&amp;gt; is used for the pool name.&lt;br /&gt;
* &amp;lt;code&amp;gt;.setRolls&amp;lt;/code&amp;gt; is used for the amount.&lt;br /&gt;
* &amp;lt;code&amp;gt;.add&amp;lt;/code&amp;gt; is used to add an &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt; defines what is returned, and which functions and/or conditions are applied (see [https://minecraft.fandom.com/wiki/Loot_table Loot table] for the vanilla functions and conditions).&lt;br /&gt;
* &amp;lt;code&amp;gt;.lootTableItem&amp;lt;/code&amp;gt; is used to define which item is returned.&lt;br /&gt;
* &amp;lt;code&amp;gt;.apply&amp;lt;/code&amp;gt; is used to apply a function or condition&lt;br /&gt;
&lt;br /&gt;
After all attributes have been added the &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; can be used to make a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt; of the proper &amp;lt;code&amp;gt;LootParameterSets&amp;lt;/code&amp;gt;. This builder can then be added to the &amp;lt;code&amp;gt;lootTables&amp;lt;/code&amp;gt; map made in the previous section (in the overwritten abstract method).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(...)&lt;br /&gt;
                .setRolls(...)&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(...)&lt;br /&gt;
                        .apply(Function1)&lt;br /&gt;
                        .apply(Function2&lt;br /&gt;
                                .options(option1)&lt;br /&gt;
                                .options(option2))&lt;br /&gt;
                );&lt;br /&gt;
        LootTable.lootTable().withPool(builder).setParamSet(...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2673</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2673"/>
		<updated>2021-07-16T14:18:51Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* Preperation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
==Preperation==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable. You start with a &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; and add the necessary attributes to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;.name&amp;lt;/code&amp;gt; is used for the pool name.&lt;br /&gt;
* &amp;lt;code&amp;gt;.setRolls&amp;lt;/code&amp;gt; is used for the amount.&lt;br /&gt;
* &amp;lt;code&amp;gt;.add&amp;lt;/code&amp;gt; is used to add an &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt; defines what is returned, and which functions and/or conditions are applied (see [https://minecraft.fandom.com/wiki/Loot_table Loot table] for the vanilla functions and conditions).&lt;br /&gt;
* &amp;lt;code&amp;gt;.lootTableItem&amp;lt;/code&amp;gt; is used to define which item is returned.&lt;br /&gt;
* &amp;lt;code&amp;gt;.apply&amp;lt;/code&amp;gt; is used to apply a function or condition&lt;br /&gt;
&lt;br /&gt;
After all attributes have been added the &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; can be used to make a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt; of the proper &amp;lt;code&amp;gt;LootParameterSets&amp;lt;/code&amp;gt;. This builder can then be added to the &amp;lt;code&amp;gt;lootTables&amp;lt;/code&amp;gt; map made in the previous section (in the overwritten abstract method).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(...)&lt;br /&gt;
                .setRolls(...)&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(...)&lt;br /&gt;
                        .apply(Function1)&lt;br /&gt;
                        .apply(Function2&lt;br /&gt;
                                .options(option1)&lt;br /&gt;
                                .options(option2))&lt;br /&gt;
                );&lt;br /&gt;
        LootTable.lootTable().withPool(builder).setParamSet(...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2672</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2672"/>
		<updated>2021-07-16T14:17:18Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable. You start with a &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; and add the necessary attributes to it.&lt;br /&gt;
* &amp;lt;code&amp;gt;.name&amp;lt;/code&amp;gt; is used for the pool name.&lt;br /&gt;
* &amp;lt;code&amp;gt;.setRolls&amp;lt;/code&amp;gt; is used for the amount.&lt;br /&gt;
* &amp;lt;code&amp;gt;.add&amp;lt;/code&amp;gt; is used to add an &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;ItemLootEntry&amp;lt;/code&amp;gt; defines what is returned, and which functions and/or conditions are applied (see [https://minecraft.fandom.com/wiki/Loot_table Loot table] for the vanilla functions and conditions).&lt;br /&gt;
* &amp;lt;code&amp;gt;.lootTableItem&amp;lt;/code&amp;gt; is used to define which item is returned.&lt;br /&gt;
* &amp;lt;code&amp;gt;.apply&amp;lt;/code&amp;gt; is used to apply a function or condition&lt;br /&gt;
&lt;br /&gt;
After all attributes have been added the &amp;lt;code&amp;gt;LootPool.Builder&amp;lt;/code&amp;gt; can be used to make a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt; of the proper &amp;lt;code&amp;gt;LootParameterSets&amp;lt;/code&amp;gt;. This builder can then be added to the &amp;lt;code&amp;gt;lootTables&amp;lt;/code&amp;gt; map made in the previous section (in the overwritten abstract method).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(...)&lt;br /&gt;
                .setRolls(...)&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(...)&lt;br /&gt;
                        .apply(Function1)&lt;br /&gt;
                        .apply(Function2&lt;br /&gt;
                                .options(option1)&lt;br /&gt;
                                .options(option2))&lt;br /&gt;
                );&lt;br /&gt;
        LootTable.lootTable().withPool(builder).setParamSet(...);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2671</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2671"/>
		<updated>2021-07-16T13:52:22Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The actual Class for Lootables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The method should return a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt;. This builder can be made by using the &amp;lt;code&amp;gt;LootPool.lootPool()&amp;lt;/code&amp;gt; method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions and/or conditions (see [https://minecraft.fandom.com/wiki/Loot_table LootTables] for possible vanilla funtions and conditions). After having made the builder, you return &amp;lt;code&amp;gt;LootTable.lootTable().withPool(builder)&amp;lt;/code&amp;gt;. An example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents when placed.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: [https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials Full list of his tutorials] and [https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen Lootprovider and other datagen classes]&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2670</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2670"/>
		<updated>2021-07-16T09:52:05Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The method should return a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt;. This builder can be made by using the &amp;lt;code&amp;gt;LootPool.lootPool()&amp;lt;/code&amp;gt; method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions and/or conditions (see [https://minecraft.fandom.com/wiki/Loot_table LootTables] for possible vanilla funtions and conditions). After having made the builder, you return &amp;lt;code&amp;gt;LootTable.lootTable().withPool(builder)&amp;lt;/code&amp;gt;. An example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents when placed.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: [https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials Full list of his tutorials] and [https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen Lootprovider and other datagen classes]&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2669</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2669"/>
		<updated>2021-07-16T09:51:32Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The method should return a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt;. This builder can be made by using the &amp;lt;code&amp;gt;LootPool.lootPool()&amp;lt;/code&amp;gt; method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions and/or conditions (see [https://minecraft.fandom.com/wiki/Loot_table LootTables] for possible vanilla funtions and conditions). After having made the builder, you return &amp;lt;code&amp;gt;LootTable.lootTable().withPool(builder)&amp;lt;/code&amp;gt;. An example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: [https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials Full list of his tutorials] and [https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen Lootprovider and other datagen classes]&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2668</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2668"/>
		<updated>2021-07-16T09:50:52Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The method should return a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt;. This builder can be made by using the &amp;lt;code&amp;gt;LootPool.lootPool()&amp;lt;/code&amp;gt; method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions and/or conditions (see [https://minecraft.fandom.com/wiki/Loot_table LootTables] for possible vanilla funtions and conditions). After having made the builder, you return &amp;lt;code&amp;gt;LootTable.lootTable().withPool(builder)&amp;lt;/code&amp;gt;. A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: [https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials Full list of his tutorials] and [https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen Lootprovider and other datagen classes]&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2667</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2667"/>
		<updated>2021-07-16T09:49:54Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* Preperation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strictly needed.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class which is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt;. This builder can be made by using the &amp;lt;code&amp;gt;LootPool.lootPool()&amp;lt;/code&amp;gt; method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions and/or conditions (see [https://minecraft.fandom.com/wiki/Loot_table LootTables] for possible vanilla funtions and conditions). After having made the builder, you return &amp;lt;code&amp;gt;LootTable.lootTable().withPool(builder)&amp;lt;/code&amp;gt;. A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: [https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials Full list of his tutorials] and [https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen Lootprovider and other datagen classes]&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2666</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2666"/>
		<updated>2021-07-16T09:47:59Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt;. This builder can be made by using the &amp;lt;code&amp;gt;LootPool.lootPool()&amp;lt;/code&amp;gt; method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions and/or conditions (see [https://minecraft.fandom.com/wiki/Loot_table LootTables] for possible vanilla funtions and conditions). After having made the builder, you return &amp;lt;code&amp;gt;LootTable.lootTable().withPool(builder)&amp;lt;/code&amp;gt;. A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: [https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials Full list of his tutorials] and [https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen Lootprovider and other datagen classes]&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2665</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2665"/>
		<updated>2021-07-16T09:41:37Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt;. This builder can be made by using the &amp;lt;code&amp;gt;LootPool.lootPool()&amp;lt;/code&amp;gt; method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions and/or conditions (see https://minecraft.fandom.com/wiki/Loot_table for possible vanilla funtions and conditions). After having made the builder, you return &amp;lt;code&amp;gt;LootTable.lootTable().withPool(builder)&amp;lt;/code&amp;gt;. A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials and https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2664</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2664"/>
		<updated>2021-07-16T09:41:02Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a &amp;lt;code&amp;gt;LootTable.Builder&amp;lt;/code&amp;gt;. This builder can be made by using the &amp;lt;code&amp;gt;LootPool.lootPool()&amp;lt;/code&amp;gt; method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions or conditions (see https://minecraft.fandom.com/wiki/Loot_table for possible vanilla funtions and conditions). After having made the builder, you return &amp;lt;code&amp;gt;LootTable.lootTable().withPool(builder)&amp;lt;/code&amp;gt;. A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials and https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2663</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2663"/>
		<updated>2021-07-16T09:38:37Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The actual Class for Lootables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a LootTable.Builder. This builder can be made by using the LootPool.lootPool() method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions or conditions (see https://minecraft.fandom.com/wiki/Loot_table for possible vanilla funtions and conditions). After having made the builder, you return LootTable.lootTable().withPool(builder). A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder).setParamSet(LootParameterSets.BLOCK);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials and https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2662</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2662"/>
		<updated>2021-07-16T09:35:01Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The actual Class for Lootables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class for blocks. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().setParamSet(LootParameterSets.BLOCK).build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a LootTable.Builder. This builder can be made by using the LootPool.lootPool() method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions or conditions (see https://minecraft.fandom.com/wiki/Loot_table for possible vanilla funtions and conditions). After having made the builder, you return LootTable.lootTable().withPool(builder). A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials and https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2661</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2661"/>
		<updated>2021-07-16T09:33:59Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The LootPool Builder */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().setParamSet(LootParameterSets.BLOCK).build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable (this is an explanation for a block loottable). If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a LootTable.Builder. This builder can be made by using the LootPool.lootPool() method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions or conditions (see https://minecraft.fandom.com/wiki/Loot_table for possible vanilla funtions and conditions). After having made the builder, you return LootTable.lootTable().withPool(builder). A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Thanks and creddits to McJty with his amazing tutorials: https://wiki.mcjty.eu/modding/index.php?title=YouTube-Tutorials and https://github.com/McJty/YouTubeModding14/tree/1.16/src/main/java/com/mcjty/mytutorial/datagen&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2660</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2660"/>
		<updated>2021-07-16T09:28:02Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* Preperation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().setParamSet(LootParameterSets.BLOCK).build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable. If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a LootTable.Builder. This builder can be made by using the LootPool.lootPool() method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions or conditions (see https://minecraft.fandom.com/wiki/Loot_table for possible vanilla funtions and conditions). After having made the builder, you return LootTable.lootTable().withPool(builder). A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2659</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2659"/>
		<updated>2021-07-16T09:22:11Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The actual Class for Lootables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.toJson(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
Here's an example Lootprovider class. The class is abstract and will be extended by the actual lootprovider class. This is however, optional. The class could also be used directly.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().setParamSet(LootParameterSets.BLOCK).build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;Example LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LootTables extends BaseLootTableProvider{&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    protected void addTables() {&lt;br /&gt;
	lootTables.put(BLOCK, LootTable.Builder);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where you actually make a loottable. If you have multiple blocks with similar loottables, making a general method could be a good idea. The Method should return a LootTable.Builder. This builder can be made by using the LootPool.lootPool() method, but you still need to add attributes. You need a name for the pool, the amount you get and also &amp;quot;what&amp;quot; you get. The &amp;quot;what&amp;quot; can modified using functions or conditions (see https://minecraft.fandom.com/wiki/Loot_table for possible vanilla funtions and conditions). After having made the builder, you return LootTable.lootTable().withPool(builder). A example of a &amp;quot;shulkerbox-like&amp;quot; block, copying its name, inventory and &amp;quot;energy&amp;quot; data to the block and restoring its contents.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected LootTable.Builder createTable(String name, Block block) {&lt;br /&gt;
        LootPool.Builder builder = LootPool.lootPool()&lt;br /&gt;
                .name(name)&lt;br /&gt;
                .setRolls(ConstantRange.exactly(1))&lt;br /&gt;
                .add(ItemLootEntry.lootTableItem(block)&lt;br /&gt;
                        .apply(CopyName.copyName(CopyName.Source.BLOCK_ENTITY))&lt;br /&gt;
                        .apply(CopyNbt.copyData(CopyNbt.Source.BLOCK_ENTITY)&lt;br /&gt;
                                .copy(&amp;quot;inv&amp;quot;, &amp;quot;BlockEntityTag.inv&amp;quot;, CopyNbt.Action.REPLACE)&lt;br /&gt;
                                .copy(&amp;quot;energy&amp;quot;, &amp;quot;BlockEntityTag.energy&amp;quot;, CopyNbt.Action.REPLACE))&lt;br /&gt;
                        .apply(SetContents.setContents()&lt;br /&gt;
                                .withEntry(DynamicLootEntry.dynamicEntry(new ResourceLocation(&amp;quot;minecraft&amp;quot;, &amp;quot;contents&amp;quot;))))&lt;br /&gt;
                );&lt;br /&gt;
        return LootTable.lootTable().withPool(builder);&lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2658</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2658"/>
		<updated>2021-07-16T08:54:07Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* The actual Class for Lootables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.toJson(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public abstract class BaseLootTableProvider extends LootTableProvider {&lt;br /&gt;
&lt;br /&gt;
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
    private static final Logger LOGGER = LogManager.getLogger();&lt;br /&gt;
&lt;br /&gt;
    protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
    private final DataGenerator generator;&lt;br /&gt;
&lt;br /&gt;
    public BaseLootTableProvider(DataGenerator dataGeneratorIn) {&lt;br /&gt;
        super(dataGeneratorIn);&lt;br /&gt;
        this.generator = dataGeneratorIn;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected abstract void addTables();&lt;br /&gt;
    &lt;br /&gt;
    @Override&lt;br /&gt;
    public void run(DirectoryCache cache) {&lt;br /&gt;
        addTables();&lt;br /&gt;
&lt;br /&gt;
        Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
        for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : lootTables.entrySet()) {&lt;br /&gt;
            tables.put(entry.getKey().getLootTable(), entry.getValue().setParamSet(LootParameterSets.BLOCK).build());&lt;br /&gt;
        }&lt;br /&gt;
        writeTables(cache, tables);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
        Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
        tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
            Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
            try {&lt;br /&gt;
                IDataProvider.save(GSON, cache, LootTableManager.serialize(lootTable), path);&lt;br /&gt;
            } catch (IOException e) {&lt;br /&gt;
                LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    @Override&lt;br /&gt;
    public String getName() {&lt;br /&gt;
        return &amp;quot;MagicScrolls LootTables&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables&lt;br /&gt;
&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where the magic happens /s.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2657</id>
		<title>Datageneration/Loot Tables</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Datageneration/Loot_Tables&amp;diff=2657"/>
		<updated>2021-07-15T19:15:19Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* Preperation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Under construction}}&lt;br /&gt;
Loot Tables are not so polished like the other Providers. You need need to do some work to get them to a good state.&lt;br /&gt;
&lt;br /&gt;
== Preperation ==&lt;br /&gt;
First you would need a new Class that extend the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. In this class you would override the &amp;lt;code&amp;gt;act&amp;lt;/code&amp;gt; and optionally &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; Method. &lt;br /&gt;
In the &amp;lt;code&amp;gt;getName&amp;lt;/code&amp;gt; you just return the Name shown in the Logs. &lt;br /&gt;
Also you should create a abstract Method which you would override in subclasses but this is not strickly needded.&lt;br /&gt;
Also you need a Gson constant. You would create it like this &amp;lt;code&amp;gt;   private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); &amp;lt;/code&amp;gt;&lt;br /&gt;
You should also save the &amp;lt;code&amp;gt;DataGenerator&amp;lt;/code&amp;gt; for later use since you can't access from the &amp;lt;code&amp;gt;LootTableProvider&amp;lt;/code&amp;gt;. &lt;br /&gt;
Also you would need two Maps, one with the the Class witch is used to get the Lootable Resource Location in this example the Block and one the Loot Table Builder.&lt;br /&gt;
The second Map consist of a &amp;lt;code&amp;gt;ResourceLocation&amp;lt;/code&amp;gt; and the actual &amp;lt;code&amp;gt;LootTable&amp;lt;/code&amp;gt;. Look at the Code for more info.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();&lt;br /&gt;
&lt;br /&gt;
  protected final Map&amp;lt;Block, LootTable.Builder&amp;gt; lootTables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  public static Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables = new HashMap&amp;lt;&amp;gt;();&lt;br /&gt;
  protected final DataGenerator generator;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also you would need a Function to save the Tables&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
  private void writeTables(DirectoryCache cache, Map&amp;lt;ResourceLocation, LootTable&amp;gt; tables) {&lt;br /&gt;
    Path outputFolder = this.generator.getOutputFolder();&lt;br /&gt;
    tables.forEach((key, lootTable) -&amp;gt; {&lt;br /&gt;
      Path path = outputFolder.resolve(&amp;quot;data/&amp;quot; + key.getNamespace() + &amp;quot;/loot_tables/&amp;quot; + key.getPath() + &amp;quot;.json&amp;quot;);&lt;br /&gt;
      try {&lt;br /&gt;
        IDataProvider.save(GSON, cache, LootTableManager.toJson(lootTable), path);&lt;br /&gt;
      } catch (IOException e) {&lt;br /&gt;
        LOGGER.error(&amp;quot;Couldn't write loot table {}&amp;quot;, path, (Object) e);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For the writeTables method you would need to convert the First Map to the second map, for this we need to iterate over the first map.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
    lootTables.forEach(blockBuilderMap -&amp;gt; {&lt;br /&gt;
      for (Map.Entry&amp;lt;Block, LootTable.Builder&amp;gt; entry : blockBuilderMap.entrySet()) {&lt;br /&gt;
        tables.put(entry.getKey().getLootTable(), entry.getValue().build());&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the act Method you would then first call the Method where you create the tables or just create them in there (if you do you can ignore the next section), then you would convert the Tables and at last you would save the loottables.&lt;br /&gt;
&lt;br /&gt;
== The actual Class for Lootables ==&lt;br /&gt;
=== Another class (Optional) ===&lt;br /&gt;
Create a new class that extends from the Class you created in the Section above and override the abstract function in there you can begin to create your Lootables&lt;br /&gt;
&lt;br /&gt;
=== The LootPool Builder ===&lt;br /&gt;
This is where the magic happens /s.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Data Generation]]&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
	<entry>
		<id>https://forge.gemwire.uk/index.php?title=Tinted_Textures&amp;diff=2656</id>
		<title>Tinted Textures</title>
		<link rel="alternate" type="text/html" href="https://forge.gemwire.uk/index.php?title=Tinted_Textures&amp;diff=2656"/>
		<updated>2021-06-29T22:23:12Z</updated>

		<summary type="html">&lt;p&gt;Ferri Arnus: /* IBlockColor / IItemColor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Many blocks and items in vanilla change their texture color depending on where they are, such as grass. Models support specifying “tint indices” on faces, which are integers that can then be handled by &amp;lt;code&amp;gt;IBlockColor&amp;lt;/code&amp;gt;s and &amp;lt;code&amp;gt;IItemColor&amp;lt;/code&amp;gt;s. See the wiki for information on how tint indices are defined in vanilla models.&lt;br /&gt;
&lt;br /&gt;
=== IBlockColor / IItemColor ===&lt;br /&gt;
Both of these are single-method interfaces. &amp;lt;code&amp;gt;IBlockColor&amp;lt;/code&amp;gt; takes an &amp;lt;code&amp;gt;IBlockState&amp;lt;/code&amp;gt;, an (&amp;lt;code&amp;gt;nullable&amp;lt;/code&amp;gt;) &amp;lt;code&amp;gt;IBlockDisplayReader&amp;lt;/code&amp;gt;, and a (&amp;lt;code&amp;gt;nullable&amp;lt;/code&amp;gt;) &amp;lt;code&amp;gt;BlockPos&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;IItemColor&amp;lt;/code&amp;gt; takes an &amp;lt;code&amp;gt;ItemStack&amp;lt;/code&amp;gt;. Both of them take a parameter &amp;lt;code&amp;gt;tintIndex&amp;lt;/code&amp;gt;, which is the tint index of the face being colored. Both of them return an &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;, a color multiplier. This int is treated as four unsigned bytes, alpha, red, green, and blue, in that order, from most significant byte to least. For each pixel in the tinted face, the value of each color channel is &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;(int)((float)base * multiplier / 255)&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;base&amp;lt;/code&amp;gt; is the original value for the channel, and &amp;lt;code&amp;gt;multiplier&amp;lt;/code&amp;gt; is the associated byte from the color multiplier. Note that blocks do not use the alpha channel. For example, the grass texture, untinted, looks white and gray. The &amp;lt;code&amp;gt;IBlockColor&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;IItemColor&amp;lt;/code&amp;gt; for grass return color multipliers with low red and blue components, but high alpha and green components, (at least in warm biomes) so when the multiplication is performed, the green is brought out and the red/blue diminished.&lt;br /&gt;
&lt;br /&gt;
If an item inherits from the &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;builtin/generated&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; model, each layer (“layer0”, “layer1”, etc.) has a tint index corresponding to its layer index. For blocks, the “particle” layer is index 0.&lt;br /&gt;
&lt;br /&gt;
=== Creating Color Handlers ===&lt;br /&gt;
&amp;lt;code&amp;gt;IBlockColor&amp;lt;/code&amp;gt;s need to be registered to the &amp;lt;code&amp;gt;BlockColors&amp;lt;/code&amp;gt; instance of the game. &amp;lt;code&amp;gt;BlockColors&amp;lt;/code&amp;gt; can be acquired through &amp;lt;code&amp;gt;ColorHandlerEvent$Block&amp;lt;/code&amp;gt;, and an &amp;lt;code&amp;gt;IBlockColor&amp;lt;/code&amp;gt; can be registered by &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;BlockColors#register&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. Note that this does not cause the &amp;lt;code&amp;gt;BlockItem&amp;lt;/code&amp;gt; for the given block to be colored. &amp;lt;code&amp;gt;BlockItem&amp;lt;/code&amp;gt; are items and need to colored with an &amp;lt;code&amp;gt;IItemColor&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void registerBlockColors(ColorHandlerEvent.Block event){&lt;br /&gt;
    event.getBlockColors().register(myIBlockColor, coloredBlock1, coloredBlock2, ...);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;IItemColor&amp;lt;/code&amp;gt;s need to be registered to the &amp;lt;code&amp;gt;ItemColors&amp;lt;/code&amp;gt; instance of the game. &amp;lt;code&amp;gt;ItemColors&amp;lt;/code&amp;gt; can be acquired through &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;ColorHandlerEvent$Item()&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;, and an &amp;lt;code&amp;gt;IItemColor&amp;lt;/code&amp;gt; can be registered by &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;ItemColors#register&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;. This method is overloaded to also take &amp;lt;code&amp;gt;Block&amp;lt;/code&amp;gt;s, which simply registers the color handler for the item &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;Block#asItem&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; (i.e. the block’s &amp;lt;code&amp;gt;BlockItem&amp;lt;/code&amp;gt;).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void registerItemColors(ColorHandlerEvent.Item event){&lt;br /&gt;
    event.getItemColors().register(myIItemColor, coloredItem1, coloredItem2, ...);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This registration must be done client-side, in the initialization phase.&lt;/div&gt;</summary>
		<author><name>Ferri Arnus</name></author>
	</entry>
</feed>