-
Notifications
You must be signed in to change notification settings - Fork 41
Native Extension
- Development environment
- Creating your extension base
- Running the extension from your IDE
- Intercepting and/or sending packets
- Included parsers
Any IDE with Java support can be used to create a G-Earth extension using the G-Earth Native Extension framework, for this guide we'll be using IntelliJ.
G-Earth is written as a Maven project, this allows G-Earth and it's extension framework to be used as dependencies in other projects. For this reason it's best to also create your extension as a Maven project.
- Create a new Maven project with Java 1.8 as the Project JDK (Java 1.8 is recommended since G-Earth itself was also build using Java 1.8)
- Give your project a name, editing the
GroupId
,ArtifactId
andVersion
is optional
IntelliJ will generate the following project files for you
Note: You only have to do this one time, unless you want to add a new version of G-Earth to the repository.
If you've already have G-Earth in your local Maven repository you can skip to the next step.
- Copy
G-Earth.jar
into your project at root level, you will find the jar file in the folder where you have G-Earth installed
- Open the Maven side panel in IntelliJ which you will find in the right sidebar and click the
icon
- Copy the following Maven command and paste it into the window that opened after clicking the
icon and press enter to run it
mvn install:install-file -Dfile=G-Earth.jar -DgroupId=G-Earth -DartifactId=G-Earth -Dversion=1.5.3 -Dpackaging=jar
Note 1: The
mvn
part of the command is already present in the window, make sure not to put it in twice
Note 2: Make sure to change the-DVersion
value if you happen to be installing a different version of the G-Earth.jar
- Now you can delete the
G-Earth.jar
file from your project
One of the generated files is the pom.xml
file which should currently contain the following:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>G-Earth.Extensions</groupId>
<artifactId>TestExtension</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
- Add G-Earth as a dependency by adding the following under the
<properties>...</properties>
part of yourpom
file
<dependencies>
<dependency>
<groupId>G-Earth</groupId>
<artifactId>G-Earth</artifactId>
<version>1.5.3</version>
</dependency>
</dependencies>
Note: If you have a different version of G-Earth added to your local Maven repository make sure to change the version in the
<version>...</version>
tag.
You're pom
file should now look like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>G-Earth.Extensions</groupId>
<artifactId>TestExtension</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>G-Earth</groupId>
<artifactId>G-Earth</artifactId>
<version>1.5.3</version>
</dependency>
</dependencies>
</project>
The Native Extension framework allows you to create two types of extension, console extensions and GUI extensions.
Note: The next section will focus on the setup of a console extension, if you want to setup a GUI extension you can jump over this section.
- Create a new
Java Class
file in themain/java
folder and name it after your extension, in my caseExampleExtension
- Add the
ExtensionInfo
annotation by placing the following right above thepublic class
declaration in the file you just created and change the values to match your extension
@ExtensionInfo(
Title = "Example extension",
Description = "This is just an example",
Version = "0.1",
Author = "WiredSpast"
)
- Make the class extend the
Extension
class by addingextends Extension
right behind thepublic class ExampleExtension
declaration
public class ExampleExtension extends Extension {
- Add a constructor to your class which matches the
super
class
public ExampleExtension(String[] args) {
super(args);
}
- Add the following main method to your file, this will allow you to run your extension
public static void main(String[] args) {
new ExampleExtension(args).run();
}
- In case your IDE hasn't done it for you yet, add the following imports at the top of the file:
import gearth.extensions.Extension;
import gearth.extensions.ExtensionInfo;
Note: Make sure to change
ExampleExtension
in step 4 and 5 to the name of your class file
Your class file should now look like this:
import gearth.extensions.Extension;
import gearth.extensions.ExtensionInfo;
@ExtensionInfo(
Title = "Example extension",
Description = "This is just an example",
Version = "0.1",
Author = "WiredSpast"
)
public class ExampleExtension extends Extension {
public ExampleExtension(String[] args) {
super(args);
}
public static void main(String[] args) {
new ExampleExtension(args).run();
}
}
Your base is now all set up, to test if your base works you can jump to the "Running your extension from your IDE" section.
A GUI extension requires a base of 3 files
- Create a new
Java Class
file in themain/java
folder and name it after your extension, in my caseExampleExtension
- Add the
ExtensionInfo
annotation by placing the following right above thepublic class
declaration in the file you just created and change the values to match your extension
@ExtensionInfo(
Title = "Example extension",
Description = "This is just an example",
Version = "0.1",
Author = "WiredSpast"
)
- Make the class extend the
ExtensionForm
class by addingextends ExtensionForm
right behind thepublic class ExampleExtension
declaration
public class ExampleExtension extends ExtensionForm {
- In case your IDE hasn't done it for you yet, add the following imports at the top of the file:
import gearth.extensions.ExtensionForm;
import gearth.extensions.ExtensionInfo;
Your controller class should now look like this:
import gearth.extensions.ExtensionForm;
import gearth.extensions.ExtensionInfo;
@ExtensionInfo(
Title = "Example extension",
Description = "This is just an example",
Version = "0.1",
Author = "WiredSpast"
)
public class ExampleExtension extends ExtensionForm {
}
- Create a new
FXML file
in themain/resources
folder and name it same way as your controller class, in my caseExampleExtension.fxml
- The created file will already contain a base, in this base you will find the value
fx:controller
replace this value by the name of your controller class (Leave out the.java
)
Afterwards your file should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="ExampleExtension"
prefHeight="400.0" prefWidth="600.0">
</AnchorPane>
- To create your GUI layout it's easiest to switch to IntelliJ's build in Scene Builder which you can find at the bottom of your screen when you have the
FXML
file open
Note 1: If you haven't used the Scene Builder before you will be asked to download the Scene Builder Kit and JavaFX
Note 2: If you are using a different IDE you can download and install the scene builder from here
- Using the Scene Builder you can easily drag components from the left column onto your form canvas and edit it's properties in the right column
- Add a public clicklistener method to your controller class which has exactly one parameter
ActionEvent event
and returnsvoid
public class ExampleExtension extends ExtensionForm {
...
public void onButtonClick(ActionEvent event) {
// Code to run on button click
}
...
}
- Select the button in the Scene builder and set the
On Action
value in theCode
section of the button's properties to the name of your created clicklistener method.
- Give the component a unique
fx:id
in theCode
section of the component's properties
- Add a public variable with the same name and correct JavaFX class type to your controller class
public class ExampleExtension extends ExtensionForm {
...
public Label myLabel;
...
}
Note: Info on how to interact with every different component type can be found here.
- Create a new Java class in the
main/java
folder and give it a name preferably ending in Launcher
- Make the class extend the
ThemedExtensionFormCreator
class by addingextends ThemedExtensionFormCreator
behind thepublic class ExampleExtensionLauncher
declaration
public class ExampleExtensionLauncher extends ThemedExtensionFormCreator {
- Add the following methods to your Launcher class
@Override
public String getTitle() {
return "Example Extension";
}
@Override
protected URL getFormResource() {
return getClass().getResource("ExampleExtension.fxml");
}
Note 1: Make sure to change the name of the FXML file and the window title to match your extension
- Add the following main method to your Launcher class, this main method will be used to run your extension
public static void main(String[] args) {
runExtensionForm(args, ExampleExtensionLauncher.class);
}
Note: make sure the class given as the second parameter of the
runExtensionForm
method matches your launcher class
- In case your IDE hasn't done it for you yet make sure this import is present at the top of your Launcher class file
import gearth.extensions.ThemedExtensionFormCreator;
Now your Launcher class file should look like this:
import gearth.extensions.ThemedExtensionFormCreator;
public class ExampleExtensionLauncher extends ThemedExtensionFormCreator {
@Override
protected String getTitle() {
return "Example Extension";
}
@Override
protected URL getFormResource() {
return getClass().getResource(ExampleExtension.fxml");
}
public static void main(String[] args) {
runExtensionForm(args, ExampleExtensionLauncher.class);
}
}
Now you have your base all set up.
Your extension class (or launcher class for a GUI extension) has a main method, this method will be used to run your extension.
- Create a run configuration for your main class by right clicking the file containing your main method and click
Modify Run Configuration...
underMore Run/Debug
- Put
-p 9092
in theProgram arguments
field, then clickApply
andOK
Note: 9092 is the basic port G-Earth runs its extension socket on, if this port is already occupied G-Earth uses another port, you can find the correct port in the bottom left corner of the Extensions tab in G-Earth.
- Now you can find a play button in the top right corner of your IDE, clicking this play button will run your extension.
- The first time running your extension G-Earth will ask you to confirm the connection, check the
Remember my choice
checkbox and clickYes
- The extension should now be connected to G-Earth and be shown in the Extensions tab
Note: GUI extensions will have a play button displayed at the right side, clicking this will open the GUI you created.
Currently your extension doesn't do anything, to make it do something we have to intercept and/or send packets
To intercept a packet we permanently add a listener, adding these listeners should only happen once when the extension first gets launched. To do this the Extension class has an initExtension
method which we will override in our own extension.
Packets can be intercepted in 2 directions:
- To the hotel server:
HMessage.Direction.TOSERVER
- To your client:
HMessage.Direction.TOCLIENT
- Override the
initExtension
method in your Extension class (or your Controller class for GUI extensions)
@Override
protected void initExtension() {
...
}
- Create a method which has exactly one parameter
HMessage hMessage
, this method will be called when the required packet passes by:
private void onPacket(HMessage hMessage) {
HPacket packet = hMessage.getPacket();
...
}
- Link the created method to the packet header, name or hash or intercept every packet in the
initExtension
method.
- Intercept every packet going to the client
@Override
protected void initExtension() {
...
intercept(HMessage.Direction.TOCLIENT, this::onPacket());
...
}
- Intercept a packet with a specific header ID, in the example we're intercepting the packet with id 100 being send to the server
@Override
protected void initExtension() {
...
intercept(HMessage.Direction.TOSERVER, 100, this::onPacket());
...
}
Note: If you are planning to add your extension to the Extension Store, you're required to not intercept packets by ID but by name or hash
- Intercept a packet with a specific header name, in the example we're intercepting the packet with the name
Chat
going to the client.
@Override
protected void initExtension() {
...
intercept(HMessage.Direction.TOSERVER, "Chat", this::onPacket());
...
}
The same way that we can intercept packets going in both directions, we can also send packets in both directions:
- To the hotel server:
HMessage.Direction.TOSERVER
- To your client:
HMessage.Direction.TOCLIENT
// TODO
// TODO
sendToServer(packet);
sendToClient(packet);
// TODO
// TODO
// TODO