Skip to content

Commit

Permalink
Added auto-binding
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim203 committed Jul 12, 2022
1 parent 450eeed commit 4eb60ab
Show file tree
Hide file tree
Showing 14 changed files with 403 additions and 16 deletions.
Empty file added ap/build.gradle.kts
Empty file.
38 changes: 38 additions & 0 deletions ap/src/main/java/org/geysermc/floodgate/ap/AutoBindProcessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/

package org.geysermc.floodgate.ap;

import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;

@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class AutoBindProcessor extends ClassProcessor {
public AutoBindProcessor() {
super("org.geysermc.floodgate.util.AutoBind");
}
}
221 changes: 221 additions & 0 deletions ap/src/main/java/org/geysermc/floodgate/ap/ClassProcessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/

package org.geysermc.floodgate.ap;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.StandardLocation;

/*
* Copied from Geyser
*/
public class ClassProcessor extends AbstractProcessor {
private final String annotationClassName;

private Path outputPath;

private final Set<String> locations = new HashSet<>();

public ClassProcessor(String annotationClassName) {
this.annotationClassName = annotationClassName;
}

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);

processingEnv.getMessager().printMessage(
Kind.NOTE, "Initializing processor " + annotationClassName
);

String outputFile = processingEnv.getOptions().get("metadataOutputFile");
if (outputFile != null && !outputFile.isEmpty()) {
outputPath = Paths.get(outputFile);
}
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
if (!roundEnv.errorRaised()) {
complete();
}

return false;
}

if (!contains(annotations, annotationClassName)) {
return false;
}

for (Element element : roundEnv.getRootElements()) {
if (element.getKind() != ElementKind.CLASS) {
continue;
}

if (!contains(element.getAnnotationMirrors(), annotationClassName)) {
continue;
}

TypeElement typeElement = (TypeElement) element;
locations.add(typeElement.getQualifiedName().toString());
}
return false;
}

public boolean contains(Collection<? extends TypeElement> elements, String className) {
if (elements.isEmpty()) {
return false;
}

for (TypeElement element : elements) {
if (element.getQualifiedName().contentEquals(className)) {
return true;
}
}

return false;
}

public boolean contains(List<? extends AnnotationMirror> elements, String className) {
if (elements.isEmpty()) {
return false;
}

for (AnnotationMirror element : elements) {
if (element.getAnnotationType().toString().equals(className)) {
return true;
}
}

return false;
}

public void complete() {
// Read existing annotation list and verify each class still has this annotation
try (BufferedReader reader = createReader()) {
if (reader != null) {
reader.lines().forEach(canonicalName -> {
if (!locations.contains(canonicalName)) {

TypeElement element =
processingEnv.getElementUtils().getTypeElement(canonicalName);

if (element != null && element.getKind() == ElementKind.CLASS &&
contains(element.getAnnotationMirrors(), annotationClassName)) {
locations.add(canonicalName);
}
}
});
}
} catch (IOException e) {
e.printStackTrace();
}

if (!locations.isEmpty()) {
try (BufferedWriter writer = createWriter()) {
for (String location : locations) {
writer.write(location);
writer.newLine();
}
} catch (IOException ex) {
ex.printStackTrace();
}
} else {
processingEnv.getMessager().printMessage(Kind.NOTE,
"Did not find any classes annotated with " + annotationClassName
);
}

processingEnv.getMessager().printMessage(
Kind.NOTE, "Completed processing for " + annotationClassName
);
}

private BufferedReader createReader() throws IOException {
if (outputPath != null) {
processingEnv.getMessager().printMessage(Kind.NOTE,
"Reading existing " + annotationClassName + " list from " + outputPath
);

return Files.newBufferedReader(outputPath);
}

FileObject obj = processingEnv.getFiler().getResource(
StandardLocation.CLASS_OUTPUT, "", annotationClassName
);

if (obj != null) {
processingEnv.getMessager().printMessage(
Kind.NOTE,
"Reading existing " + annotationClassName + " list from " + obj.toUri()
);

try {
return new BufferedReader(obj.openReader(false));
} catch (NoSuchFileException ignored) {}
}
return null;
}

