Build system update (#527)

This commit is contained in:
Articdive 2022-01-01 18:27:52 +01:00 committed by TheMode
parent de817e5e52
commit 3089843cc9
69 changed files with 433 additions and 1325 deletions

7
.gitignore vendored
View File

@ -31,7 +31,7 @@
hs_err_pid*
### Gradle template
.gradle
**/.gradle
**/build/
# Ignore Gradle GUI config
@ -53,5 +53,6 @@ gradle-app.setting
/src/main/java/com/mcecraft/
# When running the demo we generate the extensions folder
/extensions/
/.mixin.out/
# Incase people are using IntelliJ to run the server, this will exclude extensions from any folder.
/demo/extensions
/extensions

View File

@ -0,0 +1,16 @@
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
gradlePluginPortal()
}
dependencies {
val indraVersion = "2.0.6"
implementation("org.jetbrains.kotlin", "kotlin-gradle-plugin", "1.6.10")
implementation("net.kyori", "indra-common", indraVersion)
implementation("net.kyori", "indra-publishing-sonatype", indraVersion)
implementation("org.graalvm.buildtools", "native-gradle-plugin", "0.9.9")
}

View File

@ -0,0 +1,25 @@
plugins {
java
}
// Always exclude checker-qual. This is the single most annoying thing that always reappears.
configurations.all {
// We only use Jetbrains Annotations
exclude("org.checkerframework", "checker-qual")
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
tasks {
withType<JavaCompile> {
// We are fully aware, that we should be suppressing these instead of ignoring them here, but man keep my terminal clean.
options.compilerArgs.addAll(listOf("-Xlint:none", "-Xlint:-deprecation", "-Xlint:-unchecked"))
}
withType<Test> {
useJUnitPlatform()
}
}

View File

@ -0,0 +1,14 @@
plugins {
id("minestom.common-conventions")
id("org.graalvm.buildtools.native")
}
graalvmNative {
binaries {
named("main") {
buildArgs.add("--allow-incomplete-classpath")
// One day toolchains will support getting this automagically, but that day is not today.
toolchainDetection.set(false)
}
}
}

View File

@ -0,0 +1,32 @@
plugins {
id("net.kyori.indra")
id("net.kyori.indra.publishing")
id("net.kyori.indra.publishing.sonatype")
}
indra {
javaVersions {
target(17)
testWith(17)
}
github("Minestom", "Minestom") {
ci(true)
}
apache2License()
configurePublications {
pom {
developers {
developer {
id.set("TheMode")
name.set("TheMode")
}
developer {
id.set("jglrxavpok")
name.set("jglrxavpok")
}
}
}
}
}

View File

@ -1,186 +0,0 @@
import org.gradle.internal.os.OperatingSystem
plugins {
id 'java-library'
id 'maven-publish'
id 'org.jetbrains.kotlin.jvm' version '1.5.31'
//id 'checkstyle'
}
group 'net.minestom.server'
version '1.0'
sourceCompatibility = 17
project.ext.lwjglVersion = "3.2.3"
switch (OperatingSystem.current()) {
case OperatingSystem.LINUX:
def osArch = System.getProperty("os.arch")
project.ext.lwjglNatives = osArch.startsWith("arm") || osArch.startsWith("aarch64")
? "natives-linux-${osArch.contains("64") || osArch.startsWith("armv8") ? "arm64" : "arm32"}"
: "natives-linux"
break
case OperatingSystem.MAC_OS:
project.ext.lwjglNatives = "natives-macos"
break
case OperatingSystem.WINDOWS:
project.ext.lwjglNatives = System.getProperty("os.arch").contains("64") ? "natives-windows" : "natives-windows-x86"
break
}
allprojects {
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
javadoc {
options {
addBooleanOption('html5', true)
links "https://jd.adventure.kyori.net/api/$adventureVersion/"
links "https://docs.oracle.com/en/java/javase/11/docs/api/"
}
// see https://stackoverflow.com/a/56641766
doLast {
// Append the fix to the file
def searchScript = new File(destinationDir, '/search.js')
searchScript.append '\n\n' +
'getURLPrefix = function(ui) {\n' +
' return \'\';\n' +
'};\n'
}
}
//checkstyle {
// toolVersion "8.42"
// configFile file("${projectDir}/minestom_checks.xml")
//}
}
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir 'src/autogenerated/java'
}
}
lwjgl {
java {
srcDir 'src/lwjgl/java'
}
compileClasspath += sourceSets.main.runtimeClasspath
runtimeClasspath += sourceSets.main.runtimeClasspath
}
}
java {
// Minestom uses LWJGL libs as optional dependency if interfacing with a GPU is asked
registerFeature("lwjgl") {
usingSourceSet(sourceSets.lwjgl)
withJavadocJar()
withSourcesJar()
}
withJavadocJar()
withSourcesJar()
}
test {
useJUnitPlatform()
}
tasks.withType(Zip).configureEach {
duplicatesStrategy DuplicatesStrategy.EXCLUDE
}
dependencies {
// Junit Testing Framework
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testRuntimeOnly('org.junit.jupiter:junit-jupiter-engine:5.8.2')
// Only here to ensure J9 module support for extensions and our classloaders
testCompileOnly 'org.mockito:mockito-core:4.2.0'
// https://mvnrepository.com/artifact/it.unimi.dsi/fastutil
api 'it.unimi.dsi:fastutil:8.5.6'
implementation group: 'space.vectrix.flare', name: 'flare', version: '2.0.0'
implementation group: 'space.vectrix.flare', name: 'flare-fastutil', version: '2.0.0'
// https://mvnrepository.com/artifact/com.google.code.gson/gson
api 'com.google.code.gson:gson:2.8.9'
// Noise library for terrain generation
// https://jitpack.io/#Articdive/Jnoise
api 'com.github.Articdive:Jnoise:2.1.0'
// Logging
api 'org.apache.logging.log4j:log4j-core:2.17.0'
// SLF4J is the base logger for most libraries, therefore we can hook it into log4j2.
api 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.0'
// https://mvnrepository.com/artifact/org.jline/jline
implementation group: 'org.jline', name: 'jline', version: '3.20.0'
// https://mvnrepository.com/artifact/org.jline/jline-terminal-jansi
implementation group: 'org.jline', name: 'jline-terminal-jansi', version: '3.20.0'
implementation 'com.github.ben-manes.caffeine:caffeine:3.0.5'
// https://mvnrepository.com/artifact/org.jctools/jctools-core
implementation group: 'org.jctools', name: 'jctools-core', version: '3.3.0'
// Guava 21.0+ required for Mixin
api 'com.google.guava:guava:31.0.1-jre'
// Path finding
api 'com.github.MadMartian:hydrazine-path-finding:1.6.0'
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${project.kotlinVersion}"
api "org.jetbrains.kotlin:kotlin-reflect:${project.kotlinVersion}"
// NBT parsing/manipulation/saving
api("io.github.jglrxavpok.hephaistos:common:${project.hephaistosVersion}")
api("io.github.jglrxavpok.hephaistos:gson:${project.hephaistosVersion}")
/* api("io.github.jglrxavpok.hephaistos:common:${project.hephaistosVersion}") {
capabilities {
requireCapability("io.github.jglrxavpok.hephaistos:Hephaistos-gson")
}
}*/
api "com.github.Minestom:DependencyGetter:v1.0.1"
implementation 'com.github.Minestom:MinestomDataGenerator:801b8007cf'
// Adventure, for user-interface
api "net.kyori:adventure-api:$adventureVersion"
api "net.kyori:adventure-text-serializer-gson:$adventureVersion"
api "net.kyori:adventure-text-serializer-plain:$adventureVersion"
api "net.kyori:adventure-text-serializer-legacy:$adventureVersion"
// LWJGL, for map rendering
lwjglApi platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
lwjglApi "org.lwjgl:lwjgl"
lwjglApi "org.lwjgl:lwjgl-egl"
lwjglApi "org.lwjgl:lwjgl-opengl"
lwjglApi "org.lwjgl:lwjgl-opengles"
lwjglApi "org.lwjgl:lwjgl-glfw"
lwjglApi "org.lwjgl:lwjgl-glfw"
lwjglApi 'org.joml:joml:1.10.2'
lwjglRuntimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
lwjglRuntimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
lwjglRuntimeOnly "org.lwjgl:lwjgl-opengles::$lwjglNatives"
lwjglRuntimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
}
configurations.all {
// we use jetbrains annotations
exclude group: "org.checkerframework", module: "checker-qual"
}
publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
}

