Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabric Port #13

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 27 additions & 25 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
# This workflow will build a Java project with Gradle

name: Java CI with Maven
name: Java CI with Gradle

on:
workflow_dispatch:
Expand All @@ -12,27 +11,30 @@ on:

jobs:
build:

strategy:
matrix:
# Use these Java versions
java: [
21
]
runs-on: ubuntu-latest

steps:
- uses: actions/[email protected]
- name: Set up JDK 16
uses: actions/[email protected]
with:
java-version: '16'
distribution: 'temurin'
- name: Cache
uses: actions/[email protected]
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Upload a Build Artifact
uses: actions/[email protected]
with:
# A file, directory or wildcard pattern that describes what to upload
path: /home/runner/work/BlueMapFloodgate/BlueMapFloodgate/target/*
- name: checkout repository
uses: actions/checkout@v4
- name: validate gradle wrapper
uses: gradle/wrapper-validation-action@v2
- name: setup jdk ${{ matrix.java }}
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'microsoft'
- name: make gradle wrapper executable
run: chmod +x ./gradlew
- name: build
run: ./gradlew build
- name: capture build artifacts
if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java
uses: actions/upload-artifact@v4
with:
name: Artifacts
path: build/libs/
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
*.ipr
*.iws

# IntelliJ
# Gradle
.gradle/
build/
out/
classes/

# Compiled class file
*.class
Expand All @@ -18,7 +21,6 @@ out/
*.ctxt

# Package Files #
*.jar
*.war
*.nar
*.ear
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![GitHub Total Downloads](https://img.shields.io/github/downloads/TechnicJelle/BlueMapFloodgate/total?label=Downloads&color=success "Click here to download the plugin")](https://github.com/TechnicJelle/BlueMapFloodgate/releases/latest)
[![Servers using this plugin](https://img.shields.io/bstats/servers/16426?label=Servers)](https://bstats.org/plugin/bukkit/BlueMap%20Floodgate/16426)

A Minecraft Paper plugin and [BlueMap](https://github.com/BlueMap-Minecraft/BlueMap) addon that adds [Geyser/Floodgate](https://github.com/GeyserMC/Floodgate) support:
A Minecraft Paper plugin, Fabric mod, and [BlueMap](https://github.com/BlueMap-Minecraft/BlueMap) addon that adds [Geyser/Floodgate](https://github.com/GeyserMC/Floodgate) support:
by default, floodgate players don't have the correct playerhead image on BlueMap. This plugin fixes that.

| Without | With |
Expand Down
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
plugins {
id 'maven-publish'

id 'fabric-loom' version '1.6-SNAPSHOT' apply false
}
61 changes: 61 additions & 0 deletions fabric/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
apply plugin: 'fabric-loom'

version = project.mod_version
group = project.maven_group

base {
archivesName = "${project.archives_base_name}-${project.target_version}"
}

repositories {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}

loom {
splitEnvironmentSourceSets()

mods {
"blue-map-floodgate" {
sourceSet sourceSets.main
sourceSet sourceSets.client
}
}

}

dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"

implementation "maven.modrinth:bluemap:${project.bluemap_version}"
}

processResources {
inputs.property "version", project.version

filesMatching("fabric.mod.json") {
expand "version": project.version
}
}

tasks.withType(JavaCompile).configureEach {
it.options.release = 21
}

java {
withSourcesJar()

sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}

jar {
from("LICENSE") {
rename { "${it}_${project.base.archivesName.get()}"}
}
}
18 changes: 18 additions & 0 deletions fabric/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
org.gradle.parallel=true

mod_version=1.0.0
maven_group=com.technicjelle.bluemapfloodgate
archives_base_name=blue-map-floodgate

target_version=1.20-1.20.6

# Dependencies

minecraft_version=1.20.6
yarn_mappings=1.20.6+build.1
loader_version=0.15.11
fabric_version=0.98.0+1.20.6

bluemap_version=3.21-fabric-1.20.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.technicjelle.bluemapfloodgate;

import de.bluecolored.bluemap.api.BlueMapAPI;
import de.bluecolored.bluemap.api.plugin.SkinProvider;
import net.fabricmc.api.ModInitializer;

import net.fabricmc.loader.api.FabricLoader;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;

public class BlueMapFloodgate implements ModInitializer {
public static final String MODID = "blue-map-floodgate";
private static final Logger LOGGER = LoggerFactory.getLogger(MODID);

@Override
public void onInitialize() {
LOGGER.info("Successfully loaded {} mod!", MODID);

// this needs to below the LOGGER message, otherwise the game will crash
if (FabricLoader.getInstance().isModLoaded("bluemap")) {
BlueMapAPI.onEnable(this.setSkinProvider);
}
}

private final Consumer<BlueMapAPI> setSkinProvider = blueMapAPI -> {
SkinProvider skinProvider = getSkinProvider(blueMapAPI);

blueMapAPI.getPlugin().setSkinProvider(skinProvider);
};

// TODO convert into an API so the 'paper' and 'fabric' projects can use the same code

private SkinProvider getSkinProvider(BlueMapAPI blueMapAPI) {
return new SkinProvider() {
private final SkinProvider skinProvider = blueMapAPI.getPlugin().getSkinProvider();

@Override
public Optional<BufferedImage> load(UUID uuid) throws IOException {
if (isFloodgatePlayer(uuid)) {
long xuid = getXUID(uuid);

@Nullable String textureId = SkinHttpUtils.getTextureIdFromXUID(xuid);
if (textureId == null) {
LOGGER.warn("Texture ID for {} is null!", uuid);
return Optional.empty();
}

@Nullable BufferedImage skin = SkinHttpUtils.getSkinTexture(textureId);

if (skin == null) {
LOGGER.warn("Failed to get the skin for {}", uuid);
return Optional.empty();
}

LOGGER.info("Successfully retrieved the skin for {}!", uuid);
return Optional.of(skin);
} else {
return skinProvider.load(uuid);
}
}
};
}

/**
* Checks to see if the player connecting the sever is a Floodgate player.
*/
private boolean isFloodgatePlayer(UUID uuid) {
return uuid.version() == 0;
}

