use of org.spongepowered.api.util.Tuple in project SpongeCommon by SpongePowered.
the class FilterGenerator method generateClass.
public byte[] generateClass(String name, final ListenerClassVisitor.DiscoveredMethod method) throws ClassNotFoundException {
name = name.replace('.', '/');
final ListenerClassVisitor.ListenerParameter[] parameters = method.parameterTypes();
SubtypeFilterDelegate sfilter = null;
final List<FilterDelegate> additional = new ArrayList<>();
boolean cancellation = false;
for (final ListenerClassVisitor.ListenerAnnotation anno : method.annotations()) {
final Annotation annotation;
try {
annotation = anno.annotation();
} catch (final AnnotationFormatException e) {
throw new ClassNotFoundException("Failed to load annotation", e);
}
final Object obj = FilterGenerator.filterFromAnnotation(method.classByLoader(anno.type().getClassName()));
if (obj == null) {
continue;
}
if (obj instanceof SubtypeFilter) {
if (sfilter != null) {
throw new IllegalStateException("Cannot have both @Include and @Exclude annotations present at once");
}
sfilter = ((SubtypeFilter) obj).getDelegate(annotation);
} else if (obj instanceof EventTypeFilter) {
final EventTypeFilter etf = (EventTypeFilter) obj;
additional.add(etf.getDelegate(annotation));
if (etf == EventTypeFilter.CANCELLATION) {
cancellation = true;
}
}
}
if (!cancellation && Cancellable.class.isAssignableFrom(parameters[0].clazz())) {
additional.add(new CancellationEventFilterDelegate(Tristate.FALSE));
}
// we know there are no filters, skip generating a class
if (additional.isEmpty() && sfilter == null && parameters.length == 1) {
return null;
}
final ClassWriter cw = new LoaderClassWriter(method.declaringClass().getClassLoader(), ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
MethodVisitor mv;
cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, name, null, "java/lang/Object", new String[] { Type.getInternalName(EventFilter.class) });
if (sfilter != null) {
sfilter.createFields(cw);
}
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
if (sfilter != null) {
sfilter.writeCtor(name, cw, mv);
}
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "filter", "(" + Type.getDescriptor(Event.class) + ")[Ljava/lang/Object;", null, null);
mv.visitCode();
// index of the next available local variable
int local = 2;
if (sfilter != null) {
local = sfilter.write(name, cw, mv, method, local);
}
for (final FilterDelegate eventFilter : additional) {
local = eventFilter.write(name, cw, mv, method, local);
}
// local var indices of the parameters values
final int[] plocals = new int[parameters.length - 1];
for (int i = 1; i < parameters.length; i++) {
final ListenerClassVisitor.ListenerParameter param = parameters[i];
ParameterFilterSourceDelegate source = null;
final List<ParameterFilterDelegate> paramFilters = new ArrayList<>();
for (final ListenerClassVisitor.ListenerAnnotation anno : param.annotations()) {
final Object obj = FilterGenerator.filterFromAnnotation(method.classByLoader(anno.type().getClassName()));
if (obj == null) {
continue;
}
final Annotation annotation;
try {
annotation = anno.annotation();
} catch (AnnotationFormatException e) {
throw new ClassNotFoundException("Failed to load annotation", e);
}
if (obj instanceof ParameterSource) {
if (source != null) {
throw new IllegalStateException("Cannot have multiple parameter filter source annotations (for " + param.name() + ")");
}
source = ((ParameterSource) obj).getDelegate(annotation);
} else if (obj instanceof ParameterFilter) {
paramFilters.add(((ParameterFilter) obj).getDelegate(annotation));
}
}
if (source == null) {
throw new IllegalStateException("Cannot have additional parameters filters without a source (for " + param.name() + ")");
}
if (source instanceof AllCauseFilterSourceDelegate && !paramFilters.isEmpty()) {
// TODO until better handling for filtering arrays is added
throw new IllegalStateException("Cannot have additional parameters filters without an array source (for " + param.name() + ")");
}
final Tuple<Integer, Integer> localState = source.write(cw, mv, method, i, local, plocals, parameters);
local = localState.first();
plocals[i - 1] = localState.second();
for (final ParameterFilterDelegate paramFilter : paramFilters) {
paramFilter.write(cw, mv, param, plocals[i - 1]);
}
}
// create the return array
if (parameters.length == 1) {
mv.visitInsn(ICONST_1);
} else {
mv.visitIntInsn(BIPUSH, parameters.length);
}
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
// load the event into the array
mv.visitInsn(DUP);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(AASTORE);
// load all the params into the array
for (int i = 1; i < parameters.length; i++) {
mv.visitInsn(DUP);
mv.visitIntInsn(BIPUSH, i);
final Type paramType = parameters[i].type();
mv.visitVarInsn(paramType.getOpcode(ILOAD), plocals[i - 1]);
GeneratorUtils.visitBoxingMethod(mv, paramType);
mv.visitInsn(AASTORE);
}
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
final byte[] data = cw.toByteArray();
if (FilterGenerator.FILTER_DEBUG) {
final File outDir = new File(".sponge.debug.out");
final File outFile = new File(outDir, name + ".class");
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
try (final FileOutputStream out = new FileOutputStream(outFile)) {
out.write(data);
} catch (final IOException ignored) {
ignored.printStackTrace();
}
}
return data;
}
use of org.spongepowered.api.util.Tuple in project SpongeCommon by SpongePowered.
the class ResolutionResult method printErrorsIfAny.
public void printErrorsIfAny(final Map<PluginCandidate<T>, String> failedInstance, final Map<PluginCandidate<T>, String> consequentialFailedInstance, final Logger logger) {
final int noOfFailures = this.numberOfFailures() + failedInstance.size() + consequentialFailedInstance.size();
if (noOfFailures == 0) {
return;
}
final PrettyPrinter errorPrinter = new PrettyPrinter(120);
errorPrinter.add("SPONGE PLUGINS FAILED TO LOAD").centre().hr().addWrapped("%d plugin(s) have unfulfilled or cyclic dependencies or failed to load. Your game will continue to load without" + " these plugins.", noOfFailures);
if (!this.duplicateIds.isEmpty()) {
errorPrinter.add();
errorPrinter.add("The following plugins IDs were duplicated - some plugins will not have been loaded:");
for (final String id : this.duplicateIds) {
errorPrinter.add(" * %s", id);
}
}
if (!this.missingDependencies.isEmpty()) {
errorPrinter.add();
errorPrinter.add("The following plugins are missing dependencies:");
for (final Map.Entry<PluginCandidate<T>, Collection<String>> entry : this.missingDependencies.entrySet()) {
errorPrinter.add(" * %s requires [ %s ]", entry.getKey().metadata().id(), String.join(", ", entry.getValue()));
}
}
if (!this.versionMismatch.isEmpty()) {
errorPrinter.add();
errorPrinter.add("The following plugins require different version(s) of dependencies you have installed:");
for (final Map.Entry<PluginCandidate<T>, Collection<Tuple<String, PluginCandidate<T>>>> entry : this.versionMismatch.entrySet()) {
final PluginCandidate<T> candidate = entry.getKey();
final Collection<Tuple<String, PluginCandidate<T>>> mismatchedDeps = entry.getValue();
final String errorString = mismatchedDeps.stream().map(x -> String.format("%s version %s (currently version %s)", x.second().metadata().id(), x.first(), x.second().metadata().version())).collect(Collectors.joining(", "));
errorPrinter.add(" * %s requires [ %s ]", candidate.metadata().id(), errorString);
}
}
if (!this.cyclicDependency.isEmpty()) {
errorPrinter.add();
errorPrinter.add("The following plugins were found to have cyclic dependencies:");
for (final Map.Entry<PluginCandidate<T>, Collection<PluginCandidate<T>>> node : this.cyclicDependency.entrySet()) {
errorPrinter.add(" * %s has dependency cycle [ ... -> %s -> ... ]", node.getKey().metadata().id(), node.getValue().stream().map(x -> x.metadata().id()).collect(Collectors.joining(" -> ")));
}
}
if (!failedInstance.isEmpty()) {
errorPrinter.add();
errorPrinter.add("The following plugins threw exceptions when being created (report these to the plugin authors):");
for (final Map.Entry<PluginCandidate<T>, String> node : failedInstance.entrySet()) {
errorPrinter.add(" * %s with the error message \"%s\"", node.getKey().metadata().id(), node.getValue());
}
}
if (!this.cascadedFailure.isEmpty() || !consequentialFailedInstance.isEmpty()) {
final Map<PluginCandidate<T>, String> mergedFailures = new HashMap<>(consequentialFailedInstance);
for (final Map.Entry<PluginCandidate<T>, Collection<PluginCandidate<T>>> entry : this.cascadedFailure.entrySet()) {
final String error = entry.getValue().stream().map(x -> x.metadata().id()).collect(Collectors.joining(", "));
mergedFailures.merge(entry.getKey(), error, (old, incoming) -> old + ", " + incoming);
}
errorPrinter.add();
errorPrinter.add("The following plugins are not loading because they depend on plugins that will not load:");
for (final Map.Entry<PluginCandidate<T>, String> node : mergedFailures.entrySet()) {
errorPrinter.add(" * %s depends on [ %s ]", node.getKey().metadata().id(), // so we just list all the plugins that failed
node.getValue());
}
}
errorPrinter.add().hr().addWrapped("DO NOT REPORT THIS TO SPONGE. These errors are not Sponge errors, they are plugin loading errors. Seek " + "support from the authors of the plugins listed above if you need help getting these plugins to load.").add();
errorPrinter.addWrapped("Your game will continue to start without the %d plugins listed above. Other plugins will continue to load, " + "however you may wish to stop your game and fix these issues. For any missing dependencies, you " + "may be able to find them at https://ore.spongepowered.org/. For any plugins that have cyclic dependencies or threw " + "exceptions, it is likely a bug in the plugin.", noOfFailures);
errorPrinter.log(logger, Level.ERROR);
}
use of org.spongepowered.api.util.Tuple in project LanternServer by LanternPowered.
the class LanternPlayerAdvancements method createCriteria.
static Tuple<List<AdvancementCriterion>, String[][]> createCriteria(AdvancementCriterion criterion) {
final List<AdvancementCriterion> criteria = new ArrayList<>();
final List<String[]> names = new ArrayList<>();
if (criterion instanceof AndCriterion) {
for (AdvancementCriterion child : ((AndCriterion) criterion).getCriteria()) {
if (child instanceof LanternScoreCriterion) {
for (String id : ((LanternScoreCriterion) child).getIds()) {
names.add(new String[] { id });
}
} else {
names.add(new String[] { child.getName() });
}
criteria.add(child);
}
} else {
if (criterion instanceof LanternScoreCriterion) {
for (String id : ((LanternScoreCriterion) criterion).getIds()) {
names.add(new String[] { id });
}
} else {
names.add(new String[] { criterion.getName() });
}
criteria.add(criterion);
}
return new Tuple<>(criteria, names.toArray(new String[names.size()][]));
}
use of org.spongepowered.api.util.Tuple in project LanternServer by LanternPowered.
the class LanternEntity method collectDamageFunctions.
protected void collectDamageFunctions(List<Tuple<DamageFunction, Consumer<DamageEntityEvent>>> damageFunctions) {
// Absorption health modifier
get(Keys.ABSORPTION).filter(value -> value > 0).ifPresent(value -> {
final DoubleUnaryOperator function = d -> -(Math.max(d - Math.max(d - value, 0), 0));
final DamageModifier modifier = DamageModifier.builder().cause(Cause.of(EventContext.empty(), this)).type(DamageModifierTypes.ABSORPTION).build();
damageFunctions.add(new Tuple<>(new DamageFunction(modifier, function), event -> {
final double mod = event.getDamage(modifier);
offer(Keys.ABSORPTION, Math.max(get(Keys.ABSORPTION).get() + mod, 0));
}));
});
}
use of org.spongepowered.api.util.Tuple in project LanternServer by LanternPowered.
the class LanternWorldManager method init.
/**
* Initializes the root world and the dimension id map.
*/
@SuppressWarnings("SuspiciousMethodCalls")
public void init() throws IOException {
final Path rootWorldDir = this.rootWorldDirectory.get();
// The properties of the root world
LanternWorldProperties rootWorldProperties = null;
LevelData levelData;
if (Files.exists(rootWorldDir)) {
try {
levelData = LanternWorldPropertiesIO.read(rootWorldDir, null, null);
// Create a config
try {
final WorldConfigResult result = getOrCreateWorldConfig(levelData.worldName);
rootWorldProperties = LanternWorldPropertiesIO.convert(levelData, result.config, result.newCreated);
if (result.newCreated) {
result.config.save();
}
} catch (IOException e) {
this.logger.error("Unable to read/write the root world config, please fix this issue before loading the world.", e);
throw e;
}
// Already store the data
addUpdatedWorldProperties(rootWorldProperties, this.rootWorldDirectory.get(), 0);
} catch (FileNotFoundException e) {
// We can ignore this exception, because this means
// that we have to generate the world
} catch (IOException e) {
this.logger.error("Unable to load root world, please fix this issue before starting the server.", e);
throw e;
}
}
// Always use a new dimension map, we will scan for the worlds
// through folders and the dimension ids will be generated or
// refreshed if needed
this.dimensionMap = new BitSet();
LanternWorldProperties rootWorldProperties0 = rootWorldProperties;
// Generate the root (default) world if missing
if (rootWorldProperties0 == null) {
final String name = "Overworld";
rootWorldProperties0 = createWorld(WorldArchetype.builder().from(WorldArchetypes.OVERWORLD).generator(GeneratorTypes.OVERWORLD).build(name, name), "", 0);
}
// Get all the dimensions (worlds) that should be loaded
final List<WorldLookupEntry> loadQueue = new ArrayList<>(1);
// Add the root dimension
loadQueue.add(this.worldByDimensionId.get(0));
final Map<Integer, Tuple<Path, LevelData>> idToLevelData = new HashMap<>();
final List<Tuple<Path, LevelData>> levelDataWithoutId = new ArrayList<>();
if (rootWorldProperties != null) {
for (Path path : Files.list(rootWorldDir).filter(Files::isDirectory).collect(Collectors.toList())) {
if (Files.list(path).count() == 0 || this.ignoredDirectoryNames.contains(path.getFileName().toString().toLowerCase())) {
continue;
}
try {
try {
levelData = LanternWorldPropertiesIO.read(path, null, null);
} catch (FileNotFoundException e) {
this.logger.info("Found a invalid world directory {} inside the root world directory, the level.dat file is missing", path.getFileName().toString());
continue;
}
final Integer dimensionId;
if (path.getFileName().toString().equalsIgnoreCase("DIM1")) {
dimensionId = 1;
} else if (path.getFileName().toString().equalsIgnoreCase("DIM-1")) {
dimensionId = -1;
} else if (levelData.dimensionId != null && levelData.dimensionId >= MIN_CUSTOM_DIMENSION_ID) {
dimensionId = levelData.dimensionId;
} else {
dimensionId = null;
}
final Tuple<Path, LevelData> tuple = Tuple.of(path, levelData);
if (dimensionId == null || idToLevelData.containsValue(dimensionId)) {
levelDataWithoutId.add(tuple);
} else {
idToLevelData.put(dimensionId, tuple);
}
} catch (Exception e) {
this.logger.info("Unable to load the world in the directory {}", path.getFileName().toString());
}
}
}
// Generate a dimension id for all the worlds that need it
for (Tuple<Path, LevelData> tuple : levelDataWithoutId) {
idToLevelData.put(getNextFreeDimensionId(), tuple);
}
levelDataWithoutId.clear();
// Load the world properties and config files for all the worlds
for (Map.Entry<Integer, Tuple<Path, LevelData>> entry : idToLevelData.entrySet()) {
levelData = entry.getValue().getSecond();
final LanternWorldProperties worldProperties;
try {
final WorldConfigResult result = getOrCreateWorldConfig(levelData.worldName);
worldProperties = LanternWorldPropertiesIO.convert(levelData, result.config, result.newCreated);
if (result.newCreated) {
result.config.save();
}
} catch (IOException e) {
this.logger.error("Unable to read/write the world config, please fix this issue before loading the world.", e);
throw e;
}
// Store the world properties
final WorldLookupEntry lookupEntry = addWorldProperties(worldProperties, entry.getValue().getFirst(), entry.getKey());
// Check if it should be loaded on startup
if (worldProperties.loadOnStartup()) {
loadQueue.add(lookupEntry);
}
}
if (!this.worldByDimensionId.containsKey(-1)) {
final String name = "Nether";
if (createWorld(WorldArchetype.builder().from(WorldArchetypes.THE_NETHER).generator(GeneratorTypes.NETHER).build(name, name), "DIM-1", -1).loadOnStartup()) {
loadQueue.add(this.worldByDimensionId.get(-1));
}
}
// The end
if (!this.worldByDimensionId.containsKey(1)) {
final String name = "TheEnd";
if (createWorld(WorldArchetype.builder().from(WorldArchetypes.THE_END).generator(GeneratorTypes.THE_END).build(name, name), "DIM1", 1).loadOnStartup()) {
loadQueue.add(this.worldByDimensionId.get(1));
}
}
// The root world must be enabled
rootWorldProperties0.setEnabled(true);
// Load all the worlds
loadQueue.forEach(this::loadWorld);
}
Aggregations