84
build.gradle.kts Normal file
View File

@ -0,0 +1,84 @@
plugins {
`java-library`
id("minestom.publishing-conventions")
id("minestom.native-conventions")
}
allprojects {
group = "net.minestom.server"
version = "1.0"
description = "Lightweight and multi-threaded Minecraft server implementation"
}
sourceSets {
main {
java {
srcDir(file("src/autogenerated/java"))
}
}
}
java {
withJavadocJar()
withSourcesJar()
}
tasks {
withType<Javadoc> {
(options as? StandardJavadocDocletOptions)?.apply {
encoding = "UTF-8"
// Custom options
addBooleanOption("html5", true)
addStringOption("-release", "17")
// Links to external javadocs
links("https://docs.oracle.com/en/java/javase/17/docs/api/")
links("https://jd.adventure.kyori.net/api/${libs.versions.adventure.get()}/")
}
}
withType<Zip> {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
dependencies {
// Junit Testing Framework
testImplementation(libs.junit.api)
testRuntimeOnly(libs.junit.engine)
// Only here to ensure J9 module support for extensions and our classloaders
testCompileOnly(libs.mockito.core)
// Logging
implementation(libs.bundles.logging)
// Libraries required for the terminal
implementation(libs.bundles.terminal)
// Performance improving libraries
implementation(libs.caffeine)
api(libs.fastutil)
implementation(libs.bundles.flare)
// Libraries
api(libs.guava)
api(libs.gson)
implementation(libs.jcTools)
// Path finding
api(libs.hydrazine)
// Adventure, for user-interface
api(libs.bundles.adventure)
// Kotlin Libraries
api(libs.bundles.kotlin)
// Extension Management System dependency handler.
api(libs.dependencyGetter)
// Minestom Data (From MinestomDataGenerator)
implementation(libs.minestomData)
// NBT parsing/manipulation/saving
api("io.github.jglrxavpok.hephaistos:common:${libs.versions.hephaistos.get()}")
api("io.github.jglrxavpok.hephaistos:gson:${libs.versions.hephaistos.get()}")
}

View File

@ -1,39 +0,0 @@
plugins {
id 'java'
id 'application'
// Used to download our data
}
group 'net.minestom.server'
version '1.0'
sourceCompatibility = 17
application {
mainClass.set("net.minestom.codegen.Generators")
}
repositories {
}
dependencies {
implementation 'com.google.code.gson:gson:2.8.7'
implementation 'org.jetbrains:annotations:21.0.1'
implementation 'com.squareup:javapoet:1.13.0'
// Logging
implementation 'org.apache.logging.log4j:log4j-core:2.14.1'
// SLF4J is the base logger for most libraries, therefore we can hook it into log4j2.
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.14.1'
// Contains the json files
implementation 'com.github.Minestom:MinestomDataGenerator:801b8007cf'
}
run {
// Update version
setArgs(List.of(
// Points to src/autogenerated/java
project.rootProject.projectDir.getPath() + "${File.separatorChar}src${File.separatorChar}autogenerated${File.separatorChar}java"
) as List<String>
)
}

View File

@ -0,0 +1,24 @@
plugins {
application
id("minestom.common-conventions")
}
application {
mainClass.set("net.minestom.codegen.Generators")
}
dependencies {
implementation(libs.gson)
implementation(libs.jetbrainsAnnotations)
implementation(libs.javaPoet)
// Logging
implementation(libs.bundles.logging)
// Contains the json files
implementation(libs.minestomData)
}
tasks {
getByName<JavaExec>("run") {
args = listOf(project.rootProject.projectDir.resolve("src").resolve("autogenerated").resolve("java").absolutePath)
}
}

18
demo/build.gradle.kts Normal file
View File

@ -0,0 +1,18 @@
plugins {
application
id("minestom.common-conventions")
id("minestom.native-conventions")
id("com.github.johnrengelman.shadow") version("7.1.1")
}
application {
mainClass.set("net.minestom.demo.Main")
// This is included because Shadow is buggy. Wait for https://github.com/johnrengelman/shadow/issues/613 to befixed.
@Suppress("DEPRECATION")
mainClassName = "net.minestom.demo.Main"
}
dependencies {
implementation(rootProject)
implementation(libs.jNoise)
}

View File

@ -1,11 +1,11 @@
package demo;
package net.minestom.demo;
import demo.commands.*;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.minestom.demo.commands.*;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandManager;
import net.minestom.server.event.server.ServerListPingEvent;
@ -31,7 +31,6 @@ public class Main {
CommandManager commandManager = MinecraftServer.getCommandManager();
commandManager.register(new TestCommand());
commandManager.register(new GamemodeCommand());
commandManager.register(new EntitySelectorCommand());
commandManager.register(new HealthCommand());
commandManager.register(new LegacyCommand());

View File

@ -1,4 +1,4 @@
package demo;
package net.minestom.demo;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;

View File

@ -1,7 +1,7 @@
package demo;
package net.minestom.demo;
import demo.generator.ChunkGeneratorDemo;
import demo.generator.NoiseTestGenerator;
import net.minestom.demo.generator.ChunkGeneratorDemo;
import net.minestom.demo.generator.NoiseTestGenerator;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.audience.Audiences;

View File

@ -1,4 +1,4 @@
package demo.block;
package net.minestom.demo.block;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.item.ItemStack;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.command.builder.Command;
import net.minestom.server.entity.Entity;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.inventory.Book;
import net.kyori.adventure.text.Component;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.builder.Command;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identity;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.command.builder.Command;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.command.CommandSender;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.command.CommandSender;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.command.CommandSender;
import net.minestom.server.entity.Player;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.minecraft.ArgumentBlockState;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.command.CommandSender;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandSender;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.minestom.server.command.CommandSender;

View File

@ -1,4 +1,4 @@
package demo.commands;
package net.minestom.demo.commands;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.title.Title;

View File

@ -1,4 +1,4 @@
package demo.entity;
package net.minestom.demo.entity;
import com.google.common.collect.ImmutableList;
import net.minestom.server.attribute.Attribute;

View File

@ -1,4 +1,4 @@
package demo.entity;
package net.minestom.demo.entity;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;

View File

@ -1,4 +1,4 @@
package demo.generator;
package net.minestom.demo.generator;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.ChunkGenerator;

View File

@ -1,4 +1,4 @@
package demo.generator;
package net.minestom.demo.generator;
import de.articdive.jnoise.JNoise;
import de.articdive.jnoise.interpolation.InterpolationType;

View File

@ -1,4 +1,4 @@
package demo.generator;
package net.minestom.demo.generator;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec;

View File

@ -1,6 +0,0 @@
# Update this version with every release. It is purely used for the code generator and data dependency.
mcVersion = 1.17
hephaistosVersion=2.3.2
kotlinVersion=1.5.31
adventureVersion=4.9.3

90
gradle/libs.versions.toml Normal file
View File

@ -0,0 +1,90 @@
metadata.format.version = "1.1"
[versions]
# Important dependencies
adventure = "4.9.3"
kotlin = "1.6.10"
hydrazine = "1.7.2"
dependencyGetter = "v1.0.1"
minestomData = "801b8007cf"
hephaistos = "2.3.2"
jetbrainsAnnotations = "23.0.0"
# Terminal / Logging
tinylog = "2.4.1"
jline = "3.21.0"
# Performance / Data Structures
caffeine = "3.0.5"
fastutil = "8.5.6"
flare = "2.0.0"
gson = "2.8.9"
guava = "31.0.1-jre"
jcTools = "3.3.0"
# Code Generation
javaPoet = "1.13.0"
# Demo
jNoise = "3.0.1"
# Test
junit-jupiter = "5.8.2"
mockito = "4.2.0"
[libraries]
# Important Dependencies
# Adventure
adventure-api = { group = "net.kyori", name = "adventure-api", version.ref = "adventure" }
adventure-serializer-gson = { group = "net.kyori", name = "adventure-text-serializer-gson", version.ref = "adventure" }
adventure-serializer-legacy = { group = "net.kyori", name = "adventure-text-serializer-legacy", version.ref = "adventure" }
adventure-serializer-plain = { group = "net.kyori", name = "adventure-text-serializer-plain", version.ref = "adventure" }
# Kotlin
kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" }
kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" }
# Miscellaneous
hydrazine = { group = "com.github.MadMartian", name = "hydrazine-path-finding", version.ref = "hydrazine" }
dependencyGetter = { group = "com.github.Minestom", name = "DependencyGetter", version.ref = "dependencyGetter" }
minestomData = { group = "com.github.Minestom", name = "MinestomDataGenerator", version.ref = "minestomData" }
jetbrainsAnnotations = { group = "org.jetbrains", name = "annotations", version.ref = "jetbrainsAnnotations" }
# Logging
tinylog-api = { group = "org.tinylog", name = "tinylog-api", version.ref = "tinylog" }
tinylog-impl = { group = "org.tinylog", name = "tinylog-impl", version.ref = "tinylog" }
tinylog-slf4j = { group = "org.tinylog", name = "slf4j-tinylog", version.ref = "tinylog" }
# Terminal
jline = { group = "org.jline", name = "jline", version.ref = "jline"}
jline-jansi = { group = "org.jline", name = "jline-terminal-jansi", version.ref = "jline" }
# Performance / Data Structures
caffeine = { group = "com.github.ben-manes.caffeine", name = "caffeine", version.ref = "caffeine" }
fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" }
flare = { group = "space.vectrix.flare", name = "flare-fastutil", version.ref = "flare"}
flare-fastutil = { group = "space.vectrix.flare", name = "flare", version.ref = "flare"}
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
jcTools = { group = "org.jctools", name = "jctools-core", version.ref = "jcTools"}
# Test
junit-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit-jupiter" }
junit-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit-jupiter" }
mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito" }
# Code Generation
javaPoet = { group = "com.squareup", name = "javapoet", version.ref = "javaPoet" }
# Demo
jNoise = { group = "com.github.Articdive", name = "JNoise", version.ref = "jNoise" }
[bundles]
kotlin = ["kotlin-stdlib-jdk8", "kotlin-reflect"]
flare = ["flare", "flare-fastutil"]
adventure = ["adventure-api", "adventure-serializer-gson", "adventure-serializer-legacy", "adventure-serializer-plain"]
logging = ["tinylog-api", "tinylog-impl", "tinylog-slf4j"]
terminal = ["jline", "jline-jansi"]

View File

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

10
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright ? 2015-2021 the original authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -32,10 +32,10 @@
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions <EFBFBD>á$var<61>â, <20>á${var}<7D>â, <20>á${var:-default}<7D>â, <20>á${var+SET}<7D>â,
# <EFBFBD>á${var#prefix}<7D>â, <20>á${var%suffix}<7D>â, and <20>á$( cmd )<29>â;
# * compound commands having a testable exit status, especially <EFBFBD>ácase<EFBFBD>â;
# * various built-in commands including <EFBFBD>ácommand<EFBFBD>â, <20>áset<65>â, and <20>áulimit<69>â.
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#

View File

@ -0,0 +1,8 @@
plugins {
id("me.champeau.jmh") version ("0.6.6")
id("minestom.common-conventions")
}
dependencies {
implementation(rootProject)
}

View File

@ -0,0 +1,47 @@
package net.minestom.jmh.event;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventNode;
import net.minestom.server.event.ListenerHandle;
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@Warmup(iterations = 5, time = 1500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 1500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class SingleNodeBenchmark {
@Param({"0", "1", "2", "3", "5", "10"})
public int listenerCount;
private EventNode<Event> node;
private ListenerHandle<TestEvent> handle;
record TestEvent() implements Event {
}
@Setup
public void setup() {
node = EventNode.all("node");
for (int i = 0; i < listenerCount; i++) {
node.addListener(TestEvent.class, testEvent -> {
// Empty
});
}
this.handle = node.getHandle(TestEvent.class);
}
@Benchmark
public void call() {
node.call(new TestEvent());
}
@Benchmark
public void handleCall() {
handle.call(new TestEvent());
}
}

View File

@ -1,2 +0,0 @@
rootProject.name = 'Minestom'
include 'code-generators'

22
settings.gradle.kts Normal file
View File

@ -0,0 +1,22 @@
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
enableFeaturePreview("VERSION_CATALOGS")
dependencyResolutionManagement {
repositories {
maven("https://jitpack.io")
mavenCentral()
}
}
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
includeBuild("build-logic")
}
rootProject.name = "Minestom"
include("code-generators")
include("jmh-benchmarks")
include("demo")

View File

@ -1,6 +0,0 @@
# Minestom LWJGL code
Here is all LWJGL-related code in Minestom.
Accessible when using "lwjgl" as an optional dependency in Gradle when declaring Minestom as a dependency
Go to [LWJGL Minestom Example](https://github.com/Minestom/LWJGL-Example) to see in details how to use.

View File

@ -1,129 +0,0 @@
package net.minestom.demo.largeframebuffers;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.metadata.other.ItemFrameMeta;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.metadata.MapMeta;
import net.minestom.server.map.Framebuffer;
import net.minestom.server.map.LargeFramebuffer;
import net.minestom.server.map.MapColors;
import net.minestom.server.map.framebuffers.LargeDirectFramebuffer;
import net.minestom.server.map.framebuffers.LargeGLFWFramebuffer;
import net.minestom.server.map.framebuffers.LargeGraphics2DFramebuffer;
import net.minestom.server.map.framebuffers.MapColorRenderer;
import net.minestom.server.network.packet.server.play.MapDataPacket;
import net.minestom.server.utils.time.TimeUnit;
import java.awt.*;
import java.util.Arrays;
import java.util.function.Consumer;
public class Demo {
public static void main(String[] args) {
MainDemo.main(args); // used to avoid code duplication
initDemo();
}
private static void initDemo() {
InstanceManager instances = MinecraftServer.getInstanceManager();
Instance instance = instances.getInstances().stream().findAny().get();
LargeDirectFramebuffer directFramebuffer = new LargeDirectFramebuffer(512, 512);
LargeGraphics2DFramebuffer graphics2DFramebuffer = new LargeGraphics2DFramebuffer(512, 512);
LargeGLFWFramebuffer glfwFramebuffer = new LargeGLFWFramebuffer(512, 512);
glfwFramebuffer.changeRenderingThreadToCurrent();
OpenGLRendering.init();
MapColorRenderer renderer = new MapColorRenderer(glfwFramebuffer, OpenGLRendering::render);
glfwFramebuffer.unbindContextFromThread();
// renderingLoop(0, directFramebuffer, Demo::directRendering);
// renderingLoop(101, graphics2DFramebuffer, Demo::graphics2DRendering);
renderingLoop(201, glfwFramebuffer, f -> {
});
glfwFramebuffer.setupRenderLoop(15, TimeUnit.MILLISECOND, renderer);
for (int x = -2; x <= 2; x++) {
for (int z = -2; z <= 2; z++) {
instance.loadChunk(x, z);
}
}
setupMaps(instance, 0, 10);
setupMaps(instance, 101, 20);
setupMaps(instance, 201, 30);
}
private static void createFrame(Instance instance, int id, int x, int y, int z) {
Entity itemFrame = new Entity(EntityType.ITEM_FRAME);
ItemFrameMeta itemFrameMeta = (ItemFrameMeta) itemFrame.getEntityMeta();
itemFrameMeta.setNotifyAboutChanges(false);
itemFrameMeta.setOrientation(ItemFrameMeta.Orientation.NORTH);
ItemStack map = ItemStack.builder(Material.FILLED_MAP)
.meta(new MapMeta.Builder().mapId(id).build())
.build();
itemFrameMeta.setItem(map);
itemFrameMeta.setCustomNameVisible(true);
itemFrameMeta.setCustomName(Component.text("MapID: " + id));
itemFrameMeta.setNotifyAboutChanges(true);
itemFrame.setInstance(instance, new Pos(x, y, z, 180, 0));
}
private static void setupMaps(Instance instance, int mapIDStart, int zCoordinate) {
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
createFrame(instance, mapIDStart + y * 4 + x, 2 - x, 45 - y, zCoordinate);
}
}
}
private static <T extends LargeFramebuffer> void renderingLoop(int mapIDStart, T framebuffer, Consumer<T> renderingCode) {
final Framebuffer[] subviews = new Framebuffer[4 * 4];
for (int i = 0; i < subviews.length; i++) {
int x = (i % 4) * 128;
int y = (i / 4) * 128;
subviews[i] = framebuffer.createSubView(x, y);
}
MinecraftServer.getSchedulerManager().buildTask(() -> {
renderingCode.accept(framebuffer);
for (int i = 0; i < subviews.length; i++) {
Framebuffer f = subviews[i];
MapDataPacket packet = f.preparePacket(mapIDStart + i);
sendPacket(packet);
}
}).repeat(15, TimeUnit.MILLISECOND).schedule();
}
private static void sendPacket(MapDataPacket packet) {
MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(p -> p.getPlayerConnection().sendPacket(packet));
}
private static void directRendering(LargeDirectFramebuffer framebuffer) {
Arrays.fill(framebuffer.getColors(), 0, 512 * 40 + 128, MapColors.COLOR_CYAN.baseColor());
Arrays.fill(framebuffer.getColors(), 512 * 40 + 128, framebuffer.getColors().length, MapColors.COLOR_RED.baseColor());
}
private static void graphics2DRendering(LargeGraphics2DFramebuffer framebuffer) {
Graphics2D renderer = framebuffer.getRenderer();
renderer.setColor(Color.BLACK);
renderer.clearRect(0, 0, 512, 512);
renderer.setColor(Color.WHITE);
renderer.drawString("Here's a very very long string that needs multiple maps to fit", 0, 100);
}
}

View File

@ -1,70 +0,0 @@
package net.minestom.demo.largeframebuffers;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.instance.*;
import net.minestom.server.instance.batch.ChunkBatch;
import net.minestom.server.instance.block.Block;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class MainDemo {
public static void main(String[] args) {
// Initialization
MinecraftServer minecraftServer = MinecraftServer.init();
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
// Create the instance
InstanceContainer instanceContainer = instanceManager.createInstanceContainer();
// Set the ChunkGenerator
instanceContainer.setChunkGenerator(new GeneratorDemo());
// Enable the auto chunk loading (when players come close)
instanceContainer.enableAutoChunkLoad(true);
// Add event listeners
GlobalEventHandler globalEventHandler = MinecraftServer.getGlobalEventHandler();
// Set the spawning instance
globalEventHandler.addListener(PlayerLoginEvent.class, event -> {
Player player = event.getPlayer();
event.setSpawningInstance(instanceContainer);
player.setRespawnPoint(new Pos(0, 45, 0));
});
// Teleport the player at spawn
globalEventHandler.addListener(PlayerSpawnEvent.class, event -> {
Player player = event.getPlayer();
player.teleport(new Pos(0, 45, 0));
player.setGameMode(GameMode.CREATIVE);
});
// Start the server
minecraftServer.start("localhost", 25565);
}
private static class GeneratorDemo implements ChunkGenerator {
@Override
public void generateChunkData(@NotNull ChunkBatch batch, int chunkX, int chunkZ) {
// Set chunk blocks
for (byte x = 0; x < Chunk.CHUNK_SIZE_X; x++)
for (byte z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
for (byte y = 0; y < 40; y++) {
batch.setBlock(x, y, z, Block.STONE);
}
}
}
@Override
public List<ChunkPopulator> getPopulators() {
return null;
}
}
}

View File

@ -1,203 +0,0 @@
package net.minestom.demo.largeframebuffers;
import org.joml.Matrix4f;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GLUtil;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.util.stream.Collectors;
import static org.lwjgl.opengl.GL20.*;
public final class OpenGLRendering {
private static int vbo;
private static int indexBuffer;
private static final int VERTEX_SIZE = 5*4; // position + tex
// array of vertices (order: X,Y,Z, Tex U, Tex V)
private static float[] vertices = {
// front face
-1f, -1f, -1f, 0, 0,
1f, -1f, -1f, 1, 0,
1f, 1f, -1f, 1, 1,
-1f, 1f, -1f, 0, 1,
// back face
-1f, -1f, 1f, 0, 1,
1f, -1f, 1f, 1, 1,
1f, 1f, 1f, 1, 0,
-1f, 1f, 1f, 0, 0,
};
private static int[] indices = {
// south face
0,1,2,
2,3,0,
// north face
4,5,6,
6,7,4,
// west face
0,4,7,
7,3,0,
// east face
1,5,6,
6,2,1,
// top face
3, 2, 6,
6, 7, 3
};
private static int renderShader;
private static Matrix4f projectionMatrix;
private static Matrix4f viewMatrix;
private static Matrix4f modelMatrix;
private static int projectionUniform;
private static int viewUniform;
private static int modelUniform;
private static int boxTexture;
static void init() {
GLUtil.setupDebugMessageCallback();
boxTexture = loadTexture("box");
vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
indexBuffer = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
// prepare matrices and shader
renderShader = glCreateProgram();
projectionMatrix = new Matrix4f().setPerspective((float) (Math.PI/4f), 1f, 0.001f, 100f);
viewMatrix = new Matrix4f().setLookAt(5f, 5f, 5f, 0, 0, 0, 0, -1, 0);
modelMatrix = new Matrix4f().identity();
int vertexShader = createShader("/shaders/vertex.glsl", GL_VERTEX_SHADER);
int fragmentShader = createShader("/shaders/fragment.glsl", GL_FRAGMENT_SHADER);
glAttachShader(renderShader, vertexShader);
glAttachShader(renderShader, fragmentShader);
glLinkProgram(renderShader);
if(glGetProgrami(renderShader, GL_LINK_STATUS) == 0) {
System.err.println("Link error: "+glGetProgramInfoLog(renderShader));
}
projectionUniform = glGetUniformLocation(renderShader, "projection");
viewUniform = glGetUniformLocation(renderShader, "view");
modelUniform = glGetUniformLocation(renderShader, "model");
int boxUniform = glGetUniformLocation(renderShader, "box");
glUseProgram(renderShader); {
uploadMatrix(projectionUniform, projectionMatrix);
uploadMatrix(viewUniform, viewMatrix);
glUniform1i(boxUniform, 0); // texture unit 0
}
glUseProgram(0);
}
private static int loadTexture(String filename) {
int tex = glGenTextures();
glBindTexture(GL_TEXTURE_2D, tex);
BufferedImage image;
try {
image = ImageIO.read(OpenGLRendering.class.getResourceAsStream("/textures/"+filename+".png"));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Missing image "+filename, e);
}
ByteBuffer pixels = BufferUtils.createByteBuffer(image.getWidth()*image.getHeight()*4);
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int rgb = image.getRGB(x, y);
int alpha = (rgb >> 24) & 0xFF;
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
pixels.put((byte) red);
pixels.put((byte) green);
pixels.put((byte) blue);
pixels.put((byte) alpha);
}
}
pixels.flip();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// closest neighbor required here, as pixels can have very different rgb values, and interpolation will break palette lookup
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
return tex;
}
private static void uploadMatrix(int uniform, Matrix4f matrix) {
float[] values = new float[4*4];
matrix.get(values);
glUniformMatrix4fv(uniform, false, values);
}
private static int createShader(String filename, int type) {
int shader = glCreateShader(type);
try(BufferedReader reader = new BufferedReader(new InputStreamReader(OpenGLRendering.class.getResourceAsStream(filename)))) {
String source = reader.lines().collect(Collectors.joining("\n"));
glShaderSource(shader, source);
glCompileShader(shader);
} catch (IOException e) {
e.printStackTrace();
}
return shader;
}
private static long lastTime = System.currentTimeMillis();
private static int frame = 0;
static void render() {
if(frame % 100 == 0) {
long time = System.currentTimeMillis();
long dt = time-lastTime;
System.out.println(">> Render time for 100 frames: "+dt);
System.out.println(">> Average time per frame: "+(dt/100.0));
System.out.println(">> Average FPS: "+(1000.0/(dt/100.0)));
lastTime = time;
}
frame++;
glClearColor(0f, 0f, 0f, 1f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
modelMatrix.rotateY((float) (Math.PI/60f));
glUseProgram(renderShader); {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, boxTexture);
uploadMatrix(modelUniform, modelMatrix);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, VERTEX_SIZE, 0); // position
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, false, VERTEX_SIZE, 3*4); // color
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glDrawElements(GL_TRIANGLES, indices.length, GL_UNSIGNED_INT, 0);
}
glUseProgram(0);
}
}

