mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-23 08:31:26 +01:00
Build system update (#527)
This commit is contained in:
parent
de817e5e52
commit
3089843cc9
7
.gitignore
vendored
7
.gitignore
vendored
@ -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
|
16
build-logic/build.gradle.kts
Normal file
16
build-logic/build.gradle.kts
Normal 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")
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
186
build.gradle
186
build.gradle
@ -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
84
build.gradle.kts
Normal 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()}")
|
||||
}
|
@ -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>
|
||||
)
|
||||
}
|
24
code-generators/build.gradle.kts
Normal file
24
code-generators/build.gradle.kts
Normal 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
18
demo/build.gradle.kts
Normal 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)
|
||||
}
|
@ -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());
|
@ -1,4 +1,4 @@
|
||||
package demo;
|
||||
package net.minestom.demo;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.coordinate.Pos;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.inventory.Book;
|
||||
import net.kyori.adventure.text.Component;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.builder.Command;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.audience.MessageType;
|
||||
import net.kyori.adventure.identity.Identity;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.command.CommandSender;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.command.CommandSender;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.minestom.server.command.CommandSender;
|
||||
import net.minestom.server.entity.Player;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.MinecraftServer;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.MinecraftServer;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.MinecraftServer;
|
@ -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;
|
@ -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;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.command.CommandSender;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandSender;
|
@ -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;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.MinecraftServer;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.command.CommandSender;
|
@ -1,4 +1,4 @@
|
||||
package demo.commands;
|
||||
package net.minestom.demo.commands;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.title.Title;
|
@ -1,4 +1,4 @@
|
||||
package demo.entity;
|
||||
package net.minestom.demo.entity;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minestom.server.attribute.Attribute;
|
@ -1,4 +1,4 @@
|
||||
package demo.entity;
|
||||
package net.minestom.demo.entity;
|
||||
|
||||
import net.minestom.server.entity.EntityCreature;
|
||||
import net.minestom.server.entity.EntityType;
|
@ -1,4 +1,4 @@
|
||||
package demo.generator;
|
||||
package net.minestom.demo.generator;
|
||||
|
||||
import net.minestom.server.instance.Chunk;
|
||||
import net.minestom.server.instance.ChunkGenerator;
|
@ -1,4 +1,4 @@
|
||||
package demo.generator;
|
||||
package net.minestom.demo.generator;
|
||||
|
||||
import de.articdive.jnoise.JNoise;
|
||||
import de.articdive.jnoise.interpolation.InterpolationType;
|
@ -1,4 +1,4 @@
|
||||
package demo.generator;
|
||||
package net.minestom.demo.generator;
|
||||
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Vec;
|
@ -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
90
gradle/libs.versions.toml
Normal 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"]
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
10
gradlew
vendored
@ -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:
|
||||
#
|
||||
|
8
jmh-benchmarks/build.gradle.kts
Normal file
8
jmh-benchmarks/build.gradle.kts
Normal file
@ -0,0 +1,8 @@
|
||||
plugins {
|
||||
id("me.champeau.jmh") version ("0.6.6")
|
||||
id("minestom.common-conventions")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(rootProject)
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
rootProject.name = 'Minestom'
|
||||
include 'code-generators'
|
22
settings.gradle.kts
Normal file
22
settings.gradle.kts
Normal 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")
|
@ -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.
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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())];
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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 |
@ -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();
|
||||
|
@ -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>
|
4
src/main/resources/tinylog.properties
Normal file
4
src/main/resources/tinylog.properties
Normal file
@ -0,0 +1,4 @@
|
||||
autoshutdown=true
|
||||
writer=console
|
||||
writer.level=info
|
||||
writer.format=[{thread}] [{date: HH:mm:ss}] ({class-name}.{method}) - {level} - {message}
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"entrypoint": "improveextensions.unloadcallbacks.UnloadCallbacksExtension",
|
||||
"name": "UnloadCallbacksExtension"
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"entrypoint": "improveextensions.unloadextensiononstop.UnloadExtensionOnStop",
|
||||
"name": "UnloadExtensionOnStop"
|
||||
}
|
Loading…
Reference in New Issue
Block a user