Allow loading json constants outside of _constants

This commit is contained in:
tterrag 2018-12-02 00:46:19 +00:00
parent 102e0095a7
commit 416bf9e3bf
5 changed files with 151 additions and 55 deletions

View file

@ -31,6 +31,7 @@ import java.util.stream.Stream;
import javax.annotation.Nullable;
import net.minecraftforge.fml.ModList;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Lists;
@ -302,60 +303,66 @@ public class CraftingHelper
String path = key.getPath();
if (!path.equals("recipes/_constants.json")) //Top level only
continue;
try (IResource iresource = manager.getResource(key))
{
JsonObject[] elements = JsonUtils.fromJson(GSON, IOUtils.toString(iresource.getInputStream(), StandardCharsets.UTF_8), JsonObject[].class);
for (int x = 0; x < elements.length; x++)
{
JsonObject json = elements[x];
//Force namespace to the directory that this constants file is in, to prevent modders from overriding other's sneakily
//TODO: Move back to a resource pack/mod specific constant list?
ResourceLocation name = json.has("name") ? new ResourceLocation(JsonUtils.getString(json, "name")) : null;
if (name != null)
name = new ResourceLocation(key.getNamespace(), name.getPath());
if (json == null || json.size() == 0)
LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's null or empty", x, key);
else if (!processConditions(json, "conditions"))
LOGGER.info(CRAFTHELPER, "Skipping loading constant #{} from {} as it's conditions were not met", x, key);
else if (name == null)
LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's missing `name`", x, key);
else if (json.has("items"))
{
List<ItemStack> items = new ArrayList<>();
for (JsonElement item : JsonUtils.getJsonArray(json, "items"))
{
if (item.isJsonObject())
items.add(getItemStack(item.getAsJsonObject(), true));
else
{
LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's `items` entry is not a object", x, key);
items.clear();
break;
}
}
if (!items.isEmpty())
tmp.put(name, new StackList(items));
}
else if (json.has("tag"))
tmp.put(name, Ingredient.deserializeItemList(json));
else if (json.has("item"))
tmp.put(name, new StackList(Lists.newArrayList(getItemStack(JsonUtils.getJsonObject(json, "item"), true))));
else
LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's missing `item` or `items` element", x, key);
}
}
catch (IllegalArgumentException | JsonParseException e)
{
LOGGER.error(CRAFTHELPER, "Parsing error loading constants {}", key, e);
}
catch (IOException e)
{
LOGGER.error(CRAFTHELPER, "Couldn't read constants from {}", key, e);
}
tmp.putAll(loadConstants(manager, key));
}
constants = tmp;
}
public static Map<ResourceLocation, IItemList> loadConstants(IResourceManager manager, ResourceLocation key) {
Map<ResourceLocation, IItemList> tmp = new HashMap<>();
try (IResource iresource = manager.getResource(key))
{
JsonObject[] elements = JsonUtils.fromJson(GSON, IOUtils.toString(iresource.getInputStream(), StandardCharsets.UTF_8), JsonObject[].class);
for (int x = 0; x < elements.length; x++)
{
JsonObject json = elements[x];
//Force namespace to the directory that this constants file is in, to prevent modders from overriding other's sneakily
//TODO: Move back to a resource pack/mod specific constant list?
ResourceLocation name = json.has("name") ? new ResourceLocation(JsonUtils.getString(json, "name")) : null;
if (name != null)
name = new ResourceLocation(key.getNamespace(), name.getPath());
if (json == null || json.size() == 0)
LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's null or empty", x, key);
else if (!processConditions(json, "conditions"))
LOGGER.info(CRAFTHELPER, "Skipping loading constant #{} from {} as it's conditions were not met", x, key);
else if (name == null)
LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's missing `name`", x, key);
else if (json.has("items"))
{
List<ItemStack> items = new ArrayList<>();
for (JsonElement item : JsonUtils.getJsonArray(json, "items"))
{
if (item.isJsonObject())
items.add(getItemStack(item.getAsJsonObject(), true));
else
{
LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's `items` entry is not a object", x, key);
items.clear();
break;
}
}
if (!items.isEmpty())
tmp.put(name, new StackList(items));
}
else if (json.has("tag"))
tmp.put(name, Ingredient.deserializeItemList(json));
else if (json.has("item"))
tmp.put(name, new StackList(Lists.newArrayList(getItemStack(JsonUtils.getJsonObject(json, "item"), true))));
else
LOGGER.error(CRAFTHELPER, "Couldn't load constant #{} from {} as it's missing `item` or `items` element", x, key);
}
}
catch (IllegalArgumentException | JsonParseException e)
{
LOGGER.error(CRAFTHELPER, "Parsing error loading constants {}", key, e);
}
catch (IOException e)
{
LOGGER.error(CRAFTHELPER, "Couldn't read constants from {}", key, e);
}
return tmp;
}
}

