Update gradle to 7.0.2 and add fabric-1.17 implementation

This commit is contained in:
Blue (Lukas Rieger) 2021-06-08 22:44:55 +02:00
parent 67a0e2a0bf
commit be059a108f
No known key found for this signature in database
GPG Key ID: 904C4995F9E1F800
32 changed files with 1142 additions and 38 deletions

View File

@ -9,10 +9,10 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: recursive submodules: recursive
- name: Set up JDK 1.8 - name: Set up JDK 1.16
uses: actions/setup-java@v1 uses: actions/setup-java@v1
with: with:
java-version: 8 java-version: 16
- name: Build with Gradle - name: Build with Gradle
run: ./gradlew clean test build run: ./gradlew clean test build
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2

View File

@ -146,7 +146,7 @@ public enum MinecraftResource {
MC_1_15 (new MinecraftVersion(1, 15), "mc1_15", "https://launcher.mojang.com/v1/objects/e3f78cd16f9eb9a52307ed96ebec64241cc5b32d/client.jar"), MC_1_15 (new MinecraftVersion(1, 15), "mc1_15", "https://launcher.mojang.com/v1/objects/e3f78cd16f9eb9a52307ed96ebec64241cc5b32d/client.jar"),
MC_1_16 (new MinecraftVersion(1, 16), "mc1_16", "https://launcher.mojang.com/v1/objects/228fdf45541c4c2fe8aec4f20e880cb8fcd46621/client.jar"), MC_1_16 (new MinecraftVersion(1, 16), "mc1_16", "https://launcher.mojang.com/v1/objects/228fdf45541c4c2fe8aec4f20e880cb8fcd46621/client.jar"),
MC_1_16_2 (new MinecraftVersion(1, 16, 2), "mc1_16", "https://launcher.mojang.com/v1/objects/653e97a2d1d76f87653f02242d243cdee48a5144/client.jar"), MC_1_16_2 (new MinecraftVersion(1, 16, 2), "mc1_16", "https://launcher.mojang.com/v1/objects/653e97a2d1d76f87653f02242d243cdee48a5144/client.jar"),
MC_1_17_0_PRE (new MinecraftVersion(1, 17, -1), "mc1_16", "https://launcher.mojang.com/v1/objects/de8e68ea23f837f9ab628cda7b16ba3de4b79153/client.jar"); MC_1_17 (new MinecraftVersion(1, 17), "mc1_16", "https://launcher.mojang.com/v1/objects/1cf89c77ed5e72401b869f66410934804f3d6f52/client.jar");
private final MinecraftVersion version; private final MinecraftVersion version;
private final String resourcePrefix; private final String resourcePrefix;

View File

@ -118,7 +118,7 @@ public static BufferAttribute readJson(JsonReader json) throws IOException {
if(name.equals("array")){ if(name.equals("array")){
json.beginArray(); //array json.beginArray(); //array
while (json.hasNext()){ while (json.hasNext()){
list.add(new Float(json.nextDouble())); list.add((float) json.nextDouble());
} }
json.endArray(); //array json.endArray(); //array
} }

View File

@ -2,7 +2,7 @@ plugins {
id 'java' id 'java'
id 'java-library' id 'java-library'
id 'com.github.johnrengelman.shadow' version '6.1.0' id 'com.github.johnrengelman.shadow' version '6.1.0'
id 'com.github.hierynomus.license' version '0.15.0' id 'com.github.hierynomus.license' version '0.16.1'
} }
allprojects { allprojects {

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -1,7 +1,7 @@
import net.fabricmc.loom.task.RemapJarTask import net.fabricmc.loom.task.RemapJarTask
plugins { plugins {
id 'fabric-loom' version '0.6-SNAPSHOT' id 'fabric-loom' version '0.8-SNAPSHOT'
} }
configurations { configurations {
@ -27,14 +27,9 @@ dependencies {
processResources { processResources {
inputs.property "version", project.version inputs.property "version", project.version
from(sourceSets.main.resources.srcDirs) { filesMatching("fabric.mod.json") {
include "fabric.mod.json"
expand "version": project.version expand "version": project.version
} }
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
} }
shadowJar { shadowJar {

View File

@ -1,7 +1,7 @@
import net.fabricmc.loom.task.RemapJarTask import net.fabricmc.loom.task.RemapJarTask
plugins { plugins {
id 'fabric-loom' version '0.6-SNAPSHOT' id 'fabric-loom' version '0.8-SNAPSHOT'
} }
configurations { configurations {
@ -27,14 +27,9 @@ dependencies {
processResources { processResources {
inputs.property "version", project.version inputs.property "version", project.version
from(sourceSets.main.resources.srcDirs) { filesMatching("fabric.mod.json") {
include "fabric.mod.json"
expand "version": project.version expand "version": project.version
} }
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
} }
shadowJar { shadowJar {

View File

@ -1,7 +1,7 @@
import net.fabricmc.loom.task.RemapJarTask import net.fabricmc.loom.task.RemapJarTask
plugins { plugins {
id 'fabric-loom' version '0.6-SNAPSHOT' id 'fabric-loom' version '0.8-SNAPSHOT'
} }
configurations { configurations {
@ -27,14 +27,9 @@ dependencies {
processResources { processResources {
inputs.property "version", project.version inputs.property "version", project.version
from(sourceSets.main.resources.srcDirs) { filesMatching("fabric.mod.json") {
include "fabric.mod.json"
expand "version": project.version expand "version": project.version
} }
from(sourceSets.main.resources.srcDirs) {
exclude "fabric.mod.json"
}
} }
shadowJar { shadowJar {

View File

@ -0,0 +1,64 @@
import net.fabricmc.loom.task.RemapJarTask
plugins {
id 'fabric-loom' version '0.8-SNAPSHOT'
}
configurations {
implementation.extendsFrom shadowInclude
}
dependencies {
minecraft "com.mojang:minecraft:1.17"
mappings "net.fabricmc:yarn:1.17+build.1:v2"
modImplementation "net.fabricmc:fabric-loader:0.11.3"
modImplementation "net.fabricmc.fabric-api:fabric-api:0.34.9+1.17"
shadowInclude (project(':BlueMapCommon')) {
//exclude dependencies provided by fabric
exclude group: 'com.google.guava', module: 'guava'
exclude group: 'com.google.code.gson', module: 'gson'
exclude group: 'org.apache.commons', module: 'commons-lang3'
exclude group: 'commons-io', module: 'commons-io'
exclude group: 'com.mojang', module: 'brigadier'
}
}
processResources {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
shadowJar {
configurations = [project.configurations.shadowInclude]
//relocate 'com.flowpowered.math', 'de.bluecolored.shadow.flowpowered.math' //DON'T relocate this, because the API depends on it
relocate 'com.typesafe.config', 'de.bluecolored.shadow.typesafe.config'
relocate 'net.querz.nbt', 'de.bluecolored.shadow.querz.nbt'
relocate 'org.spongepowered.configurate', 'de.bluecolored.shadow.configurate'
relocate 'com.github.benmanes.caffeine', 'de.bluecolored.shadow.benmanes.caffeine'
relocate 'com.google.errorprone', 'de.bluecolored.shadow.google.errorprone'
relocate 'org.aopalliance', 'de.bluecolored.shadow.aopalliance'
relocate 'javax.inject', 'de.bluecolored.shadow.javax.inject'
relocate 'com.google.inject', 'de.bluecolored.shadow.google.inject'
relocate 'org.checkerframework', 'de.bluecolored.shadow.checkerframework'
relocate 'org.codehaus', 'de.bluecolored.shadow.codehaus'
relocate 'io.leangen.geantyref', 'de.bluecolored.shadow.geantyref'
}
task ramappedShadowJar(type: RemapJarTask) {
destinationDirectory = file '../../build/release'
dependsOn tasks.shadowJar
input.set(tasks.shadowJar.archiveFile.get())
addNestedDependencies.set(true)
archiveFileName.set("BlueMap-${archiveVersion.get()}-fabric-1.17.jar")
}
build.dependsOn ramappedShadowJar
task sourcesJar(type: Jar, dependsOn: classes) {
archiveClassifier.set("sources")
from sourceSets.main.allSource
}

View File

@ -0,0 +1,84 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* 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.
*/
package de.bluecolored.bluemap.fabric;
import java.io.IOException;
import java.util.Optional;
import com.flowpowered.math.vector.Vector3d;
import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
import de.bluecolored.bluemap.common.plugin.text.Text;
import de.bluecolored.bluemap.core.world.World;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.Vec3d;
public class FabricCommandSource implements CommandSource {
private FabricMod mod;
private Plugin plugin;
private ServerCommandSource delegate;
public FabricCommandSource(FabricMod mod, Plugin plugin, ServerCommandSource delegate) {
this.mod = mod;
this.plugin = plugin;
this.delegate = delegate;
}
@Override
public void sendMessage(Text text) {
delegate.sendFeedback(net.minecraft.text.Text.Serializer.fromJson(text.toJSONString()), false);
}
@Override
public boolean hasPermission(String permission) {
return delegate.hasPermissionLevel(1);
}
@Override
public Optional<Vector3d> getPosition() {
Vec3d pos = delegate.getPosition();
if (pos != null) {
return Optional.of(new Vector3d(pos.x, pos.y, pos.z));
}
return Optional.empty();
}
@Override
public Optional<World> getWorld() {
try {
ServerWorld world = delegate.getWorld();
if (world != null) {
return Optional.ofNullable(plugin.getWorld(mod.getUUIDForWorld(world)));
}
} catch (IOException ignore) {}
return Optional.empty();
}
}

View File

@ -0,0 +1,72 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* 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.
*/
package de.bluecolored.bluemap.fabric;
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.fabric.events.PlayerJoinCallback;
import de.bluecolored.bluemap.fabric.events.PlayerLeaveCallback;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
public class FabricEventForwarder {
private FabricMod mod;
private Collection<ServerEventListener> eventListeners;
public FabricEventForwarder(FabricMod mod) {
this.mod = mod;
this.eventListeners = new ArrayList<>(1);
PlayerJoinCallback.EVENT.register(this::onPlayerJoin);
PlayerLeaveCallback.EVENT.register(this::onPlayerLeave);
}
public synchronized void addEventListener(ServerEventListener listener) {
this.eventListeners.add(listener);
}
public synchronized void removeAllListeners() {
this.eventListeners.clear();
}
public synchronized void onPlayerJoin(MinecraftServer server, ServerPlayerEntity player) {
if (this.mod.getServer() != server) return;
UUID uuid = player.getUuid();
for (ServerEventListener listener : eventListeners) listener.onPlayerJoin(uuid);
}
public synchronized void onPlayerLeave(MinecraftServer server, ServerPlayerEntity player) {
if (this.mod.getServer() != server) return;
UUID uuid = player.getUuid();
for (ServerEventListener listener : eventListeners) listener.onPlayerLeave(uuid);
}
}

View File

@ -0,0 +1,256 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* 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.
*/
package de.bluecolored.bluemap.fabric;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.commands.Commands;
import de.bluecolored.bluemap.common.plugin.serverinterface.Player;
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
import de.bluecolored.bluemap.core.logger.Logger;
import de.bluecolored.bluemap.core.resourcepack.ParseResourceException;
import de.bluecolored.bluemap.fabric.events.PlayerJoinCallback;
import de.bluecolored.bluemap.fabric.events.PlayerLeaveCallback;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.WorldSavePath;
import net.minecraft.world.dimension.DimensionType;
import org.apache.logging.log4j.LogManager;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
public class FabricMod implements ModInitializer, ServerInterface {
private Plugin pluginInstance = null;
private MinecraftServer serverInstance = null;
private Map<File, UUID> worldUUIDs;
private FabricEventForwarder eventForwarder;
private LoadingCache<ServerWorld, UUID> worldUuidCache;
private int playerUpdateIndex = 0;
private Map<UUID, Player> onlinePlayerMap;
private List<FabricPlayer> onlinePlayerList;
public FabricMod() {
Logger.global = new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME));
this.onlinePlayerMap = new ConcurrentHashMap<>();
this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>());
pluginInstance = new Plugin(new MinecraftVersion(1, 17), "fabric-1.17", this);
this.worldUUIDs = new ConcurrentHashMap<>();
this.eventForwarder = new FabricEventForwarder(this);
this.worldUuidCache = Caffeine.newBuilder()
.executor(BlueMap.THREAD_POOL)
.weakKeys()
.maximumSize(1000)
.build(this::loadUUIDForWorld);
}
@Override
public void onInitialize() {
//register commands
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> {
new Commands<>(pluginInstance, dispatcher, fabricSource -> new FabricCommandSource(this, pluginInstance, fabricSource));
});
ServerLifecycleEvents.SERVER_STARTED.register((MinecraftServer server) -> {
this.serverInstance = server;
new Thread(()->{
Logger.global.logInfo("Loading BlueMap...");
try {
pluginInstance.load();
if (pluginInstance.isLoaded()) Logger.global.logInfo("BlueMap loaded!");
} catch (IOException | ParseResourceException e) {
Logger.global.logError("Failed to load bluemap!", e);
pluginInstance.unload();
}
}).start();
});
ServerLifecycleEvents.SERVER_STOPPING.register((MinecraftServer server) -> {
pluginInstance.unload();
Logger.global.logInfo("BlueMap unloaded!");
});
PlayerJoinCallback.EVENT.register(this::onPlayerJoin);
PlayerLeaveCallback.EVENT.register(this::onPlayerLeave);
ServerTickEvents.END_SERVER_TICK.register((MinecraftServer server) -> {
if (server == this.serverInstance) this.updateSomePlayers();
});
}
@Override
public void registerListener(ServerEventListener listener) {
eventForwarder.addEventListener(listener);
}
@Override
public void unregisterAllListeners() {
eventForwarder.removeAllListeners();
}
@Override
public UUID getUUIDForWorld(File worldFolder) throws IOException {
worldFolder = worldFolder.getCanonicalFile();
UUID uuid = worldUUIDs.get(worldFolder);
if (uuid == null) {
uuid = UUID.randomUUID();
worldUUIDs.put(worldFolder, uuid);
}
return uuid;
}
public UUID getUUIDForWorld(ServerWorld world) throws IOException {
try {
return worldUuidCache.get(world);
} catch (RuntimeException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException) throw (IOException) cause;
else throw new IOException(cause);
}
}
private UUID loadUUIDForWorld(ServerWorld world) throws IOException {
MinecraftServer server = world.getServer();
File worldFolder = world.getServer().getRunDirectory().toPath().resolve(server.getSavePath(WorldSavePath.ROOT)).toFile();
File dimensionFolder = DimensionType.getSaveDirectory(world.getRegistryKey(), worldFolder);
File dimensionDir = dimensionFolder.getCanonicalFile();
return getUUIDForWorld(dimensionDir);
}
@Override
public boolean persistWorldChanges(UUID worldUUID) throws IOException, IllegalArgumentException {
final CompletableFuture<Boolean> taskResult = new CompletableFuture<>();
serverInstance.execute(() -> {
try {
for (ServerWorld world : serverInstance.getWorlds()) {
if (getUUIDForWorld(world).equals(worldUUID)) {
world.save(null, true, false);
}
}
taskResult.complete(true);
} catch (Exception e) {
taskResult.completeExceptionally(e);
}
});
try {
return taskResult.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
} catch (ExecutionException e) {
Throwable t = e.getCause();
if (t instanceof IOException) throw (IOException) t;
if (t instanceof IllegalArgumentException) throw (IllegalArgumentException) t;
throw new IOException(t);
}
}
@Override
public File getConfigFolder() {
return new File("config/bluemap");
}
public void onPlayerJoin(MinecraftServer server, ServerPlayerEntity playerInstance) {
if (this.serverInstance != server) return;
FabricPlayer player = new FabricPlayer(this, playerInstance.getUuid());
onlinePlayerMap.put(player.getUuid(), player);
onlinePlayerList.add(player);
}
public void onPlayerLeave(MinecraftServer server, ServerPlayerEntity player) {
if (this.serverInstance != server) return;
UUID playerUUID = player.getUuid();
onlinePlayerMap.remove(playerUUID);
synchronized (onlinePlayerList) {
onlinePlayerList.removeIf(p -> p.getUuid().equals(playerUUID));
}
}
public MinecraftServer getServer() {
return this.serverInstance;
}
@Override
public Collection<Player> getOnlinePlayers() {
return onlinePlayerMap.values();
}
@Override
public Optional<Player> getPlayer(UUID uuid) {
return Optional.ofNullable(onlinePlayerMap.get(uuid));
}
/**
* Only update some of the online players each tick to minimize performance impact on the server-thread.
* Only call this method on the server-thread.
*/
private void updateSomePlayers() {
int onlinePlayerCount = onlinePlayerList.size();
if (onlinePlayerCount == 0) return;
int playersToBeUpdated = onlinePlayerCount / 20; //with 20 tps, each player is updated once a second
if (playersToBeUpdated == 0) playersToBeUpdated = 1;
for (int i = 0; i < playersToBeUpdated; i++) {
playerUpdateIndex++;
if (playerUpdateIndex >= 20 && playerUpdateIndex >= onlinePlayerCount) playerUpdateIndex = 0;
if (playerUpdateIndex < onlinePlayerCount) {
onlinePlayerList.get(playerUpdateIndex).update();
}
}
}
}

View File

@ -0,0 +1,150 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* 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.
*/
package de.bluecolored.bluemap.fabric;
import java.io.IOException;
import java.util.EnumMap;
import java.util.Map;
import java.util.UUID;
import com.flowpowered.math.vector.Vector3d;
import de.bluecolored.bluemap.common.plugin.serverinterface.Gamemode;
import de.bluecolored.bluemap.common.plugin.serverinterface.Player;
import de.bluecolored.bluemap.common.plugin.text.Text;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.GameMode;
public class FabricPlayer implements Player {
private static final UUID UNKNOWN_WORLD_UUID = UUID.randomUUID();
private static final Map<GameMode, Gamemode> GAMEMODE_MAP = new EnumMap<>(GameMode.class);
static {
GAMEMODE_MAP.put(GameMode.ADVENTURE, Gamemode.ADVENTURE);
GAMEMODE_MAP.put(GameMode.SURVIVAL, Gamemode.SURVIVAL);
GAMEMODE_MAP.put(GameMode.CREATIVE, Gamemode.CREATIVE);
GAMEMODE_MAP.put(GameMode.SPECTATOR, Gamemode.SPECTATOR);
}
private UUID uuid;
private Text name;
private UUID world;
private Vector3d position;
private boolean online;
private boolean sneaking;
private boolean invisible;
private Gamemode gamemode;
private FabricMod mod;
public FabricPlayer(FabricMod mod, UUID playerUuid) {
this.uuid = playerUuid;
this.mod = mod;
update();
}
@Override
public UUID getUuid() {
return this.uuid;
}
@Override
public Text getName() {
return this.name;
}
@Override
public UUID getWorld() {
return this.world;
}
@Override
public Vector3d getPosition() {
return this.position;
}
@Override
public boolean isOnline() {
return this.online;
}
@Override
public boolean isSneaking() {
return this.sneaking;
}
@Override
public boolean isInvisible() {
return this.invisible;
}
@Override
public Gamemode getGamemode() {
return this.gamemode;
}
/**
* Only call on server thread!
*/
public void update() {
MinecraftServer server = mod.getServer();
if (server == null) {
this.online = false;
return;
}
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
if (player == null) {
this.online = false;
return;
}
this.gamemode = GAMEMODE_MAP.get(player.interactionManager.getGameMode());
if (this.gamemode == null) this.gamemode = Gamemode.SURVIVAL;
StatusEffectInstance invis = player.getStatusEffect(StatusEffects.INVISIBILITY);
this.invisible = invis != null && invis.getDuration() > 0;
this.name = Text.of(player.getName().getString());
this.online = true;
Vec3d pos = player.getPos();
this.position = new Vector3d(pos.getX(), pos.getY(), pos.getZ());
this.sneaking = player.isSneaking();
try {
this.world = mod.getUUIDForWorld(player.getServerWorld());
} catch (IOException e) {
this.world = UNKNOWN_WORLD_UUID;
}
}
}

View File

@ -0,0 +1,69 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* 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.
*/
package de.bluecolored.bluemap.fabric;
import org.apache.logging.log4j.Logger;
import de.bluecolored.bluemap.core.logger.AbstractLogger;
public class Log4jLogger extends AbstractLogger {
private Logger out;
public Log4jLogger(Logger out) {
this.out = out;
}
@Override
public void logError(String message, Throwable throwable) {
out.error(message, throwable);
}
@Override
public void logWarning(String message) {
out.warn(message);
}
@Override
public void logInfo(String message) {
out.info(message);
}
@Override
public void logDebug(String message) {
if (out.isDebugEnabled()) out.debug(message);
}
@Override
public void noFloodDebug(String message) {
if (out.isDebugEnabled()) super.noFloodDebug(message);
}
@Override
public void noFloodDebug(String key, String message) {
if (out.isDebugEnabled()) super.noFloodDebug(key, message);
}
}

View File

@ -0,0 +1,42 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* 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.
*/
package de.bluecolored.bluemap.fabric.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
public interface PlayerJoinCallback {
Event<PlayerJoinCallback> EVENT = EventFactory.createArrayBacked(PlayerJoinCallback.class,
(listeners) -> (server, player) -> {
for (PlayerJoinCallback event : listeners) {
event.onPlayerJoin(server, player);
}
}
);
void onPlayerJoin(MinecraftServer server, ServerPlayerEntity player);
}

View File

@ -0,0 +1,42 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* 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.
*/
package de.bluecolored.bluemap.fabric.events;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
public interface PlayerLeaveCallback {
Event<PlayerLeaveCallback> EVENT = EventFactory.createArrayBacked(PlayerLeaveCallback.class,
(listeners) -> (server, player) -> {
for (PlayerLeaveCallback event : listeners) {
event.onPlayerLeave(server, player);
}
}
);
void onPlayerLeave(MinecraftServer server, ServerPlayerEntity player);
}

View File

@ -0,0 +1,56 @@
/*
* This file is part of BlueMap, licensed under the MIT License (MIT).
*
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
* Copyright (c) contributors
*
* 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.
*/
package de.bluecolored.bluemap.fabric.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import de.bluecolored.bluemap.fabric.events.PlayerJoinCallback;
import de.bluecolored.bluemap.fabric.events.PlayerLeaveCallback;
import net.minecraft.network.ClientConnection;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerPlayerEntity;
@Mixin(PlayerManager.class)
public abstract class MixinPlayerManager {
@Shadow
public abstract MinecraftServer getServer();
@Inject(at = @At("RETURN"), method = "onPlayerConnect")
public void onPlayerConnect(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) {
PlayerJoinCallback.EVENT.invoker().onPlayerJoin(this.getServer(), player);
}
@Inject(at = @At("HEAD"), method = "remove")
public void remove(ServerPlayerEntity player, CallbackInfo ci) {
PlayerLeaveCallback.EVENT.invoker().onPlayerLeave(this.getServer(), player);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,14 @@
{
"required": true,
"minVersion": "0.8",
"package": "de.bluecolored.bluemap.fabric.mixin",
"compatibilityLevel": "JAVA_8",
"mixins": [],
"client": [],
"server": [
"MixinPlayerManager"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@ -0,0 +1,4 @@
accept-download: false
renderThreadCount: -2
metrics: true
data: "bluemap"

View File

@ -0,0 +1,30 @@
## ##
## BlueMap ##
## Core-Config ##
## ##
# By changing the setting (accept-download) below to TRUE you are indicating that you have accepted mojang's EULA (https://account.mojang.com/documents/minecraft_eula),
# you confirm that you own a license to Minecraft (Java Edition)
# and you agree that BlueMap will download and use a minecraft-client file (depending on the minecraft-version) from mojangs servers (https://launcher.mojang.com/) for you.
# This file contains resources that belong to mojang and you must not redistribute it or do anything else that is not compliant with mojang's EULA.
# BlueMap uses resources in this file to generate the 3D-Models used for the map and texture them. (BlueMap will not work without those resources.)
# %datetime-iso%
accept-download: false
# This changes the amount of threads that BlueMap will use to render the maps.
# A higher value can improve render-speed but could impact performance on the host machine.
# This should be always below or equal to the number of available processor-cores.
# Zero or a negative value means the amount of of available processor-cores subtracted by the value.
# (So a value of -2 with 6 cores results in 4 render-processes)
# Default is -2
renderThreadCount: -2
# If this is true, BlueMap might send really basic metrics reports containg only the implementation-type and the version that is being used to https://metrics.bluecolored.de/bluemap/
# This allows me to track the basic usage of BlueMap and helps me stay motivated to further develop this tool! Please leave it on :)
# An example report looks like this: {"implementation":"bukkit","version":"%version%"}
# Default is true
metrics: true
# The folder where bluemap saves data-files it needs during runtime or to save e.g. the render-progress to resume it later.
# Default is "bluemap"
data: "bluemap"

View File

@ -0,0 +1,5 @@
liveUpdates: true
skinDownload: true
hiddenGameModes: []
hideInvisible: true
hideSneaking: false

View File

@ -0,0 +1,27 @@
## ##
## BlueMap ##
## Plugin-Config ##
## ##
# If the server should send live-updates and player-positions.
# This only works if the integrated webserver is enabled.
# Default is true
liveUpdates: true
# Download the skin from mojang-serves when a player joins your server, so it can be used for the player-markers.
# Default is true
skinDownload: true
# A list of gamemodes that will prevent a player from appearing on the map.
# Possible values are: survival, creative, spectator, adventure
hiddenGameModes: [
"spectator"
]
# If this is true, players that have an invisibility (potion-)effect will be hidden on the map.
# Default is true
hideInvisible: true
# If this is true, players that are sneaking will be hidden on the map.
# Default is false
hideSneaking: false

View File

@ -0,0 +1,3 @@
webroot: "bluemap/web"
useCookies: true
maps: []

View File

@ -0,0 +1,126 @@
## ##
## BlueMap ##
## Render-Config ##
## ##
# The folder (webroot) where the map-data and web-application files will be saved.
# Default is "bluemap/web"
webroot: "bluemap/web"
# If the web-application should use cookies to save the configurations of a user.
# Default is true
useCookies: true
# This is an array with multiple configured maps.
# You can define multiple maps, for different worlds with different render-settings here
maps: [
{
# The id of this map
# Should only contain word-charactes: [a-zA-Z0-9_]
# Changing this value breaks your existing renders.
id: "world"
# The name of this map
# This defines the display name of this map, you can change this at any time.
# Default is the id of this map
name: "World"
# The path to the save-folder of the world to render.
world: "world"
# The position on the world where the map will be centered if you open it.
# You can change this at any time.
# This defaults to the world-spawn if you don't set it.
#startPos: [500, -820]
# The color of thy sky as a hex-color
# You can change this at any time.
# Default is "#7dabff"
skyColor: "#7dabff"
# Defines the ambient light-strength that every block is recieving, regardless of the sunlight/blocklight.
# 0 is no ambient light, 1 is fully lighted.
# You can change this at any time.
# Default is 0
ambientLight: 0
# If this is false, BlueMap tries to omit all blocks that are not visible from above-ground.
# More specific: Block-Faces that have a sunlight/skylight value of 0 are removed.
# This improves the performance of the map on slower devices by a lot, but might cause some blocks to disappear that should normally be visible.
# Changing this value requires a re-render of the map.
# Default is false
renderCaves: false
# With the below values you can limit the map-render.
# This can be used to ignore the nethers ceiling or render only a certain part of a world.
# Changing this values might require a re-render of the map, already rendered tiles outside the limits will not be deleted.
# Default is no min or max value (= infinite bounds)
#minX: -4000
#maxX: 4000
#minZ: -4000
#maxZ: 4000
#minY: 50
#maxY: 126
# Using this, BlueMap pretends that every Block out of the defined render-bounds is AIR,
# this means you can see the blocks where the world is cut (instead of having a see-through/xray view).
# This has only an effect if you set some render-bounds above.
# Changing this value requires a re-render of the map.
# Default is true
renderEdges: true
# With this set to true, the generated files for this world are compressed using gzip to save A LOT of space.
# Files will be only 5% as big with compression!
# Note: If you are using NGINX or Apache to host your map, you can configure them to serve the compressed files directly.
# This is much better than disabling the compression.
# Changing this value requires a re-render of the map.
# Default is true
useCompression: true
# Normally BlueMap detects if a chunk has not yet generated it's light-data and omits rendering those chunks.
# If this is set to true BlueMap will render Chunks even if there is no light-data!
# This can be usefull for example if some mod prevents light-data from being saved correctly.
# However, this also has a few drawbacks:
# - For those chunks, every block will always be fully lit
# - Night-mode might not work correctly
# - Caves will always be rendered (ignoring the 'renderCaves' setting)
# Default is false
ignoreMissingLightData: false
}
# Here another example for the End-Map
# Things we don't want to change from default we can just omit
{
id: "end"
name: "End"
world: "world/DIM1"
# We dont want a blue sky in the end
skyColor: "#080010"
# In the end is no sky-light, so we need to enable this or we won't see anything.
renderCaves: true
# Same here, we don't want a dark map. But not completely lighted, so we see the effect of e.g torches.
ambientLight: 0.6
}
# Here another example for the Nether-Map
{
id: "nether"
name: "Nether"
world: "world/DIM-1"
skyColor: "#290000"
renderCaves: true
ambientLight: 0.6
# We slice the whole world at y:90 so every block above 90 will be air.
# This way we don't render the nethers ceiling.
maxY: 90
renderEdges: true
}
]

View File

@ -0,0 +1,4 @@
enabled: true
webroot: "bluemap/web"
port: 8100
maxConnectionCount: 100

View File

@ -0,0 +1,29 @@
## ##
## BlueMap ##
## Webserver-Config ##
## ##
# With this setting you can disable the integrated web-server.
# This is usefull if you want to only render the map-data for later use, or if you setup your own webserver.
# Default is enabled
enabled: true
# The webroot that the server will host to the web.
# Usually this should be set to the same directory like in the render.conf!
# Default is "bluemap/web"
webroot: "bluemap/web"
# The IP-Adress that the webserver binds to.
# Use "0.0.0.0" to bind to all available local adresses.
# If you only want to access it locally use "localhost".
# Default is "0.0.0.0"
#ip: "localhost"
#ip: "123.45.6.78"
# The port that the webserver listenes to.
# Default is 8100
port: 8100
# Max number of simultaneous connections that the webserver allows
# Default is 100
maxConnectionCount: 100

View File

@ -0,0 +1,36 @@
{
"schemaVersion": 1,
"id": "bluemap",
"version": "${version}",
"name": "BlueMap",
"description": "A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebGL)",
"authors": [
"Blue (TBlueF, Lukas Rieger)"
],
"contact": {
"homepage": "https://github.com/BlueMap-Minecraft",
"sources": "https://github.com/BlueMap-Minecraft/BlueMap"
},
"license": "MIT",
"icon": "assets/bluemap/icon.png",
"environment": "*",
"entrypoints": {
"main": [
"de.bluecolored.bluemap.fabric.FabricMod"
]
},
"mixins": [
"bluemap.mixins.json"
],
"depends": {
"fabricloader": ">=0.11.3",
"fabric": "*",
"fabric-api-base": "*",
"minecraft": ">=1.17.0"
},
"suggests": {}
}

View File

@ -5,7 +5,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '4.1.+', changing: true classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.+', changing: true
} }
} }

View File

@ -5,7 +5,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '4.1.+', changing: true classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.+', changing: true
} }
} }

View File

@ -5,7 +5,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '4.1.+', changing: true classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.+', changing: true
} }
} }

View File

@ -17,17 +17,20 @@ include ':BlueMapCore'
include ':BlueMapCommon' include ':BlueMapCommon'
include ':cli' include ':cli'
include ':sponge-7.2.0' include ':sponge-7.2.0'
include ':sponge-8.0.0' include ':sponge-8.0.0'
include ':spigot' include ':spigot'
include ':forge-1.16.2'
include ':forge-1.15.2'
include ':forge-1.14.4' include ':forge-1.14.4'
include ':forge-1.15.2'
include ':forge-1.16.2'
include ':fabric-1.16.2'
include ':fabric-1.16.1'
include ':fabric-1.15.2' include ':fabric-1.15.2'
include ':fabric-1.16.1'
include ':fabric-1.16.2'
include ':fabric-1.17'
project(':BlueMapAPI').projectDir = "$rootDir/BlueMapAPI" as File project(':BlueMapAPI').projectDir = "$rootDir/BlueMapAPI" as File
@ -35,14 +38,17 @@ project(':BlueMapCore').projectDir = "$rootDir/BlueMapCore" as File
project(':BlueMapCommon').projectDir = "$rootDir/BlueMapCommon" as File project(':BlueMapCommon').projectDir = "$rootDir/BlueMapCommon" as File
project(':cli').projectDir = "$rootDir/implementations/cli" as File project(':cli').projectDir = "$rootDir/implementations/cli" as File
project(':sponge-7.2.0').projectDir = "$rootDir/implementations/sponge-7.2.0" as File project(':sponge-7.2.0').projectDir = "$rootDir/implementations/sponge-7.2.0" as File
project(':sponge-8.0.0').projectDir = "$rootDir/implementations/sponge-8.0.0" as File project(':sponge-8.0.0').projectDir = "$rootDir/implementations/sponge-8.0.0" as File
project(':spigot').projectDir = "$rootDir/implementations/spigot" as File project(':spigot').projectDir = "$rootDir/implementations/spigot" as File
project(':forge-1.16.2').projectDir = "$rootDir/implementations/forge-1.16.2" as File
project(':forge-1.15.2').projectDir = "$rootDir/implementations/forge-1.15.2" as File
project(':forge-1.14.4').projectDir = "$rootDir/implementations/forge-1.14.4" as File project(':forge-1.14.4').projectDir = "$rootDir/implementations/forge-1.14.4" as File
project(':forge-1.15.2').projectDir = "$rootDir/implementations/forge-1.15.2" as File
project(':forge-1.16.2').projectDir = "$rootDir/implementations/forge-1.16.2" as File
project(':fabric-1.16.2').projectDir = "$rootDir/implementations/fabric-1.16.2" as File
project(':fabric-1.16.1').projectDir = "$rootDir/implementations/fabric-1.16.1" as File
project(':fabric-1.15.2').projectDir = "$rootDir/implementations/fabric-1.15.2" as File project(':fabric-1.15.2').projectDir = "$rootDir/implementations/fabric-1.15.2" as File
project(':fabric-1.16.1').projectDir = "$rootDir/implementations/fabric-1.16.1" as File
project(':fabric-1.16.2').projectDir = "$rootDir/implementations/fabric-1.16.2" as File
project(':fabric-1.17').projectDir = "$rootDir/implementations/fabric-1.17" as File