mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-14 01:04:24 +00:00
Backport Global Loot Functions by Draco18s
This commit is contained in:
1 parent
6aadd20f5f
commit
90403d18f9
17 files changed
+735
-44
No files matched your search
@@ -113,8 +113,11 @@ import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.IWorldReader;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.dimension.DimensionType;
|
||||
import net.minecraft.world.storage.loot.LootContext;
|
||||
import net.minecraft.world.storage.loot.LootTable;
|
||||
import net.minecraft.world.storage.loot.LootTableManager;
|
||||
import net.minecraftforge.common.loot.IGlobalLootModifier;
|
||||
import net.minecraftforge.common.loot.LootModifierManager;
|
||||
import net.minecraftforge.common.util.BlockSnapshot;
|
||||
import net.minecraftforge.event.AnvilUpdateEvent;
|
||||
import net.minecraftforge.event.DifficultyChangeEvent;
|
||||
@@ -1208,4 +1211,19 @@ public class ForgeHooks
|
||||
FurnaceTileEntity.getBurnTimes().entrySet().forEach(e -> VANILLA_BURNS.put(e.getKey().delegate, e.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* All loot table drops should be passed to this function so that mod added effects
|
||||
* (e.g. smelting enchantments) can be processed.
|
||||
* @param list The loot generated
|
||||
* @param context The loot context that generated that loot
|
||||
* @return The modified list
|
||||
*/
|
||||
public static List<ItemStack> modifyLoot(List<ItemStack> list, LootContext context) {
|
||||
LootModifierManager man = context.getWorld().getServer().getLootModifierManager();
|
||||
for(IGlobalLootModifier mod : man.getAllLootMods()) {
|
||||
list = mod.apply(list, context);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2019.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common.loot;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.storage.loot.conditions.ILootCondition;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
import net.minecraftforge.registries.IForgeRegistryEntry;
|
||||
|
||||
/**
|
||||
* Abstract base deserializer for LootModifiers. Takes care of Forge registry things.<br/>
|
||||
* Modders should extend this class to return their modifier and implement the abstract
|
||||
* <code>read</code> method to deserialize from json.
|
||||
* @param <T> the Type to deserialize
|
||||
*/
|
||||
public abstract class GlobalLootModifierSerializer<T extends IGlobalLootModifier> implements IForgeRegistryEntry<GlobalLootModifierSerializer<?>> {
|
||||
private ResourceLocation registryName = null;
|
||||
|
||||
public final GlobalLootModifierSerializer<T> setRegistryName(String name) {
|
||||
if (getRegistryName() != null)
|
||||
throw new IllegalStateException("Attempted to set registry name with existing registry name! New: " + name + " Old: " + getRegistryName());
|
||||
|
||||
this.registryName = GameData.checkPrefix(name, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
//Helpers
|
||||
@Override
|
||||
public final GlobalLootModifierSerializer<T> setRegistryName(ResourceLocation name){ return setRegistryName(name.toString()); }
|
||||
|
||||
public final GlobalLootModifierSerializer<T> setRegistryName(String modID, String name){ return setRegistryName(modID + ":" + name); }
|
||||
|
||||
@Override
|
||||
public final ResourceLocation getRegistryName() {
|
||||
return registryName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Most mods will likely not need more than<br/>
|
||||
* <code>return new MyModifier(conditionsIn)</code><br/>
|
||||
* but any additional properties that are needed will need to be deserialized here.
|
||||
* @param name The resource location (if needed)
|
||||
* @param json The full json object (including ILootConditions)
|
||||
* @param conditionsIn An already deserialized list of ILootConditions
|
||||
*/
|
||||
public abstract T read(ResourceLocation location, JsonObject object, ILootCondition[] ailootcondition);
|
||||
|
||||
/**
|
||||
* Used by Forge's registry system.
|
||||
*/
|
||||
@Override
|
||||
public final Class<GlobalLootModifierSerializer<?>> getRegistryType() {
|
||||
return castClass(GlobalLootModifierSerializer.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // Need this wrapper, because generics
|
||||
private static <G> Class<G> castClass(Class<?> cls)
|
||||
{
|
||||
return (Class<G>)cls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2019.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common.loot;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.storage.loot.LootContext;
|
||||
|
||||
/**
|
||||
* Implementation that defines what a global loot modifier must implement in order to be functional.
|
||||
* {@link LootModifier} Supplies base functionality; most modders should only need to extend that.<br/>
|
||||
* Requires an {@link GlobalLootModifierSerializer} to be registered via json (see forge:loot_modifiers/global_loot_modifiers).
|
||||
*/
|
||||
public interface IGlobalLootModifier {
|
||||
/**
|
||||
* Applies the modifier to the list of generated loot. This function needs to be responsible for
|
||||
* checking ILootConditions as well.
|
||||
* @param generatedLoot the list of ItemStacks that will be dropped, generated by loot tables
|
||||
* @param context the LootContext, identical to what is passed to loot tables
|
||||
* @return modified loot drops
|
||||
*/
|
||||
@Nonnull
|
||||
List<ItemStack> apply(List<ItemStack> generatedLoot, LootContext context);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2019.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common.loot;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.storage.loot.LootContext;
|
||||
import net.minecraft.world.storage.loot.conditions.ILootCondition;
|
||||
import net.minecraft.world.storage.loot.conditions.LootConditionManager;
|
||||
|
||||
/**
|
||||
* A base implementation of a Global Loot Modifier for modders to extend.
|
||||
* Takes care of ILootCondition matching and comes with a base serializer
|
||||
* implementation that takes care of Forge registry things.
|
||||
*/
|
||||
public abstract class LootModifier implements IGlobalLootModifier {
|
||||
protected final ILootCondition[] conditions;
|
||||
private final Predicate<LootContext> combinedConditions;
|
||||
|
||||
/**
|
||||
* Constructs a LootModifier.
|
||||
* @param conditionsIn the ILootConditions that need to be matched before the loot is modified.
|
||||
*/
|
||||
protected LootModifier(ILootCondition[] conditionsIn) {
|
||||
this.conditions = conditionsIn;
|
||||
this.combinedConditions = LootConditionManager.and(conditionsIn);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public final List<ItemStack> apply(List<ItemStack> generatedLoot, LootContext context) {
|
||||
return this.combinedConditions.test(context) ? this.doApply(generatedLoot, context) : generatedLoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the modifier to the generated loot (all loot conditions have already been checked
|
||||
* and have returned true).
|
||||
* @param generatedLoot the list of ItemStacks that will be dropped, generated by loot tables
|
||||
* @param context the LootContext, identical to what is passed to loot tables
|
||||
* @return modified loot drops
|
||||
*/
|
||||
@Nonnull
|
||||
protected abstract List<ItemStack> doApply(List<ItemStack> generatedLoot, LootContext context);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2019.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package net.minecraftforge.common.loot;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import net.minecraft.client.resources.JsonReloadListener;
|
||||
import net.minecraft.profiler.IProfiler;
|
||||
import net.minecraft.resources.IResource;
|
||||
import net.minecraft.resources.IResourceManager;
|
||||
import net.minecraft.util.JSONUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.storage.loot.conditions.ILootCondition;
|
||||
import net.minecraft.world.storage.loot.conditions.LootConditionManager;
|
||||
import net.minecraft.world.storage.loot.functions.ILootFunction;
|
||||
import net.minecraft.world.storage.loot.functions.LootFunctionManager;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
public class LootModifierManager extends JsonReloadListener {
|
||||
public static final Logger LOGGER = LogManager.getLogger();
|
||||
private static final Gson GSON_INSTANCE = (new GsonBuilder()).registerTypeHierarchyAdapter(ILootFunction.class, new LootFunctionManager.Serializer()).registerTypeHierarchyAdapter(ILootCondition.class, new LootConditionManager.Serializer()).create();
|
||||
|
||||
private Map<ResourceLocation, IGlobalLootModifier> registeredLootModifiers = ImmutableMap.of();
|
||||
private static final String folder = "loot_modifiers";
|
||||
|
||||
public LootModifierManager() {
|
||||
super(GSON_INSTANCE, folder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void apply(Map<ResourceLocation, JsonObject> resourceList, IResourceManager resourceManagerIn, IProfiler profilerIn) {
|
||||
Builder<ResourceLocation, IGlobalLootModifier> builder = ImmutableMap.builder();
|
||||
//old way (for reference)
|
||||
/*Map<IGlobalLootModifier, ResourceLocation> toLocation = new HashMap<IGlobalLootModifier, ResourceLocation>();
|
||||
resourceList.forEach((location, object) -> {
|
||||
try {
|
||||
IGlobalLootModifier modifier = deserializeModifier(location, object);
|
||||
builder.put(location, modifier);
|
||||
toLocation.put(modifier, location);
|
||||
} catch (Exception exception) {
|
||||
LOGGER.error("Couldn't parse loot modifier {}", location, exception);
|
||||
}
|
||||
});
|
||||
builder.orderEntriesByValue((x,y) -> {
|
||||
return toLocation.get(x).compareTo(toLocation.get(y));
|
||||
});*/
|
||||
//new way
|
||||
ArrayList<ResourceLocation> finalLocations = new ArrayList<ResourceLocation>();
|
||||
ResourceLocation resourcelocation = new ResourceLocation("forge","loot_modifiers/global_loot_modifiers.json");
|
||||
try {
|
||||
//read in all data files from forge:loot_modifiers/global_loot_modifiers in order to do layering
|
||||
for(IResource iresource : resourceManagerIn.getAllResources(resourcelocation)) {
|
||||
try ( InputStream inputstream = iresource.getInputStream();
|
||||
Reader reader = new BufferedReader(new InputStreamReader(inputstream, StandardCharsets.UTF_8));
|
||||
) {
|
||||
JsonObject jsonobject = JSONUtils.fromJson(GSON_INSTANCE, reader, JsonObject.class);
|
||||
boolean replace = jsonobject.get("replace").getAsBoolean();
|
||||
if(replace) finalLocations.clear();
|
||||
JsonArray entryList = jsonobject.get("entries").getAsJsonArray();
|
||||
for(JsonElement entry : entryList) {
|
||||
String loc = entry.getAsString();
|
||||
ResourceLocation res = new ResourceLocation(loc);
|
||||
if(finalLocations.contains(res)) finalLocations.remove(res);
|
||||
finalLocations.add(res);
|
||||
}
|
||||
}
|
||||
|
||||
catch (RuntimeException | IOException ioexception) {
|
||||
LOGGER.error("Couldn't read global loot modifier list {} in data pack {}", resourcelocation, iresource.getPackName(), ioexception);
|
||||
} finally {
|
||||
IOUtils.closeQuietly((Closeable)iresource);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioexception1) {
|
||||
LOGGER.error("Couldn't read global loot modifier list from {}", resourcelocation, ioexception1);
|
||||
}
|
||||
//use layered config to fetch modifier data files (modifiers missing from config are disabled)
|
||||
finalLocations.forEach(location -> {
|
||||
try {
|
||||
IGlobalLootModifier modifier = deserializeModifier(location, resourceList.get(location));
|
||||
builder.put(location, modifier);
|
||||
} catch (Exception exception) {
|
||||
LOGGER.error("Couldn't parse loot modifier {}", location, exception);
|
||||
}
|
||||
});
|
||||
ImmutableMap<ResourceLocation, IGlobalLootModifier> immutablemap = builder.build();
|
||||
this.registeredLootModifiers = immutablemap;
|
||||
}
|
||||
|
||||
private IGlobalLootModifier deserializeModifier(ResourceLocation location, JsonObject object) {
|
||||
ILootCondition[] lootConditions = GSON_INSTANCE.fromJson(object.get("conditions"), ILootCondition[].class);
|
||||
|
||||
ResourceLocation serializer = new ResourceLocation(JSONUtils.getString(object, "type"));
|
||||
|
||||
return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.getValue(serializer).read(location, object, lootConditions);
|
||||
}
|
||||
|
||||
public static GlobalLootModifierSerializer<?> getSerializerForName(ResourceLocation resourcelocation) {
|
||||
return ForgeRegistries.LOOT_MODIFIER_SERIALIZERS.getValue(resourcelocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* An immutable collection of the registered loot modifiers in layered order.
|
||||
* @return
|
||||
*/
|
||||
public Collection<IGlobalLootModifier> getAllLootMods() {
|
||||
return registeredLootModifiers.values();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,6 +49,7 @@ import net.minecraft.world.gen.feature.Feature;
|
||||
import net.minecraft.world.gen.placement.Placement;
|
||||
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder;
|
||||
import net.minecraftforge.common.ModDimension;
|
||||
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
|
||||
import net.minecraftforge.fml.common.registry.GameRegistry;
|
||||
|
||||
/**
|
||||
@@ -97,6 +98,7 @@ public class ForgeRegistries
|
||||
// Custom forge registries
|
||||
public static final IForgeRegistry<ModDimension> MOD_DIMENSIONS = RegistryManager.ACTIVE.getRegistry(ModDimension.class);
|
||||
public static final IForgeRegistry<DataSerializerEntry> DATA_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(DataSerializerEntry.class);
|
||||
public static final IForgeRegistry<GlobalLootModifierSerializer<?>> LOOT_MODIFIER_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(GlobalLootModifierSerializer.class);
|
||||
|
||||
/**
|
||||
* This function is just to make sure static inializers in other classes have run and setup their registries before we query them.
|
||||
|
||||
@@ -63,6 +63,7 @@ import net.minecraft.world.gen.placement.Placement;
|
||||
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.ModDimension;
|
||||
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.event.RegistryEvent.MissingMappings;
|
||||
import net.minecraftforge.fml.LifecycleEventProvider;
|
||||
@@ -141,6 +142,7 @@ public class GameData
|
||||
// Custom forge registries
|
||||
public static final ResourceLocation MODDIMENSIONS = new ResourceLocation("forge:moddimensions");
|
||||
public static final ResourceLocation SERIALIZERS = new ResourceLocation("minecraft:dataserializers");
|
||||
public static final ResourceLocation LOOT_MODIFIER_SERIALIZERS = new ResourceLocation("forge:loot_modifier_serializers");
|
||||
|
||||
private static final int MAX_VARINT = Integer.MAX_VALUE - 1; //We were told it is their intention to have everything in a reg be unlimited, so assume that until we find cases where it isnt.
|
||||
|
||||
@@ -207,6 +209,7 @@ public class GameData
|
||||
// Custom forge registries
|
||||
makeRegistry(MODDIMENSIONS, ModDimension.class ).disableSaving().create();
|
||||
makeRegistry(SERIALIZERS, DataSerializerEntry.class, 256 /*vanilla space*/, MAX_VARINT).disableSaving().disableOverrides().addCallback(SerializerCallbacks.INSTANCE).create();
|
||||
makeRegistry(LOOT_MODIFIER_SERIALIZERS, GlobalLootModifierSerializer.class).disableSaving().disableSync().create();
|
||||
}
|
||||
|
||||
private static <T extends IForgeRegistryEntry<T>> RegistryBuilder<T> makeRegistry(ResourceLocation name, Class<T> type)
|
||||
|
||||
Reference in new issue
Block a user