private BufferedWriter createWriter() throws IOException {
if (outputPath != null) {
processingEnv.getMessager().printMessage(
Kind.NOTE, "Writing " + annotationClassName + " to " + outputPath
);

return Files.newBufferedWriter(outputPath);
}

FileObject obj = processingEnv.getFiler().createResource(
StandardLocation.CLASS_OUTPUT, "", annotationClassName
);

processingEnv.getMessager().printMessage(
Kind.NOTE, "Writing " + annotationClassName + " to " + obj.toUri()
);

return new BufferedWriter(obj.openWriter());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.geysermc.floodgate.ap.AutoBindProcessor
3 changes: 3 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ dependencies {
api(projects.api)
api("org.geysermc.configutils", "configutils", Versions.configUtilsVersion)

compileOnly(projects.ap)
annotationProcessor(projects.ap)

api("com.google.inject", "guice", Versions.guiceVersion)
api("com.nukkitx.fastutil", "fastutil-short-object-maps", Versions.fastutilVersion)
api("com.nukkitx.fastutil", "fastutil-int-object-maps", Versions.fastutilVersion)
Expand Down
19 changes: 5 additions & 14 deletions core/src/main/java/org/geysermc/floodgate/FloodgatePlatform.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,22 @@
import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.event.PostEnableEvent;
import org.geysermc.floodgate.event.ShutdownEvent;
import org.geysermc.floodgate.link.PlayerLinkLoader;
import org.geysermc.floodgate.module.PostInitializeModule;
import org.geysermc.floodgate.news.NewsChecker;
import org.geysermc.floodgate.util.Metrics;
import org.geysermc.floodgate.util.PostEnableMessages;

public class FloodgatePlatform {
private static final UUID KEY = UUID.randomUUID();
@Inject private FloodgateApi api;
@Inject private PlatformInjector injector;

@Inject private FloodgateConfig config;
@Inject private Injector guice;

@Inject
public void init(PacketHandlers packetHandlers, HandshakeHandlers handshakeHandlers) {
PlayerLink link = guice.getInstance(PlayerLinkLoader.class).load();

public void init(
FloodgateApi api,
PlayerLink link,
PacketHandlers packetHandlers,
HandshakeHandlers handshakeHandlers) {
InstanceHolder.set(api, link, this.injector, packetHandlers, handshakeHandlers, KEY);

guice.getInstance(NewsChecker.class).start();
}

public void enable(Module... postInitializeModules) throws RuntimeException {
Expand All @@ -75,10 +70,6 @@ public void enable(Module... postInitializeModules) throws RuntimeException {

this.guice = guice.createChildInjector(new PostInitializeModule(postInitializeModules));

//todo add some kind of auto-load, as this looks kinda weird
guice.getInstance(PostEnableMessages.class);
guice.getInstance(Metrics.class);

guice.getInstance(PubSubSupport.class).publish(new PostEnableEvent());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/

package org.geysermc.floodgate.module;

import com.google.inject.AbstractModule;
import org.geysermc.floodgate.util.AutoBind;
import org.geysermc.floodgate.util.Utils;

public class AutoBindModule extends AbstractModule {
@Override
protected void configure() {
for (Class<?> clazz : Utils.getGeneratedClassesForAnnotation(AutoBind.class)) {
bind(clazz).asEagerSingleton();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.packet.PacketHandlers;
import org.geysermc.floodgate.api.player.FloodgatePlayer;
Expand All @@ -56,7 +57,7 @@
import org.geysermc.floodgate.crypto.KeyProducer;
import org.geysermc.floodgate.event.util.ListenerAnnotationMatcher;
import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.news.NewsChecker;
import org.geysermc.floodgate.link.PlayerLinkLoader;
import org.geysermc.floodgate.packet.PacketHandlersImpl;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
Expand Down Expand Up @@ -92,7 +93,7 @@ public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
bind(PacketHandlers.class).to(PacketHandlersImpl.class);
bind(PacketHandlersImpl.class).asEagerSingleton();

bind(NewsChecker.class).in(Singleton.class);
install(new AutoBindModule());
}

@Provides
Expand All @@ -101,6 +102,12 @@ public FloodgateConfig floodgateConfig(ConfigLoader configLoader) {
return configLoader.load();
}

@Provides
@Singleton
public PlayerLink playerLink(PlayerLinkLoader linkLoader) {
return linkLoader.load();
}

@Provides
@Singleton
public KeyProducer keyProducer() {
Expand Down
Loading

0 comments on commit 4eb60ab

Please sign in to comment.