View File

@ -1,42 +0,0 @@
package net.minestom.server.map;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class PaletteGenerator {
public static void main(String[] args) {
Int2IntMap colors = new Int2IntOpenHashMap();
int highestIndex = 0;
for(MapColors c : MapColors.values()) {
if (c == MapColors.NONE)
continue;
for(MapColors.Multiplier m : MapColors.Multiplier.values()) {
int index = ((int)m.apply(c)) & 0xFF;
if(index > highestIndex) {
highestIndex = index;
}
int rgb = MapColors.PreciseMapColor.toRGB(c, m);
colors.put(index, rgb);
}
}
BufferedImage paletteTexture = new BufferedImage(highestIndex+1, 1, BufferedImage.TYPE_INT_ARGB);
for (int i = 0; i <= highestIndex; i++) {
int rgb = colors.getOrDefault(i, 0);
int argb = (0xFF << 24) | (rgb & 0xFFFFFF);
paletteTexture.setRGB(i, 0, argb);
}
try {
ImageIO.write(paletteTexture, "png", new File("src/lwjgl/resources/textures/palette.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,172 +0,0 @@
package net.minestom.server.map.framebuffers;
import net.minestom.server.MinecraftServer;
import net.minestom.server.map.Framebuffer;
import net.minestom.server.map.MapColors;
import net.minestom.server.timer.Task;
import net.minestom.server.utils.thread.ThreadBindingExecutor;
import org.lwjgl.BufferUtils;
import org.lwjgl.PointerBuffer;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.system.MemoryStack;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.time.temporal.TemporalUnit;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
public abstract class GLFWCapableBuffer {
protected final byte[] colors;
private final ByteBuffer pixels;
private final long glfwWindow;
private final int width;
private final int height;
private final ByteBuffer colorsBuffer;
private boolean onlyMapColors;
private static ThreadBindingExecutor threadBindingPool;
protected GLFWCapableBuffer(int width, int height) {
this(width, height, GLFW_NATIVE_CONTEXT_API, GLFW_OPENGL_API);
}
/**
* Creates the framebuffer and initializes a new context
*/
protected GLFWCapableBuffer(int width, int height, int apiContext, int clientAPI) {
this.width = width;
this.height = height;
this.colors = new byte[width*height];
colorsBuffer = BufferUtils.createByteBuffer(width*height);
this.pixels = BufferUtils.createByteBuffer(width*height*4);
if(!glfwInit()) {
throw new RuntimeException("Failed to init GLFW");
}
GLFWErrorCallback.createPrint().set();
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_CONTEXT_CREATION_API, apiContext);
glfwWindowHint(GLFW_CLIENT_API, clientAPI);
this.glfwWindow = glfwCreateWindow(width, height, "", 0L, 0L);
if(glfwWindow == 0L) {
try(var stack = MemoryStack.stackPush()) {
PointerBuffer desc = stack.mallocPointer(1);
int errcode = glfwGetError(desc);
throw new RuntimeException("("+errcode+") Failed to create GLFW Window.");
}
}
synchronized(GLFWCapableBuffer.class) {
if(threadBindingPool == null) {
threadBindingPool = new ThreadBindingExecutor(Runtime.getRuntime().availableProcessors()/2,
"GLFWCapableBuffer-ThreadBindingPool");
}
}
}
public GLFWCapableBuffer unbindContextFromThread() {
glfwMakeContextCurrent(0L);
return this;
}
public void changeRenderingThreadToCurrent() {
glfwMakeContextCurrent(glfwWindow);
GL.createCapabilities();
}
public Task setupRenderLoop(long period, TemporalUnit unit, Runnable rendering) {
return setupRenderLoop(Duration.of(period, unit), rendering);
}
public Task setupRenderLoop(Duration period, Runnable rendering) {
return MinecraftServer.getSchedulerManager()
.buildTask(new Runnable() {
private boolean first = true;
private final Runnable subAction = () -> {
if(first) {
changeRenderingThreadToCurrent();
first = false;
}
render(rendering);
};
@Override
public void run() {
threadBindingPool.execute(subAction);
}
})
.repeat(period)
.schedule();
}
public void render(Runnable rendering) {
rendering.run();
glfwSwapBuffers(glfwWindow);
prepareMapColors();
}
/**
* Called in render after glFlush to read the pixel buffer contents and convert it to map colors.
* Only call if you do not use {@link #render(Runnable)} nor {@link #setupRenderLoop}
*/
public void prepareMapColors() {
if(onlyMapColors) {
colorsBuffer.rewind();
glReadPixels(0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, colorsBuffer);
colorsBuffer.get(colors);
} else {
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int i = Framebuffer.index(x, y, width)*4;
int red = pixels.get(i) & 0xFF;
int green = pixels.get(i+1) & 0xFF;
int blue = pixels.get(i+2) & 0xFF;
int alpha = pixels.get(i+3) & 0xFF;
int argb = (alpha << 24) | (red << 16) | (green << 8) | blue;
colors[Framebuffer.index(x, y, width)] = MapColors.closestColor(argb).getIndex();
}
}
}
}
public void cleanup() {
glfwTerminate();
}
public long getGLFWWindow() {
return glfwWindow;
}
public int width() {
return width;
}
public int height() {
return height;
}
/**
* Tells this buffer that the **RED** channel contains the index of the map color to use.
*
* This allows for optimizations and fast rendering (because there is no need for a conversion)
*/
public void useMapColors() {
onlyMapColors = true;
}
/**
* Opposite to {@link #useMapColors()}
*/
public void useRGB() {
onlyMapColors = false;
}
}

View File

@ -1,48 +0,0 @@
package net.minestom.server.map.framebuffers;
import net.minestom.server.map.Framebuffer;
import org.lwjgl.BufferUtils;
import java.nio.ByteBuffer;
import static org.lwjgl.glfw.GLFW.GLFW_NATIVE_CONTEXT_API;
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_API;
/**
* GLFW-based framebuffer.
*
* Due to its interfacing with OpenGL(-ES), extra care needs to be applied when using this framebuffer.
* Rendering to this framebuffer should only be done via the thread on which the context is present.
* To perform map conversion at the end of a frame, it is advised to use {@link #render(Runnable)} to render to the map.
*
* Use {@link #changeRenderingThreadToCurrent} in a thread to switch the thread on which to render.
*
* Use {@link #setupRenderLoop} with a callback to setup a task in the {@link net.minestom.server.timer.SchedulerManager}
* to automatically render to the offscreen buffer on a specialized thread.
*
* GLFWFramebuffer does not provide guarantee that the result of {@link #toMapColors()} is synchronized with rendering, but
* it will be updated after each frame rendered through {@link #render(Runnable)} or {@link #setupRenderLoop(long, java.time.temporal.TemporalUnit, Runnable)}.
*
* This framebuffer is meant to render to a single map (ie it is only compatible with 128x128 rendering)
*/
public class GLFWFramebuffer extends GLFWCapableBuffer implements Framebuffer {
private final byte[] colors = new byte[WIDTH*HEIGHT];
private final ByteBuffer pixels = BufferUtils.createByteBuffer(WIDTH*HEIGHT*4);
public GLFWFramebuffer() {
this(GLFW_NATIVE_CONTEXT_API, GLFW_OPENGL_API);
}
/**
* Creates the framebuffer and initializes a new context
*/
public GLFWFramebuffer(int apiContext, int clientAPI) {
super(WIDTH, HEIGHT, apiContext, clientAPI);
}
@Override
public byte[] toMapColors() {
return colors;
}
}

View File

@ -1,27 +0,0 @@
package net.minestom.server.map.framebuffers;
import net.minestom.server.map.Framebuffer;
import net.minestom.server.map.LargeFramebuffer;
import static org.lwjgl.glfw.GLFW.GLFW_NATIVE_CONTEXT_API;
import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_API;
public class LargeGLFWFramebuffer extends GLFWCapableBuffer implements LargeFramebuffer {
public LargeGLFWFramebuffer(int width, int height) {
this(width, height, GLFW_NATIVE_CONTEXT_API, GLFW_OPENGL_API);
}
public LargeGLFWFramebuffer(int width, int height, int apiContext, int clientAPI) {
super(width, height, apiContext, clientAPI);
}
@Override
public Framebuffer createSubView(int left, int top) {
return new LargeFramebufferDefaultView(this, left, top);
}
@Override
public byte getMapColor(int x, int y) {
return colors[Framebuffer.index(x, y, width())];
}
}

View File

@ -1,257 +0,0 @@
package net.minestom.server.map.framebuffers;
import org.lwjgl.BufferUtils;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.util.stream.Collectors;
import static org.lwjgl.opengl.GL30.*;
/**
* Helper class designed to help OpenGL users to convert their RGB values to map colors inside a post processing pass
* with a shader provided by Minestom.
*
* When rendering to a {@link GLFWFramebuffer} or a {@link LargeGLFWFramebuffer}, wrap your rendering in a MapColorRenderer to render to the GLFW with map colors.
*
* {@link MapColorRenderer} sets up an OpenGL framebuffer with the size of the underlying framebuffer and renders to it.
* The initialization of the framebuffer is done in the constructor.
* Therefore, the constructor call should be done inside the thread linked to the OpenGL context. The context can
* be moved through {@link GLFWCapableBuffer#changeRenderingThreadToCurrent()} and {@link GLFWCapableBuffer#unbindContextFromThread()}
*
* <hr>
* Resources created in constructor are:
* <ul>
* <li>Framebuffer</li>
* <li>Color texture (if default fbo initialization chosen)</li>
* <li>Depth24 Stencil8 render buffer (if default fbo initialization chosen)</li>
* <li>Post processing shader program</li>
* <li>Palette texture</li>
* <li>Screen quad VAO</li>
* <li>Screen quad index buffer</li>
* </ul>
*
* The constructor also puts the given buffer in map color mode.
*/
public class MapColorRenderer implements Runnable {
private final int fboID;
private final GLFWCapableBuffer framebuffer;
private final Runnable renderCode;
private final int colorTextureID;
private final int width;
private final int height;
private final int renderShader;
private final int screenQuadIndices;
private int paletteTexture;
private float paletteSize;
private final int screenQuadVAO;
public MapColorRenderer(GLFWCapableBuffer framebuffer, Runnable renderCode) {
this(framebuffer, renderCode, MapColorRenderer.defaultFramebuffer(framebuffer.width(), framebuffer.height()));
}
public MapColorRenderer(GLFWCapableBuffer framebuffer, Runnable renderCode, FboInitialization fboInitialization) {
this.framebuffer = framebuffer;
this.framebuffer.useMapColors();
this.renderCode = renderCode;
this.width = framebuffer.width();
this.height = framebuffer.height();
this.fboID = glGenFramebuffers();
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
this.colorTextureID = fboInitialization.initFbo(fboID);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("Framebuffer is not complete!");
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// create post-process shader
this.renderShader = glCreateProgram();
int vertexShader = createShader("/shaders/mapcolorconvert.vertex.glsl", GL_VERTEX_SHADER);
int fragmentShader = createShader("/shaders/mapcolorconvert.fragment.glsl", GL_FRAGMENT_SHADER);
glAttachShader(renderShader, vertexShader);
glAttachShader(renderShader, fragmentShader);
glLinkProgram(renderShader);
if(glGetProgrami(renderShader, GL_LINK_STATUS) == 0) {
throw new RuntimeException("Link error: "+glGetProgramInfoLog(renderShader));
}
loadPalette("palette");
// create screen quad VAO
screenQuadVAO = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, screenQuadVAO);
glBufferData(GL_ARRAY_BUFFER, new float[] {
-1f, -1f,
1f, -1f,
1f, 1f,
-1f, 1f
}, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
screenQuadIndices = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenQuadIndices);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, new int[] {0,1,2, 2,3,0}, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
int paletteSizeUniform = glGetUniformLocation(renderShader, "paletteSize");
int paletteUniform = glGetUniformLocation(renderShader, "palette");
int frameUniform = glGetUniformLocation(renderShader, "frame");
glUseProgram(renderShader); {
glUniform1i(frameUniform, 0); // texture unit 0
glUniform1i(paletteUniform, 1); // texture unit 1
glUniform1f(paletteSizeUniform, paletteSize);
}
glUseProgram(0);
}
private static FboInitialization defaultFramebuffer(int width, int height) {
return fboId -> defaultFramebufferInit(fboId, width, height);
}
private static int defaultFramebufferInit(int fbo, int width, int height) {
// color
int colorTexture = glGenTextures();
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0L);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// attach to framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// depth
int depthStencilBuffer = glGenRenderbuffers();
glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
return colorTexture;
}
@Override
public void run() {
glViewport(0, 0, width, height);
// run user code inside of framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
renderCode.run();
// run post processing to display on screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClearColor(0f, 0f, 0f, 1f); // 0 on RED channel makes maps use NONE
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorTextureID);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, paletteTexture);
glUseProgram(renderShader); {
// render post processing quad
glBindBuffer(GL_ARRAY_BUFFER, screenQuadVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 2*4, 0); // position
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, screenQuadIndices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
}
/**
* Frees OpenGL resources used by this renderer.
* You should NOT render with this renderer after this call.
*/
public void cleanupResources() {
glDeleteFramebuffers(fboID);
glDeleteProgram(renderShader);
glDeleteTextures(paletteTexture);
// TODO: more cleanup
}
private void loadPalette(String filename) {
int tex = glGenTextures();
glBindTexture(GL_TEXTURE_2D, tex);
BufferedImage image;
try {
image = ImageIO.read(MapColorRenderer.class.getResourceAsStream("/textures/"+filename+".png"));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Missing image "+filename, e);
}
ByteBuffer pixels = BufferUtils.createByteBuffer(image.getWidth()*image.getHeight()*4);
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int rgb = image.getRGB(x, y);
int alpha = (rgb >> 24) & 0xFF;
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
pixels.put((byte) red);
pixels.put((byte) green);
pixels.put((byte) blue);
pixels.put((byte) alpha);
}
}
pixels.flip();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getWidth(), image.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// closest neighbor required here, as pixels can have very different rgb values, and interpolation will break palette lookup
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
this.paletteTexture = tex;
this.paletteSize = image.getWidth();
}
private static int createShader(String filename, int type) {
int shader = glCreateShader(type);
try(BufferedReader reader = new BufferedReader(new InputStreamReader(MapColorRenderer.class.getResourceAsStream(filename)))) {
String source = reader.lines().collect(Collectors.joining("\n"));
glShaderSource(shader, source);
glCompileShader(shader);
} catch (IOException e) {
e.printStackTrace();
}
return shader;
}
@FunctionalInterface
public interface FboInitialization {
/**
* Initializes the given framebuffer
* @param fboId
* @return the texture ID of the color texture, used for post processing.
*/
int initFbo(int fboId);
}
}

