mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-13 06:14:30 +01:00
Add neoforge implementation
This commit is contained in:
parent
3f82a821a2
commit
c7f340dec3
@ -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"))
|
||||
}
|
||||
|
||||
|
169
implementations/neoforge-1.20.2/build.gradle
Normal file
169
implementations/neoforge-1.20.2/build.gradle
Normal 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"))
|
||||
}
|
16
implementations/neoforge-1.20.2/gradle.properties
Normal file
16
implementations/neoforge-1.20.2/gradle.properties
Normal 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
|
15
implementations/neoforge-1.20.2/settings.gradle
Normal file
15
implementations/neoforge-1.20.2/settings.gradle
Normal 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")
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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"
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"pack": {
|
||||
"description": {
|
||||
"text": "${mod_id} resources"
|
||||
},
|
||||
"pack_format": ${pack_format_number}
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user