Add neoforge implementation

This commit is contained in:
Lukas Rieger (Blue) 2023-12-06 17:19:18 +01:00
parent 3f82a821a2
commit c7f340dec3
No known key found for this signature in database
GPG Key ID: 2D09EC5ED2687FF2
13 changed files with 988 additions and 0 deletions

View File

@ -1,6 +1,9 @@
tasks.register("clean") {
gradle.includedBuilds.forEach {
// workaround for https://github.com/neoforged/NeoGradle/issues/18
if (it.name == "neoforge-1.20.2") return@forEach
dependsOn(it.task(":clean"))
}

View File

@ -0,0 +1,169 @@
plugins {
id "java"
id "java-library"
id "net.neoforged.gradle.userdev" version '7.0.57'
id "com.diffplug.spotless" version "6.1.2"
id "com.github.node-gradle.node" version "3.0.1"
id "com.modrinth.minotaur" version "2.+"
id "com.matthewprenger.cursegradle" version "1.4.0"
id "com.github.johnrengelman.shadow" version "7.1.2"
}
group = "de.bluecolored.bluemap.forge"
version = System.getProperty("bluemap.version") ?: "?" // set by BlueMapCore
repositories {
mavenLocal()
mavenCentral()
maven {
setUrl("https://libraries.minecraft.net")
}
maven {
setUrl("https://jitpack.io")
}
}
base {
archivesName = "bluemap"
}
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
sourceSets.main.resources { srcDir 'src/generated/resources' }
configurations {
implementation.extendsFrom(shadowInclude)
}
dependencies {
implementation "net.neoforged:neoforge:20.2.86"
shadowInclude ("de.bluecolored.bluemap.common:BlueMapCommon") {
//exclude dependencies provided by forge
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")
}
testImplementation ("org.junit.jupiter:junit-jupiter:5.8.2")
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.8.2")
}
tasks.withType(ProcessResources).configureEach {
var replaceProperties = [
minecraft_version: minecraft_version,
minecraft_version_range: minecraft_version_range,
neo_version: neo_version,
neo_version_range: neo_version_range,
loader_version_range: loader_version_range,
mod_id: mod_id,
mod_name: mod_name,
mod_license: mod_license,
mod_version: version,
mod_description: mod_description,
pack_format_number: pack_format_number,
]
inputs.properties replaceProperties
filesMatching(['META-INF/mods.toml', 'pack.mcmeta']) {
expand replaceProperties + [project: project]
}
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
}
tasks.withType(AbstractArchiveTask).configureEach {
setReproducibleFileOrder(true)
setPreserveFileTimestamps(false)
}
spotless {
java {
target ("src/*/java/**/*.java")
licenseHeaderFile("../../HEADER")
indentWithSpaces()
trimTrailingWhitespace()
}
}
test {
useJUnitPlatform()
}
shadowJar {
destinationDirectory.set(file("../../build/release"))
archiveFileName.set("BlueMap-${project.version}-${project.name}.jar")
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 ("org.aopalliance", "de.bluecolored.shadow.aopalliance")
relocate ("javax.inject", "de.bluecolored.shadow.javax.inject")
relocate ("org.checkerframework", "de.bluecolored.shadow.checkerframework")
relocate ("org.codehaus", "de.bluecolored.shadow.codehaus")
relocate ("io.leangen.geantyref", "de.bluecolored.shadow.geantyref")
relocate ("io.airlift", "de.bluecolored.shadow.airlift")
relocate ("com.google.errorprone", "de.bluecolored.shadow.google.errorprone")
relocate ("com.google.inject", "de.bluecolored.shadow.google.inject")
relocate ("org.apache.commons.dbcp2", "de.bluecolored.shadow.apache.commons.dbcp2")
relocate ("org.apache.commons.logging", "de.bluecolored.shadow.apache.commons.logging")
relocate ("org.apache.commons.pool2", "de.bluecolored.shadow.apache.commons.pool2")
}
task release {
dependsOn(shadowJar)
}
modrinth {
token = System.getenv("MODRINTH_TOKEN")
projectId = "swbUV1cr"
versionNumber = "${project.version}-${project.name}"
changelog = file("../../release.md")
.getText()
.replace("{version}", project.version.toString())
uploadFile = shadowJar
loaders = ["neoforge"]
gameVersions = ["1.20.2", "1.20.3"]
}
curseforge {
apiKey = System.getenv("CURSEFORGE_TOKEN") ?: ""
project {
id = "406463"
changelogType = "markdown"
changelog = file("../../release.md")
.getText()
.replace("{version}", project.version.toString())
releaseType = "release"
addGameVersion "NeoForge"
addGameVersion "Java 18"
addGameVersion "Java 17"
addGameVersion "1.20.2"
addGameVersion "1.20.3"
mainArtifact shadowJar
}
options {
javaVersionAutoDetect = false
javaIntegration = false
forgeGradleIntegration = false
}
}
task publish {
dependsOn(tasks.findByName("modrinth"))
dependsOn(tasks.findByName("curseforge"))
}

View File

@ -0,0 +1,16 @@
org.gradle.daemon=false
org.gradle.debug=false
minecraft_version=1.20.2
minecraft_version_range=[1.20.2,1.21)
neo_version=20.2.86
neo_version_range=[20.2,)
loader_version_range=[1,)
mapping_channel=official
mapping_version=1.20.2
mod_id=bluemap
mod_name=BlueMap
mod_description=A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebGL)
mod_license=MIT
pack_format_number=18