/**
* When provided an {@code uuid}, return the least significant bits which represents
* the {@code xuid}.
*/
private long getXUID(UUID uuid) {
return uuid.getLeastSignificantBits();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.technicjelle.bluemapfloodgate;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class SkinHttpUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(BlueMapFloodgate.MODID + "/SkinHttpUtils");

/**
* Get a Bedrock player's skin texture using their XUID.
*
* @param xuid obtained by getting the least significant bits of the UUID.
* @return {@code String texture_id} from https://api.geysermc.org/v2/skin/{xuid}.
*/
public static String getTextureIdFromXUID(long xuid) {
try {
URL url = new URL("https://api.geysermc.org/v2/skin/" + xuid);

try {
URLConnection request = url.openConnection();
JsonObject json = JsonParser.parseReader(new InputStreamReader((InputStream) request.getContent())).getAsJsonObject();

if (json == null) {
LOGGER.warn("No content received from {}!", url);
return null;
}

JsonElement texture = json.get("texture_id");
String textureId = texture.getAsString();

if (textureId == null) {
LOGGER.warn("Could not get the texture_id from {}!", url);
return null;
}

return textureId;
} catch (IOException e) {
LOGGER.warn("Failed to get the texture for {} from {}!", xuid, url);
return null;
}
} catch (MalformedURLException e) {
LOGGER.error("Geyser API URL is malformed", e);
return null;
}
}

/**
* Retrieve a player's skin from Minecraft's texture servers.
*
* @param textureId obtained from {@link SkinHttpUtils#getTextureIdFromXUID}.
* @return {@code BufferedImage} BlueMap will use to display a player's head
* on the map website.
*/
public static BufferedImage getSkinTexture(String textureId) {
try {
URL url = new URL("https://textures.minecraft.net/texture/" + textureId);

try {
InputStream stream = url.openStream();
return ImageIO.read(stream);
} catch (IOException e) {
LOGGER.error("Failed to read input stream from {} url!", url);
}
} catch (MalformedURLException e) {
LOGGER.error("Minecraft textures URL is malformed", e);
return null;
}

return null;
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions fabric/src/main/resources/fabric.mod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"schemaVersion": 1,
"id": "blue-map-floodgate",
"version": "${version}",
"name": "Blue Map Floodgate",
"description": "Correct the player head image on BlueMap when floodgate players are connected to the server!",
"authors": [
"TechnicJelle",
"ShadowHunter22"
],
"contact": {
"sources": "https://github.com/TechnicJelle/BlueMapFloodgate"
},
"license": "Mozilla Public License 2.0",
"icon": "assets/blue-map-floodgate/icon.png",
"environment": "*",
"entrypoints": {
"main": [
"com.technicjelle.bluemapfloodgate.BlueMapFloodgate"
]
},
"depends": {
"fabricloader": ">=0.15.11",
"minecraft": ">=1.20",
"java": ">=17",
"fabric-api": "*",
"bluemap": "*"
},
"suggests": {
"another-mod": "*"
}
}
6 changes: 6 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
org.gradle.parallel=true

maven_group=com.technicjelle.bluemapfloodgate
archives_base_name=bluemapfloodgate
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
Loading