View File

@ -1,12 +0,0 @@
#version 330
in vec2 uv;
out vec4 fragColor;
uniform sampler2D box;
void main() {
vec3 vertexColor = texture(box, uv).rgb;
fragColor = vec4(vertexColor, 1.0);
}

View File

@ -1,32 +0,0 @@
#version 330
in vec2 fragCoords;
out vec4 fragColor;
uniform sampler2D frame;
uniform sampler2D palette;
uniform float paletteSize;
void main() {
vec2 uv = fragCoords;
uv.y = -uv.y;
vec3 fragmentColor = texture(frame, uv).rgb;
// render in map colors
int closest = 0;
uint closestDistance = uint(2147483647);
for(int i = 4; i < paletteSize; i++) {
vec3 mapColor = texture(palette, vec2((i+0.5f)/paletteSize, 0.0)).rgb;
int dr = int((mapColor.r - fragmentColor.r)*255);
int dg = int((mapColor.g - fragmentColor.g)*255);
int db = int((mapColor.b - fragmentColor.b)*255);
uint d = uint(dr*dr)+uint(dg*dg)+uint(db*db);
if(d < closestDistance) {
closestDistance = d;
closest = i;
}
}
fragColor = vec4(closest/255.0, closest/255.0, closest/255.0, 1.0);
}

