ForgePatch/src/main/java/net/minecraftforge/fml/common/discovery/json/ASMInfo.java

193 lines
7.2 KiB
Java

/*
* 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.fml.common.discovery.json;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.objectweb.asm.Type;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.loading.moddiscovery.ModAnnotation.EnumHolder;
//Package private, modders shouldn't access this. Do it through ASMDataTable.
class ASMInfo
{
String name;
String[] interfaces;
List<Annotation> annotations;
private Map<Integer, Annotation> byID;
public Annotation getSubAnnotation(int id)
{
if (byID == null)
{
byID = Maps.newHashMap();
annotations.forEach(a -> { if (a.id != null) byID.put(a.id, a); });
}
return byID.get(id);
}
@Override
public String toString()
{
return MoreObjects.toStringHelper("")
.add("name", name)
.add("itf", interfaces)
.add("ann", annotations)
.toString();
}
public enum TargetType { CLASS, FIELD, METHOD, SUBTYPE };
public enum ValueType
{
BOOL(Boolean::valueOf, v -> {boolean[] ret = new boolean[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Boolean.parseBoolean(v[x]); return ret; }),
BYTE(Byte::valueOf, v -> {byte[] ret = new byte[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Byte.parseByte(v[x]); return ret; }),
CHAR(x -> x.charAt(0), v -> {char[] ret = new char[v.length]; for (int x = 0; x < v.length; x++) ret[x] = v[x].charAt(0); return ret; }),
SHORT(Short::valueOf, v -> {short[] ret = new short[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Short.parseShort(v[x]); return ret; }),
INT(Integer::valueOf, v -> {int[] ret = new int[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Integer.parseInt(v[x]); return ret; }),
LONG(Long::valueOf, v -> {long[] ret = new long[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Long.parseLong(v[x]); return ret; }),
FLOAT(Float::valueOf, v -> {float[] ret = new float[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Float.parseFloat(v[x]); return ret; }),
DOUBLE(Double::valueOf, v -> {double[] ret = new double[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Double.parseDouble(v[x]); return ret; }),
STRING(x -> x, x -> x),
CLASS(Type::getType, v -> {Type[] ret = new Type[v.length]; for (int x = 0; x < v.length; x++) ret[x] = Type.getType(v[x]); return ret; }),
ENUM(ValueType::getEnumHolder, v -> {List<EnumHolder> ret = Lists.newArrayList(); for (int x = 0; x < v.length; x++) ret.add(ValueType.getEnumHolder(v[x])); return ret; }),
ANNOTATION(null, null),
NULL(x -> null, x -> null);
public final Function<String, Object> single;
public final Function<String[], Object> array;
private ValueType(Function<String, Object> single, Function<String[], Object> array)
{
this.single = single;
this.array = array;
}
private static EnumHolder getEnumHolder(String value)
{
int idx = value.lastIndexOf('/');
if (idx <= 1)
throw new IllegalArgumentException("Can not create a EnumHolder for value: " + value);
String field = value.substring(idx + 1);
value = value.substring(0, idx);
idx = value.indexOf(';'); //Legacy internal name.
value = value.substring(1, idx);
return new EnumHolder(value, field);
}
};
static class Annotation
{
TargetType type;
String name;
String target;
Integer id;
ValueHolder value;
Map<String, ValueHolder> values;
private Map<String, Object> _values;
public Map<String, Object> getValues(ASMInfo pool)
{
if (_values == null)
{
_values = Maps.newHashMap();
if (values != null)
values.forEach((k, v) -> _values.put(k, v.get(pool)));
else
_values.put("value", value == null ? null : value.get(pool));
}
return _values;
}
@Override
public String toString()
{
return MoreObjects.toStringHelper("")
.add("type", type)
.add("name", name)
.add("target", target)
.add("id", id)
.add("value", value)
.toString();
}
}
static class ValueHolder
{
ValueType type;
String value;
String[] values;
private Object _value;
private ValueType getType()
{
return type == null ? ValueType.STRING : type;
}
public Object get(ASMInfo pool)
{
if (_value == null)
{
if (values != null)
{
if (type == ValueType.ANNOTATION)
{
List<Map<String, Object>> list = Lists.newArrayList();
_value = list;
for (String s : values)
{
Annotation sub = pool.getSubAnnotation(Integer.parseInt(s));
if (sub == null)
FMLLog.log.error("Invalid Sub-Annotation in Annotation JSON: " + s);
else
list.add(sub.getValues(pool));
}
}
else
_value = getType().array.apply(values);
}
else
{
if (type == ValueType.ANNOTATION)
{
Annotation sub = pool.getSubAnnotation(Integer.parseInt(value));
if (sub == null)
FMLLog.log.error("Invalid Sub-Annotation in Annotation JSON: " + value);
else
_value = sub.getValues(pool);
}
else
_value = getType().single.apply(value);
}
}
return _value;
}
}
}