View File

@ -0,0 +1,15 @@
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
maven { url = 'https://maven.neoforged.net/releases' }
}
}
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
}
rootProject.name = "neoforge-1.20.2"
includeBuild("../../BlueMapCommon")

View File

@ -0,0 +1,79 @@
/*
* 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.forge;
import com.flowpowered.math.vector.Vector3d;
import de.bluecolored.bluemap.common.plugin.Plugin;
import de.bluecolored.bluemap.common.plugin.text.Text;
import de.bluecolored.bluemap.common.serverinterface.CommandSource;
import de.bluecolored.bluemap.core.world.World;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.Component;
import java.io.IOException;
import java.util.Optional;
public class ForgeCommandSource implements CommandSource {
private final ForgeMod mod;
private final Plugin plugin;
private final CommandSourceStack delegate;
public ForgeCommandSource(ForgeMod mod, Plugin plugin, CommandSourceStack delegate) {
this.mod = mod;
this.plugin = plugin;
this.delegate = delegate;
}
@Override
public void sendMessage(Text text) {
var component = Component.Serializer.fromJsonLenient(text.toJSONString());
if (component != null)
delegate.sendSuccess(() -> component, false);
}
@Override
public boolean hasPermission(String permission) {
return delegate.hasPermission(1);
}
@Override
public Optional<Vector3d> getPosition() {
var pos = delegate.getPosition();
return Optional.of(new Vector3d(pos.x, pos.y, pos.z));
}
@Override
public Optional<World> getWorld() {
try {
var serverWorld = mod.getWorld(delegate.getLevel());
String worldId = plugin.getBlueMap().getWorldId(serverWorld.getSaveFolder());
return Optional.ofNullable(plugin.getWorlds().get(worldId));
} catch (IOException ignore) {}
return Optional.empty();
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.forge;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
public class ForgeEventForwarder {
private final Collection<ServerEventListener> eventListeners;
public ForgeEventForwarder() {
this.eventListeners = new ArrayList<>(1);
NeoForge.EVENT_BUS.register(this);
}
public synchronized void addEventListener(ServerEventListener listener) {
this.eventListeners.add(listener);
}
public synchronized void removeAllListeners() {
this.eventListeners.clear();
}
@SubscribeEvent
public synchronized void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent evt) {
UUID uuid = evt.getEntity().getUUID();
for (ServerEventListener listener : eventListeners) listener.onPlayerJoin(uuid);
}
@SubscribeEvent
public synchronized void onPlayerLeave(PlayerEvent.PlayerLoggedOutEvent evt) {
UUID uuid = evt.getEntity().getUUID();
for (ServerEventListener listener : eventListeners) listener.onPlayerLeave(uuid);
}
}

View File

@ -0,0 +1,268 @@
/*
* 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.forge;
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.serverinterface.Player;
import de.bluecolored.bluemap.common.serverinterface.ServerEventListener;
import de.bluecolored.bluemap.common.serverinterface.ServerInterface;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import de.bluecolored.bluemap.core.BlueMap;
import de.bluecolored.bluemap.core.MinecraftVersion;
import de.bluecolored.bluemap.core.logger.Logger;
import net.minecraft.SharedConstants;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.IExtensionPoint;
import net.neoforged.fml.ModLoadingContext;
import net.neoforged.fml.common.Mod;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.neoforge.event.TickEvent;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.server.ServerStartedEvent;
import net.neoforged.neoforge.event.server.ServerStartingEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import net.neoforged.neoforge.network.NetworkConstants;
import org.apache.logging.log4j.LogManager;
import java.io.IOException;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Mod(Plugin.PLUGIN_ID)
public class ForgeMod implements ServerInterface {
private final Plugin pluginInstance;
private MinecraftServer serverInstance = null;
private final ForgeEventForwarder eventForwarder;
private final LoadingCache<ServerLevel, ServerWorld> worlds;
private int playerUpdateIndex = 0;
private final Map<UUID, Player> onlinePlayerMap;
private final List<ForgePlayer> onlinePlayerList;
public ForgeMod() {
Logger.global.clear();
Logger.global.put(new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME)));
this.onlinePlayerMap = new ConcurrentHashMap<>();
this.onlinePlayerList = Collections.synchronizedList(new ArrayList<>());
this.pluginInstance = new Plugin("neoforge-1.20.2", this);
this.eventForwarder = new ForgeEventForwarder();
this.worlds = Caffeine.newBuilder()
.executor(BlueMap.THREAD_POOL)
.weakKeys()
.maximumSize(1000)
.build(ForgeWorld::new);
NeoForge.EVENT_BUS.register(this);
//Make sure the mod being absent on the other network side does not cause the client to display the server as incompatible
ModLoadingContext.get().registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(() -> NetworkConstants.IGNORESERVERONLY, (a, b) -> true));
}
@SubscribeEvent
public void onServerStarting(ServerStartingEvent event) {
this.serverInstance = event.getServer();
}
@SubscribeEvent
public void onRegisterCommands(RegisterCommandsEvent event) {
//register commands
new Commands<>(pluginInstance, event.getDispatcher(), forgeSource ->
new ForgeCommandSource(this, pluginInstance, forgeSource)
);
}
@SubscribeEvent
public void onServerStarted(ServerStartedEvent event) {
//save worlds to generate level.dat files
serverInstance.saveAllChunks(false, true, true);
new Thread(() -> {
Logger.global.logInfo("Loading...");
try {
pluginInstance.load();
if (pluginInstance.isLoaded()) Logger.global.logInfo("Loaded!");
} catch (IOException e) {
Logger.global.logError("Failed to load bluemap!", e);
pluginInstance.unload();
}
}, "BlueMap-Plugin-Loading").start();
}
@SubscribeEvent
public void onServerStopping(ServerStoppingEvent event) {
pluginInstance.unload();
Logger.global.logInfo("BlueMap unloaded!");
}
@SubscribeEvent
public void onTick(TickEvent.ServerTickEvent evt) {
updateSomePlayers();
}
@Override
public MinecraftVersion getMinecraftVersion() {
try {
return MinecraftVersion.of(SharedConstants.getCurrentVersion().getId());
} catch (IllegalArgumentException ex) {
return MinecraftVersion.LATEST_SUPPORTED;
}
}
@Override
public void registerListener(ServerEventListener listener) {
eventForwarder.addEventListener(listener);
}
@Override
public void unregisterAllListeners() {
eventForwarder.removeAllListeners();
}
@Override
public Collection<ServerWorld> getLoadedWorlds() {
Collection<ServerWorld> loadedWorlds = new ArrayList<>(3);
for (ServerLevel serverWorld : serverInstance.getAllLevels()) {
loadedWorlds.add(worlds.get(serverWorld));
}
return loadedWorlds;
}
@SuppressWarnings("unchecked")
@Override
public Optional<ServerWorld> getWorld(Object world) {
if (world instanceof Path)
return getWorld((Path) world);
if (world instanceof String) {
ResourceLocation resourceLocation = ResourceLocation.tryParse((String) world);
if (resourceLocation != null) world = serverInstance.getLevel(ResourceKey.create(Registries.DIMENSION, resourceLocation));
}
if (world instanceof ResourceKey) {
try {
world = serverInstance.getLevel((ResourceKey<Level>) world);
} catch (ClassCastException ignored) {}
}
if (world instanceof ServerLevel)
return Optional.of(getWorld((ServerLevel) world));
return Optional.empty();
}
public ServerWorld getWorld(ServerLevel world) {
return worlds.get(world);
}
@Override
public Path getConfigFolder() {
return Path.of("config", "bluemap");
}
@Override
public Optional<Path> getModsFolder() {
return Optional.of(Path.of("mods"));
}
@SubscribeEvent
public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent evt) {
var playerInstance = evt.getEntity();
if (!(playerInstance instanceof ServerPlayer)) return;
ForgePlayer player = new ForgePlayer(playerInstance.getUUID(), this);
onlinePlayerMap.put(player.getUuid(), player);
onlinePlayerList.add(player);
}
@SubscribeEvent
public void onPlayerLeave(PlayerEvent.PlayerLoggedOutEvent evt) {
var player = evt.getEntity();
if (!(player instanceof ServerPlayer)) return;
UUID playerUUID = player.getUUID();
onlinePlayerMap.remove(playerUUID);
synchronized (onlinePlayerList) {
onlinePlayerList.removeIf(p -> p.getUuid().equals(playerUUID));
}
}
public MinecraftServer getServer() {
return this.serverInstance;
}
public Plugin getPlugin() {
return this.pluginInstance;
}
@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,172 @@
/*
* 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.forge;
import com.flowpowered.math.vector.Vector3d;
import de.bluecolored.bluemap.common.plugin.text.Text;
import de.bluecolored.bluemap.common.serverinterface.Gamemode;
import de.bluecolored.bluemap.common.serverinterface.Player;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.phys.Vec3;
import java.io.IOException;
import java.util.EnumMap;
import java.util.Map;
import java.util.UUID;
public class ForgePlayer implements Player {
private static final Map<GameType, Gamemode> GAMEMODE_MAP = new EnumMap<>(GameType.class);
static {
GAMEMODE_MAP.put(GameType.ADVENTURE, Gamemode.ADVENTURE);
GAMEMODE_MAP.put(GameType.SURVIVAL, Gamemode.SURVIVAL);
GAMEMODE_MAP.put(GameType.CREATIVE, Gamemode.CREATIVE);
GAMEMODE_MAP.put(GameType.SPECTATOR, Gamemode.SPECTATOR);
}
private final UUID uuid;
private Text name;
private String world;
private Vector3d position;
private Vector3d rotation;
private int skyLight;
private int blockLight;
private boolean online;
private boolean sneaking;
private boolean invisible;
private Gamemode gamemode;
private final ForgeMod mod;
public ForgePlayer(UUID playerUuid, ForgeMod mod) {
this.uuid = playerUuid;
this.mod = mod;
update();
}
@Override
public UUID getUuid() {
return this.uuid;
}
@Override
public Text getName() {
return this.name;
}
@Override
public String getWorld() {
return this.world;
}
@Override
public Vector3d getPosition() {
return this.position;
}
@Override
public Vector3d getRotation() {
return rotation;
}
@Override
public int getSkyLight() {
return skyLight;
}
@Override
public int getBlockLight() {
return blockLight;
}
@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;
}
ServerPlayer player = server.getPlayerList().getPlayer(uuid);
if (player == null) {
this.online = false;
return;
}
this.gamemode = GAMEMODE_MAP.getOrDefault(player.gameMode.getGameModeForPlayer(), Gamemode.SURVIVAL);
if (this.gamemode == null) this.gamemode = Gamemode.SURVIVAL;
MobEffectInstance invis = player.getEffect(MobEffects.INVISIBILITY);
this.invisible = invis != null && invis.getDuration() > 0;
this.name = Text.of(player.getName().getString());
this.online = true;
Vec3 pos = player.getPosition(1f);
this.position = new Vector3d(pos.x(), pos.y(), pos.z());
this.rotation = new Vector3d(player.getXRot(), player.getYHeadRot(), 0);
this.sneaking = player.isCrouching();
this.skyLight = player.level().getChunkSource().getLightEngine().getLayerListener(LightLayer.SKY).getLightValue(new BlockPos(player.getBlockX(), player.getBlockY(), player.getBlockZ()));
this.blockLight = player.level().getChunkSource().getLightEngine().getLayerListener(LightLayer.BLOCK).getLightValue(new BlockPos(player.getBlockX(), player.getBlockY(), player.getBlockZ()));
try {
var world = mod.getWorld(player.level()).orElse(null);
this.world = world != null ? mod.getPlugin().getBlueMap().getWorldId(world.getSaveFolder()) : "unknown";
} catch (IOException | NullPointerException e) { // NullPointerException -> the plugin isn't fully loaded
this.world = "unknown";
}
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.forge;
import de.bluecolored.bluemap.common.serverinterface.Dimension;
import de.bluecolored.bluemap.common.serverinterface.ServerWorld;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.storage.LevelResource;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.nio.file.Path;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
public class ForgeWorld implements ServerWorld {
private final WeakReference<ServerLevel> delegate;
private final Path saveFolder;
public ForgeWorld(ServerLevel delegate) {
this.delegate = new WeakReference<>(delegate);
MinecraftServer server = delegate.getServer();
Path worldFolder = delegate.getServer().getServerDirectory().toPath().resolve(server.getWorldPath(LevelResource.ROOT));
this.saveFolder = DimensionType.getStorageFolder(delegate.dimension(), worldFolder)
.toAbsolutePath().normalize();
}
@Override
public Dimension getDimension() {
ServerLevel world = delegate.get();
if (world != null) {
if (world.dimension().equals(Level.NETHER)) return Dimension.NETHER;
if (world.dimension().equals(Level.END)) return Dimension.END;
if (world.dimension().equals(Level.OVERWORLD)) return Dimension.OVERWORLD;
}
return ServerWorld.super.getDimension();
}
@Override
public boolean persistWorldChanges() throws IOException {
ServerLevel world = delegate.get();
if (world == null) return false;
var taskResult = CompletableFuture.supplyAsync(() -> {
try {
world.save(null, true, false);
return true;
} catch (Exception e) {
throw new CompletionException(e);
}
}, world.getServer());
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 Path getSaveFolder() {
return this.saveFolder;
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.forge;
import de.bluecolored.bluemap.core.logger.AbstractLogger;
import org.apache.logging.log4j.Logger;
public class Log4jLogger extends AbstractLogger {
private final 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,22 @@
modLoader="javafml"
loaderVersion="${loader_version_range}"
license="${mod_license}"
[[mods]]
modId="${mod_id}"
version="${mod_version}"
displayName="${mod_name}"
description='''${mod_description}'''
[[dependencies.${mod_id}]] #optional
modId="neoforge"
mandatory=true
versionRange="${neo_version_range}"
ordering="NONE"
side="BOTH"
[[dependencies.${mod_id}]]
modId="minecraft"
mandatory=true
versionRange="${minecraft_version_range}"
ordering="NONE"
side="BOTH"

View File

@ -0,0 +1,8 @@
{
"pack": {
"description": {
"text": "${mod_id} resources"
},
"pack_format": ${pack_format_number}
}
}

View File

@ -19,6 +19,8 @@ includeBuild("implementations/forge-1.18.1")
includeBuild("implementations/forge-1.19.4")
includeBuild("implementations/forge-1.20")
includeBuild("implementations/neoforge-1.20.2")
includeBuild("implementations/spigot")
includeBuild("implementations/paper")