View File

@ -1,10 +0,0 @@
#version 330
layout(location = 0) in vec2 pos;
out vec2 fragCoords;
void main() {
fragCoords = (pos+vec2(1.0))/2.0;
gl_Position = vec4(pos, 0.0, 1.0);
}

View File

@ -1,16 +0,0 @@
#version 330
layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 texCoords;
out vec2 uv;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main() {
mat4 mvp = projection * view * model;
uv = texCoords;
gl_Position = mvp * vec4(pos, 1.0);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 876 B

View File

@ -65,6 +65,12 @@ public final class PFBlock implements IBlockDescription, IBlockObject {
return block.namespace().asString().endsWith("door");
}
@Override
public boolean isIntractable() {
// TODO: Interactability of blocks.
return false;
}
@Override
public boolean isImpeding() {
return block.isSolid();

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" strict="true" name="Minestom">
<Appenders>
<Appender type="Console" name="STDOUT">
<Layout type="PatternLayout" pattern="[%t] [%d{HH:mm:ss}] - %p - %m%n"/>
</Appender>
<Appender type="Console" name="STDOUT-WithCaller">
<Layout type="PatternLayout" pattern="[%t] [%d{HH:mm:ss}] (%C{1}.%M) - %p - %m%n"/>
</Appender>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="STDOUT-WithCaller" level="info"/>
</Root>
</Loggers>
</Configuration>

View File

@ -0,0 +1,4 @@
autoshutdown=true
writer=console
writer.level=info
writer.format=[{thread}] [{date: HH:mm:ss}] ({class-name}.{method}) - {level} - {message}

View File

@ -1,4 +0,0 @@
{
"entrypoint": "improveextensions.unloadcallbacks.UnloadCallbacksExtension",
"name": "UnloadCallbacksExtension"
}

View File

@ -1,4 +0,0 @@
{
"entrypoint": "improveextensions.unloadextensiononstop.UnloadExtensionOnStop",
"name": "UnloadExtensionOnStop"
}