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()));
}
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);
}
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);
}
}
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();
}
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();
}
Aggregations