View file

@ -42,7 +42,7 @@ public abstract class ForgeRegistryEntry<V extends IForgeRegistryEntry<V>> imple
if (getRegistryName() != null)
throw new IllegalStateException("Attempted to set registry name with existing registry name! New: " + name + " Old: " + getRegistryName());
this.registryName = GameData.checkPrefix(name);
this.registryName = GameData.checkPrefix(name, true);
return (V)this;
}

View file

@ -896,13 +896,32 @@ public class GameData
}
}
/**
* @deprecated Use {@link #checkPrefix(String, boolean)}.
*/
@Deprecated
public static ResourceLocation checkPrefix(String name)
{
return checkPrefix(name, true);
}
/**
* Check a name for a domain prefix, and if not present infer it from the
* current active mod container.
*
* @param name The name or resource location
* @param warnOverrides If true, logs a warning if domain differs from that of
* the currently currently active mod container
*
* @return The {@link ResourceLocation} with given or inferred domain
*/
public static ResourceLocation checkPrefix(String name, boolean warnOverrides)
{
int index = name.lastIndexOf(':');
String oldPrefix = index == -1 ? "" : name.substring(0, index).toLowerCase(Locale.ROOT);
name = index == -1 ? name : name.substring(index + 1);
String prefix = ModLoadingContext.get().getActiveContainer().getNamespace();
if (!oldPrefix.equals(prefix) && oldPrefix.length() > 0)
if (warnOverrides && !oldPrefix.equals(prefix) && oldPrefix.length() > 0)
{
LogManager.getLogger().info("Potentially Dangerous alternative prefix `{}` for name `{}`, expected `{}`. This could be a intended override, but in most cases indicates a broken mod.", oldPrefix, name, prefix);
prefix = oldPrefix;

View file

@ -0,0 +1,62 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* 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.debug.gameplay;
import java.io.IOException;
import java.util.Map;
import java.util.stream.Stream;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.item.crafting.Ingredient.IItemList;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
@Mod(ConstantLoadingTest.MODID)
@Mod.EventBusSubscriber
public class ConstantLoadingTest
{
public static final String MODID = "constantloadingtest";
private static final boolean ENABLED = true;
@SubscribeEvent
public void init(FMLServerStartedEvent event) throws IOException
{
if (!ENABLED)
{
return;
}
Map<ResourceLocation, IItemList> constants = CraftingHelper.loadConstants(event.getServer().getResourceManager(), new ResourceLocation(MODID, "test/_constants.json"));
Ingredient flint = Ingredient.fromItemListStream(Stream.of(constants.get(new ResourceLocation("FLINT"))));
if (flint == null)
{
throw new IllegalStateException("Constant ingredient not loaded properly");
}
if (!flint.test(new ItemStack(Items.FLINT)))
{
throw new IllegalStateException("Constant ingredient failed to match test input");
}
}
}

View file

@ -0,0 +1,8 @@
[
{
"ingredient": {
"item": "minecraft:flint"
},
"name": "FLINT"
}
]