Search in sources :

Example 1 with PrettyPrinter

use of org.spongepowered.common.util.PrettyPrinter in project SpongeCommon by SpongePowered.

the class VanillaPluginManager method loadPlugins.

@SuppressWarnings("unchecked")
public void loadPlugins(final VanillaPluginPlatform platform) {
    this.locatedResources.putAll(platform.getResources());
    final Map<PluginCandidate<PluginResource>, PluginLanguageService<PluginResource>> pluginLanguageLookup = new HashMap<>();
    final Map<PluginLanguageService<PluginResource>, PluginLoader<PluginResource, PluginContainer>> pluginLoaders = new HashMap<>();
    // Initialise the plugin language loaders.
    for (final Map.Entry<PluginLanguageService<PluginResource>, List<PluginCandidate<PluginResource>>> candidate : platform.getCandidates().entrySet()) {
        final PluginLanguageService<PluginResource> languageService = candidate.getKey();
        final String loaderClass = languageService.pluginLoader();
        try {
            pluginLoaders.put(languageService, (PluginLoader<PluginResource, PluginContainer>) Class.forName(loaderClass).getConstructor().newInstance());
        } catch (final InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        candidate.getValue().forEach(x -> pluginLanguageLookup.put(x, languageService));
    }
    // Priority to platform plugins that will already exist here -- meaning the resolver will act upon them first
    // and if someone decides to give a plugin an ID that is the same as a platform plugin, the resolver will effectively
    // reject it.
    final Set<PluginCandidate<PluginResource>> resources = new LinkedHashSet<>();
    pluginLanguageLookup.keySet().stream().filter(x -> this.plugins.containsKey(x.metadata().id())).forEach(resources::add);
    resources.addAll(pluginLanguageLookup.keySet());
    final ResolutionResult<PluginResource> resolutionResult = DependencyResolver.resolveAndSortCandidates(resources, platform.logger());
    final Map<PluginCandidate<PluginResource>, String> failedInstances = new HashMap<>();
    final Map<PluginCandidate<PluginResource>, String> consequentialFailedInstances = new HashMap<>();
    final ClassLoader launchClassloader = VanillaLaunch.instance().getClass().getClassLoader();
    for (final PluginCandidate<PluginResource> candidate : resolutionResult.sortedSuccesses()) {
        final PluginContainer plugin = this.plugins.get(candidate.metadata().id());
        if (plugin != null) {
            if (plugin instanceof VanillaDummyPluginContainer) {
                continue;
            }
            // If we get here, we screwed up - duplicate IDs should have been detected earlier.
            // Place it in the resolution result... it'll then get picked up in the big error message
            resolutionResult.duplicateIds().add(candidate.metadata().id());
            // but this is our screw up, let's also make a big point of it
            final PrettyPrinter prettyPrinter = new PrettyPrinter(120).add("ATTEMPTED TO CREATE PLUGIN WITH DUPLICATE PLUGIN ID").centre().hr().addWrapped("Sponge attempted to create a second plugin with ID '%s'. This is not allowed - all plugins must have a unique " + "ID. Usually, Sponge will catch this earlier -- but in this case Sponge has validated two plugins with " + "the same ID. Please report this error to Sponge.", candidate.metadata().id()).add().add("Technical Details:").add("Plugins to load:", 4);
            resolutionResult.sortedSuccesses().forEach(x -> prettyPrinter.add("*" + x.metadata().id(), 4));
            prettyPrinter.add().add("Detected Duplicate IDs:", 4);
            resolutionResult.duplicateIds().forEach(x -> prettyPrinter.add("*" + x, 4));
            prettyPrinter.log(platform.logger(), Level.ERROR);
            continue;
        }
        // This should work fine, we're sorted so all deps should be in place at this stage.
        if (this.stillValid(candidate, consequentialFailedInstances)) {
            final PluginLanguageService<PluginResource> languageService = pluginLanguageLookup.get(candidate);
            final PluginLoader<PluginResource, PluginContainer> pluginLoader = pluginLoaders.get(languageService);
            try {
                final PluginContainer container = pluginLoader.loadPlugin(platform.getStandardEnvironment(), candidate, launchClassloader);
                this.addPlugin(container);
                this.containerToResource.put(container, candidate.resource());
            } catch (final InvalidPluginException e) {
                failedInstances.put(candidate, "Failed to construct: see stacktrace(s) above this message for details.");
                e.printStackTrace();
            }
        }
    }
    resolutionResult.printErrorsIfAny(failedInstances, consequentialFailedInstances, platform.logger());
    platform.logger().info("Loaded plugin(s): {}", this.sortedPlugins.stream().map(p -> p.metadata().id()).collect(Collectors.toList()));
}
Also used : LinkedHashSet(java.util.LinkedHashSet) SpongePluginManager(org.spongepowered.common.launch.plugin.SpongePluginManager) PluginLanguageService(org.spongepowered.plugin.PluginLanguageService) PluginCandidate(org.spongepowered.plugin.PluginCandidate) Level(org.apache.logging.log4j.Level) PrettyPrinter(org.spongepowered.common.util.PrettyPrinter) HashMap(java.util.HashMap) DependencyResolver(org.spongepowered.vanilla.launch.plugin.resolver.DependencyResolver) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Object2ObjectOpenHashMap(it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) PluginLoader(org.spongepowered.plugin.PluginLoader) Map(java.util.Map) LinkedHashSet(java.util.LinkedHashSet) IdentityHashMap(java.util.IdentityHashMap) ResolutionResult(org.spongepowered.vanilla.launch.plugin.resolver.ResolutionResult) Collection(java.util.Collection) Set(java.util.Set) InvalidPluginException(org.spongepowered.plugin.InvalidPluginException) Collectors(java.util.stream.Collectors) InvocationTargetException(java.lang.reflect.InvocationTargetException) Objects(java.util.Objects) Nullable(org.jetbrains.annotations.Nullable) List(java.util.List) PluginContainer(org.spongepowered.plugin.PluginContainer) PluginDependency(org.spongepowered.plugin.metadata.model.PluginDependency) VanillaPluginPlatform(org.spongepowered.vanilla.applaunch.plugin.VanillaPluginPlatform) Optional(java.util.Optional) PluginResource(org.spongepowered.plugin.PluginResource) Collections(java.util.Collections) Singleton(com.google.inject.Singleton) VanillaLaunch(org.spongepowered.vanilla.launch.VanillaLaunch) HashMap(java.util.HashMap) Object2ObjectOpenHashMap(it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) IdentityHashMap(java.util.IdentityHashMap) PluginLanguageService(org.spongepowered.plugin.PluginLanguageService) PrettyPrinter(org.spongepowered.common.util.PrettyPrinter) InvalidPluginException(org.spongepowered.plugin.InvalidPluginException) PluginResource(org.spongepowered.plugin.PluginResource) ArrayList(java.util.ArrayList) List(java.util.List) PluginLoader(org.spongepowered.plugin.PluginLoader) PluginContainer(org.spongepowered.plugin.PluginContainer) PluginCandidate(org.spongepowered.plugin.PluginCandidate) InvocationTargetException(java.lang.reflect.InvocationTargetException) HashMap(java.util.HashMap) Object2ObjectOpenHashMap(it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap)

Example 2 with PrettyPrinter

use of org.spongepowered.common.util.PrettyPrinter in project SpongeCommon by SpongePowered.

the class PhaseTracker method switchToPhase.

// ----------------- STATE ACCESS ----------------------------------
void switchToPhase(final IPhaseState<?> state, final PhaseContext<?> phaseContext) {
    if (phaseContext.createdTracker != this && Thread.currentThread() != this.getSidedThread()) {
        // lol no, report the block change properly
        new PrettyPrinter(60).add("Illegal Async PhaseTracker Access").centre().hr().addWrapped(PhasePrinter.ASYNC_TRACKER_ACCESS).add().add(new Exception("Async Block Change Detected")).log(SpongeCommon.logger(), Level.ERROR);
        // Maybe? I don't think this is wise.
        return;
    }
    checkNotNull(state, "State cannot be null!");
    checkNotNull(phaseContext, "PhaseContext cannot be null!");
    checkArgument(phaseContext.isComplete(), "PhaseContext must be complete!");
    if (this == PhaseTracker.SERVER && SpongeConfigs.getCommon().get().phaseTracker.verbose) {
        if (this.stack.size() > 6) {
            if (this.stack.checkForRunaways(state, phaseContext)) {
                PhasePrinter.printRunawayPhase(this.stack, state, phaseContext);
            }
        }
    }
    if (phaseContext.shouldProvideModifiers()) {
        this.registerPhaseContextProvider(phaseContext);
    }
    this.stack.push(state, phaseContext);
}
Also used : PrettyPrinter(org.spongepowered.common.util.PrettyPrinter)

Example 3 with PrettyPrinter

use of org.spongepowered.common.util.PrettyPrinter in project SpongeCommon by SpongePowered.

the class PhaseTracker method popCauseFrame.

@Override
public void popCauseFrame(final StackFrame oldFrame) {
    checkNotNull(oldFrame, "oldFrame");
    this.enforceMainThread();
    @Nullable final SpongeCauseStackFrame frame = this.frames.peek();
    if (frame != oldFrame) {
        // If the given frame is not the top frame then some form of
        // corruption of the stack has occurred and we do our best to correct
        // it.
        // If the target frame is still in the stack then we can pop frames
        // off the stack until we reach it, otherwise we have no choice but
        // to simply throw an error.
        int offset = -1;
        int i = 0;
        for (final SpongeCauseStackFrame f : this.frames) {
            if (f == oldFrame) {
                offset = i;
                break;
            }
            i++;
        }
        if (!PhaseTracker.DEBUG_CAUSE_FRAMES && offset == -1) {
            // that was erroneously popped.
            throw new IllegalStateException("Cause Stack Frame Corruption! Attempted to pop a frame that was not on the stack.");
        }
        final PrettyPrinter printer = new PrettyPrinter(100).add("Cause Stack Frame Corruption!").centre().hr().add("Found %d frames left on the stack. Clearing them all.", new Object[] { offset + 1 });
        if (!PhaseTracker.DEBUG_CAUSE_FRAMES) {
            printer.add().add("Please add -Dsponge.debugcauseframes=true to your startup flags to enable further debugging output.");
            SpongeCommon.logger().warn("  Add -Dsponge.debugcauseframes to your startup flags to enable further debugging output.");
        } else {
            printer.add().add("Attempting to pop frame:").add(frame.stackDebug).add().add("Frames being popped are:").add(((SpongeCauseStackFrame) oldFrame).stackDebug);
        }
        while (offset >= 0) {
            @Nullable final SpongeCauseStackFrame f = this.frames.peek();
            if (PhaseTracker.DEBUG_CAUSE_FRAMES && offset > 0) {
                printer.add("   Stack frame in position %d :", new Object[] { offset });
                printer.add(f.stackDebug);
            }
            this.popCauseFrame(f);
            offset--;
        }
        printer.trace(System.err, SpongeCommon.logger(), Level.ERROR);
        if (offset == -1) {
            // so we throw an exception.
            throw new IllegalStateException("Cause Stack Frame Corruption! Attempted to pop a frame that was not on the stack.");
        }
        return;
    }
    this.frames.pop();
    // Remove new values
    for (final Map.Entry<EventContextKey<?>, Object> entry : frame.getOriginalContextDelta().entrySet()) {
        this.cached_ctx = null;
        if (entry.getValue() == null) {
            // wasn't present before, remove
            this.ctx.remove(entry.getKey());
        } else {
            // was there, replace
            this.ctx.put(entry.getKey(), entry.getValue());
        }
    }
    // If there were any objects left on the stack then we pop them off
    while (this.cause.size() > this.min_depth) {
        final int index = this.cause.size();
        // there was a duplicate cause pushed prior to the frame being popped.
        if (this.duplicateCauses.length > index) {
            // At this point, we now need to "clean" the duplicate causes array of duplicates
            // to avoid potentially pruning earlier frame's potentially duplicate causes.
            // And of course, reset the number of duplicates in the entry.
            this.duplicateCauses[index] = 0;
        }
        this.cause.pop();
        // and clear the cached causes
        this.cached_cause = null;
    }
    this.min_depth = frame.old_min_depth;
    final int size = this.cause.size();
    if (this.duplicateCauses.length > size) {
        // Then set the last cause index to whatever the size of the entry was at the time.
        this.duplicateCauses[size] = frame.lastCauseSize;
    }
    // finally, return the frame to the pool
    if (this.framePool.size() < PhaseTracker.MAX_POOL_SIZE) {
        // cache it, but also call clear so we remove references to
        // other objects that may go out of scope
        frame.clear();
        this.framePool.push(frame);
    }
}
Also used : PrettyPrinter(org.spongepowered.common.util.PrettyPrinter) EventContextKey(org.spongepowered.api.event.EventContextKey) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 4 with PrettyPrinter

use of org.spongepowered.common.util.PrettyPrinter in project SpongeCommon by SpongePowered.

the class PhaseTracker method completePhase.

@SuppressWarnings({ "rawtypes", "unused", "try" })
void completePhase(final PhaseContext<?> context) {
    if (context.createdTracker != this && Thread.currentThread() != this.getSidedThread()) {
        // lol no, report the block change properly
        new PrettyPrinter(60).add("Illegal Async PhaseTracker Access").centre().hr().addWrapped(PhasePrinter.ASYNC_TRACKER_ACCESS).add().add(new Exception("Async Block Change Detected")).log(SpongeCommon.logger(), Level.ERROR);
        return;
    }
    final PhaseContext<?> currentContext = this.stack.peek();
    final IPhaseState<?> state = currentContext.state;
    final boolean isEmpty = this.stack.isEmpty();
    if (isEmpty) {
        // The random occurrence that we're told to complete a phase
        // while a world is being changed unknowingly.
        PhasePrinter.printEmptyStackOnCompletion(currentContext);
        return;
    }
    if (context.state != state) {
        PhasePrinter.printIncorrectPhaseCompletion(this.stack, context.state, state);
        // The phase on the top of the stack was most likely never completed.
        // Since we don't know when and where completePhase was intended to be called for it,
        // we simply pop it to allow processing to continue (somewhat) as normal
        this.stack.pop();
        return;
    }
    if (SpongeConfigs.getCommon().get().phaseTracker.verbose) {
        if (this.stack.checkForRunaways(GeneralPhase.Post.UNWINDING, null)) {
            // This printing is to detect possibilities of a phase not being cleared properly
            // and resulting in a "runaway" phase state accumulation.
            PhasePrinter.printRunAwayPhaseCompletion(this.stack, state);
        }
    }
    final boolean hasCaptures = currentContext.hasCaptures();
    try (@Nullable final UnwindingPhaseContext unwinding = UnwindingPhaseContext.unwind(currentContext, hasCaptures)) {
        // a new list of capture lists
        try {
            // loss of objects
            if (hasCaptures) {
                ((IPhaseState) state).unwind(currentContext);
            }
        } catch (final Exception e) {
            PhasePrinter.printMessageWithCaughtException(this.stack, "Exception Exiting Phase", "Something happened when trying to unwind", state, currentContext, e);
        }
    } catch (final Exception e) {
        PhasePrinter.printMessageWithCaughtException(this.stack, "Exception Post Dispatching Phase", "Something happened when trying to post dispatch state", state, currentContext, e);
    }
    this.checkPhaseContextProcessed(state, currentContext);
    // If pop is called, the Deque will already throw an exception if there is no element
    // so it's an error properly handled.
    this.stack.pop();
}
Also used : PrettyPrinter(org.spongepowered.common.util.PrettyPrinter) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 5 with PrettyPrinter

use of org.spongepowered.common.util.PrettyPrinter in project SpongeCommon by SpongePowered.

the class PhaseTracker method dumpStack.

String dumpStack() {
    if (this.stack.isEmpty()) {
        return "[Empty stack]";
    }
    final PrettyPrinter printer = new PrettyPrinter(40);
    this.stack.forEach(data -> PhasePrinter.PHASE_PRINTER.accept(printer, data));
    final ByteArrayOutputStream stream = new ByteArrayOutputStream();
    printer.print(new PrintStream(stream));
    return stream.toString();
}
Also used : PrintStream(java.io.PrintStream) PrettyPrinter(org.spongepowered.common.util.PrettyPrinter) ByteArrayOutputStream(java.io.ByteArrayOutputStream)

Aggregations

PrettyPrinter (org.spongepowered.common.util.PrettyPrinter)28 Nullable (org.checkerframework.checker.nullness.qual.Nullable)5 Map (java.util.Map)4 Collection (java.util.Collection)3 HashMap (java.util.HashMap)3 HashSet (java.util.HashSet)3 Collectors (java.util.stream.Collectors)3 ServerLevel (net.minecraft.server.level.ServerLevel)3 Level (org.apache.logging.log4j.Level)3 PluginContainer (org.spongepowered.plugin.PluginContainer)3 ArrayList (java.util.ArrayList)2 Collections (java.util.Collections)2 IdentityHashMap (java.util.IdentityHashMap)2 LinkedHashSet (java.util.LinkedHashSet)2 List (java.util.List)2 Objects (java.util.Objects)2 Optional (java.util.Optional)2 Set (java.util.Set)2 Player (net.minecraft.world.entity.player.Player)2 NonNull (org.checkerframework.checker.nullness.qual.NonNull)2