Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
38021852d0
|
|||
9c85164ed1
|
|||
ce573b51ce
|
|||
92f9639c4b
|
|||
f350467942
|
|||
a028f6f3c7
|
|||
23b0af1731 | |||
0389f97e59 | |||
706800218c
|
|||
ca2c7b58d8
|
|||
359879b0fe
|
|||
a06d8ee056
|
|||
c8138faabe
|
|||
49d283e7a3
|
|||
c93f0df30d
|
|||
75ea7baf9c
|
|||
c4a9a17c7c | |||
b4ff5114bd
|
|||
9b67897896
|
|||
efc6a8ecd0
|
|||
3641c4130b
|
|||
4b10dc82ed
|
|||
be6203719a
|
|||
c04894a0c9 | |||
9885a1ca42
|
|||
c6e6dc6851
|
|||
28b19c8f35
|
|||
30464febf6 | |||
782b3ef553
|
|||
05b1c73fbc
|
|||
bd6442318d
|
|||
6cd812f7c3 | |||
73ee339dcc
|
|||
4749be6c60
|
|||
a4b731e8a5
|
|||
e7d0e8fe40
|
|||
040a4f7fd7
|
|||
b3ac7b6afe
|
|||
2fe84dc59e
|
|||
00ea4a6281
|
|||
f186fc602d
|
248
build.gradle
248
build.gradle
@ -3,14 +3,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
// Apply the java-library plugin to add support for Java Library
|
// Apply the java-library plugin to add support for Java Library
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Uncomment the following line to enable the Eclipse plugin.
|
* Uncomment the following line to enable the Eclipse plugin.
|
||||||
* This is only necessary if you don't use Buildship plugin from the IDE
|
* This is only necessary if you don't use Buildship plugin from the IDE
|
||||||
*/
|
*/
|
||||||
//id 'eclipse'
|
//id 'eclipse'
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@ -18,8 +18,8 @@ java {
|
|||||||
* We're Java 8 for now.
|
* We're Java 8 for now.
|
||||||
* Why? As of 2020, most users have Oracle Java, which only supports Java 8.
|
* Why? As of 2020, most users have Oracle Java, which only supports Java 8.
|
||||||
*/
|
*/
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
@ -29,9 +29,9 @@ compileJava {
|
|||||||
* However, on JDK 9 and later versions, '--release' option is required,
|
* However, on JDK 9 and later versions, '--release' option is required,
|
||||||
* which is missing on JDK 8.
|
* which is missing on JDK 8.
|
||||||
*/
|
*/
|
||||||
if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
|
if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
|
||||||
options.compilerArgs.addAll(['--release', '8'])
|
options.compilerArgs.addAll(['--release', '8'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -40,39 +40,38 @@ compileJava {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
jcenter()
|
|
||||||
|
/*
|
||||||
/*
|
* Specify Windcorp Maven repository
|
||||||
* Specify Windcorp Maven repository
|
* Currently used by:
|
||||||
* Currently used by:
|
* - ru.windcorp.fork.io.github.java-graphics:glm:1.0.1
|
||||||
* - ru.windcorp.fork.io.github.java-graphics:glm:1.0.1
|
*/
|
||||||
*/
|
maven { url 'https://windcorp.ru/./maven' }
|
||||||
maven { url 'https://windcorp.ru/./maven' }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Google Guava
|
// Google Guava
|
||||||
// A generic utilities library
|
// A generic utilities library
|
||||||
implementation 'com.google.guava:guava:30.0-jre'
|
implementation 'com.google.guava:guava:30.0-jre'
|
||||||
|
|
||||||
// Trove4j
|
// Trove4j
|
||||||
// Provides optimized Collections for primitive types
|
// Provides optimized Collections for primitive types
|
||||||
implementation 'net.sf.trove4j:trove4j:3.0.3'
|
implementation 'net.sf.trove4j:trove4j:3.0.3'
|
||||||
|
|
||||||
// java-graphics
|
// java-graphics
|
||||||
// A GLM (OpenGL Mathematics) port to Java
|
// A GLM (OpenGL Mathematics) port to Java
|
||||||
// Unfortunately, Maven Central Repository provides an outdated version of this library, which contains several critical bugs
|
// Unfortunately, Maven Central Repository provides an outdated version of this library, which contains several critical bugs
|
||||||
implementation 'ru.windcorp.fork.io.github.java-graphics:glm:1.0.1'
|
implementation 'ru.windcorp.fork.io.github.java-graphics:glm:1.0.1'
|
||||||
|
|
||||||
// Log4j
|
// Log4j
|
||||||
// A logging library
|
// A logging library
|
||||||
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.13.3'
|
implementation 'org.apache.logging.log4j:log4j-api:2.17.0'
|
||||||
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.13.3'
|
implementation 'org.apache.logging.log4j:log4j-core:2.17.0'
|
||||||
|
|
||||||
// JUnit
|
// JUnit
|
||||||
// A unit-testing library
|
// A unit-testing library
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
|
|
||||||
// See LWJGL dependencies below
|
// See LWJGL dependencies below
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,8 +98,8 @@ switch (OperatingSystem.current()) {
|
|||||||
case OperatingSystem.LINUX:
|
case OperatingSystem.LINUX:
|
||||||
def osArch = System.getProperty("os.arch")
|
def osArch = System.getProperty("os.arch")
|
||||||
project.ext.lwjglNatives = osArch.startsWith("arm") || osArch.startsWith("aarch64")
|
project.ext.lwjglNatives = osArch.startsWith("arm") || osArch.startsWith("aarch64")
|
||||||
? "natives-linux-${osArch.contains("64") || osArch.startsWith("armv8") ? "arm64" : "arm32"}"
|
? "natives-linux-${osArch.contains("64") || osArch.startsWith("armv8") ? "arm64" : "arm32"}"
|
||||||
: "natives-linux"
|
: "natives-linux"
|
||||||
break
|
break
|
||||||
case OperatingSystem.MAC_OS:
|
case OperatingSystem.MAC_OS:
|
||||||
project.ext.lwjglNatives = "natives-macos"
|
project.ext.lwjglNatives = "natives-macos"
|
||||||
@ -118,12 +117,12 @@ dependencies {
|
|||||||
implementation "org.lwjgl:lwjgl-openal"
|
implementation "org.lwjgl:lwjgl-openal"
|
||||||
implementation "org.lwjgl:lwjgl-opengl"
|
implementation "org.lwjgl:lwjgl-opengl"
|
||||||
implementation "org.lwjgl:lwjgl-stb"
|
implementation "org.lwjgl:lwjgl-stb"
|
||||||
|
|
||||||
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
||||||
}
|
}
|
||||||
|
|
||||||
// LWJGL END
|
// LWJGL END
|
||||||
@ -141,49 +140,56 @@ project.ext.platforms = new HashSet<>()
|
|||||||
task addNativeDependencies {
|
task addNativeDependencies {
|
||||||
doFirst {
|
doFirst {
|
||||||
def archs = project.ext.platforms
|
def archs = project.ext.platforms
|
||||||
|
|
||||||
switch (archs.size()) {
|
switch (archs.size()) {
|
||||||
case 0:
|
case 0:
|
||||||
println "Adding LWJGL native dependencies for local platform only:\n\t$lwjglNatives"
|
println "Adding LWJGL native dependencies for local platform only:\n\t$lwjglNatives"
|
||||||
archs.add project.ext.lwjglNatives
|
archs.add project.ext.lwjglNatives
|
||||||
break
|
break
|
||||||
case 1:
|
case 1:
|
||||||
println "Adding LWJGL native dependencies for platform\n\t" + archs.get(0)
|
println "Adding LWJGL native dependencies for platform\n\t" + archs.get(0)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
println "Adding LWJGL native dependencies for platforms:\n\t" + archs.join("\n\t")
|
println "Adding LWJGL native dependencies for platforms:\n\t" + archs.join("\n\t")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project.ext.lwjglNatives.isEmpty()) println "WTF"
|
if (project.ext.lwjglNatives.isEmpty()) println "WTF"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
archs.each { arch ->
|
archs.each { arch ->
|
||||||
runtimeOnly "org.lwjgl:lwjgl::$arch"
|
runtimeOnly "org.lwjgl:lwjgl::$arch"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-glfw::$arch"
|
runtimeOnly "org.lwjgl:lwjgl-glfw::$arch"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-openal::$arch"
|
runtimeOnly "org.lwjgl:lwjgl-openal::$arch"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-opengl::$arch"
|
runtimeOnly "org.lwjgl:lwjgl-opengl::$arch"
|
||||||
runtimeOnly "org.lwjgl:lwjgl-stb::$arch"
|
runtimeOnly "org.lwjgl:lwjgl-stb::$arch"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava.mustRunAfter addNativeDependencies // Make sure runtimeOnly has not been resolved
|
compileJava.mustRunAfter addNativeDependencies // Make sure runtimeOnly has not been resolved
|
||||||
|
|
||||||
task requestLinuxDependencies {
|
task requestLinuxDependencies {
|
||||||
description 'Adds linux, linux-arm64 and linux-arm32 native libraries to built artifacts.'
|
description 'Adds linux, linux-arm64 and linux-arm32 native libraries to built artifacts.'
|
||||||
doFirst {
|
doFirst {
|
||||||
project.ext.platforms.addAll(['natives-linux', 'natives-linux-arm64', 'natives-linux-arm32'])
|
project.ext.platforms.addAll([
|
||||||
|
'natives-linux',
|
||||||
|
'natives-linux-arm64',
|
||||||
|
'natives-linux-arm32'
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
task requestWindowsDependencies {
|
task requestWindowsDependencies {
|
||||||
description 'Adds windows and windows-x86 native libraries to built artifacts.'
|
description 'Adds windows and windows-x86 native libraries to built artifacts.'
|
||||||
doFirst {
|
doFirst {
|
||||||
project.ext.platforms.addAll(['natives-windows', 'natives-windows-x86'])
|
project.ext.platforms.addAll([
|
||||||
|
'natives-windows',
|
||||||
|
'natives-windows-x86'
|
||||||
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
task requestMacOSDependencies {
|
task requestMacOSDependencies {
|
||||||
description 'Adds macos native libraries to built artifacts.'
|
description 'Adds macos native libraries to built artifacts.'
|
||||||
doFirst {
|
doFirst {
|
||||||
project.ext.platforms.addAll(['natives-macos'])
|
project.ext.platforms.addAll(['natives-macos'])
|
||||||
}
|
}
|
||||||
@ -192,7 +198,7 @@ task requestMacOSDependencies {
|
|||||||
def dependencySpecificationTasks = tasks.findAll { task -> task.name.startsWith('request') && task.name.endsWith('Dependencies') }
|
def dependencySpecificationTasks = tasks.findAll { task -> task.name.startsWith('request') && task.name.endsWith('Dependencies') }
|
||||||
|
|
||||||
task requestCrossPlatformDependencies {
|
task requestCrossPlatformDependencies {
|
||||||
description 'Adds native libraries for all available platforms to built artifacts.'
|
description 'Adds native libraries for all available platforms to built artifacts.'
|
||||||
dependsOn dependencySpecificationTasks
|
dependsOn dependencySpecificationTasks
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +211,7 @@ def isDependencyRequested(String dep) {
|
|||||||
if (dep.endsWith(".jar")) {
|
if (dep.endsWith(".jar")) {
|
||||||
dep = dep.substring(0, dep.length() - ".jar".length())
|
dep = dep.substring(0, dep.length() - ".jar".length())
|
||||||
}
|
}
|
||||||
|
|
||||||
return !dep.contains("natives-") ||
|
return !dep.contains("natives-") ||
|
||||||
project.ext.platforms.contains(dep.substring(dep.indexOf("natives-"), dep.length()))
|
project.ext.platforms.contains(dep.substring(dep.indexOf("natives-"), dep.length()))
|
||||||
}
|
}
|
||||||
@ -219,7 +225,7 @@ task specifyLocalManifest {
|
|||||||
|
|
||||||
doFirst {
|
doFirst {
|
||||||
def classPath = []
|
def classPath = []
|
||||||
|
|
||||||
configurations.runtimeClasspath.each {
|
configurations.runtimeClasspath.each {
|
||||||
if (isDependencyRequested(it.getName())) {
|
if (isDependencyRequested(it.getName())) {
|
||||||
classPath.add("lib/" + it.getName())
|
classPath.add("lib/" + it.getName())
|
||||||
@ -227,18 +233,18 @@ task specifyLocalManifest {
|
|||||||
println "\tRemoving from JAR classpath (not requested): " + it.getName()
|
println "\tRemoving from JAR classpath (not requested): " + it.getName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classPath.size() == configurations.runtimeClasspath.size()) {
|
if (classPath.size() == configurations.runtimeClasspath.size()) {
|
||||||
println "Nothing removed from JAR classpath"
|
println "Nothing removed from JAR classpath"
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
attributes(
|
attributes(
|
||||||
"Main-Class": "ru.windcorp.progressia.client.ProgressiaClientMain",
|
"Main-Class": "ru.windcorp.progressia.client.ProgressiaClientMain",
|
||||||
"Class-Path": configurations.runtimeClasspath.collect { "lib/" + it.getName() } .findAll { isDependencyRequested(it) } .join(' ')
|
"Class-Path": configurations.runtimeClasspath.collect { "lib/" + it.getName() } .findAll { isDependencyRequested(it) } .join(' ')
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,13 +254,13 @@ jar.dependsOn specifyLocalManifest
|
|||||||
/*
|
/*
|
||||||
* Library export
|
* Library export
|
||||||
*/
|
*/
|
||||||
|
|
||||||
task exportLibs(type: Sync) {
|
task exportLibs(type: Sync) {
|
||||||
mustRunAfter addNativeDependencies
|
mustRunAfter addNativeDependencies
|
||||||
|
|
||||||
into libsDirectory.get().getAsFile().getPath() + "/lib"
|
into libsDirectory.get().getAsFile().getPath() + "/lib"
|
||||||
exclude { !isDependencyRequested(it.getName()) }
|
exclude { !isDependencyRequested(it.getName()) }
|
||||||
from configurations.runtimeClasspath
|
from configurations.runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
||||||
jar.dependsOn(exportLibs)
|
jar.dependsOn(exportLibs)
|
||||||
@ -264,52 +270,52 @@ jar.dependsOn(exportLibs)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
task packageDebian(type: Exec) {
|
task packageDebian(type: Exec) {
|
||||||
description 'Builds the project and creates a Debain package.'
|
description 'Builds the project and creates a Debain package.'
|
||||||
group 'Progressia'
|
group 'Progressia'
|
||||||
|
|
||||||
dependsOn build
|
dependsOn build
|
||||||
dependsOn requestLinuxDependencies
|
dependsOn requestLinuxDependencies
|
||||||
|
|
||||||
commandLine './buildPackages.sh', 'debian'
|
commandLine './buildPackages.sh', 'debian'
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
println "Debian package available in build_packages/"
|
println "Debian package available in build_packages/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task packageWindows(type: Exec) {
|
task packageWindows(type: Exec) {
|
||||||
description 'Builds the project and creates a Windows installer.'
|
description 'Builds the project and creates a Windows installer.'
|
||||||
group 'Progressia'
|
group 'Progressia'
|
||||||
|
|
||||||
dependsOn build
|
dependsOn build
|
||||||
dependsOn requestWindowsDependencies
|
dependsOn requestWindowsDependencies
|
||||||
|
|
||||||
commandLine './buildPackages.sh', 'windows'
|
commandLine './buildPackages.sh', 'windows'
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
println "Windows installer available in build_packages/"
|
println "Windows installer available in build_packages/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task buildCrossPlatform {
|
task buildCrossPlatform {
|
||||||
description 'Builds the project including native libraries for all available platforms.'
|
description 'Builds the project including native libraries for all available platforms.'
|
||||||
group 'Progressia'
|
group 'Progressia'
|
||||||
|
|
||||||
dependsOn requestCrossPlatformDependencies
|
dependsOn requestCrossPlatformDependencies
|
||||||
dependsOn build
|
dependsOn build
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
println "Native libraries for all platforms have been added"
|
println "Native libraries for all platforms have been added"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task buildLocal {
|
task buildLocal {
|
||||||
description "Builds the project including only native libraries for current platform ($lwjglNatives)."
|
description "Builds the project including only native libraries for current platform ($lwjglNatives)."
|
||||||
group 'Progressia'
|
group 'Progressia'
|
||||||
|
|
||||||
dependsOn build
|
dependsOn build
|
||||||
|
|
||||||
doLast {
|
doLast {
|
||||||
println "Native libraries only for platform $lwjglNatives have been added"
|
println "Native libraries only for platform $lwjglNatives have been added"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
docs/ProgressiaRegion.md
Normal file
12
docs/ProgressiaRegion.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Progressia Region File
|
||||||
|
## Description
|
||||||
|
The `.progressia_region` file type is used for all region files in the game Progressia. Each region file contains a cube of 16x16x16 chunks.
|
||||||
|
## Header
|
||||||
|
The header of the file is 16 400 bytes. Every file starts with the string byte sequence `\x50\x52\x4F\x47` (UTF-8 for `PROG`), followed with the three integer values of the region position, in region coordinates. After this, there is exactly 16KiB of space in the header, which stores the offsets to the chunks' data. This space holds an integer, 4 bytes, for each chunk in the region. The integer value starts at 0 for every chunk, and is changed to the location of the chunk data once created. These are indexed in order by flattening the 3D in-chunk coordinates into a number between 0 and 4095 according to the formula `offset = 256*x+ 16*y + z` for chunk at (x, y, z). To convert from this offset value to the offset in bytes, use `byte_offset = 16400 + 64*n`.
|
||||||
|
## Sectors
|
||||||
|
Sectors are what is used to store chunk data, and are not linear, but are followed until they reach an ending block. Each is 64 bytes, which is used in the header section to find the byte offset. Each sector starts with a identification byte, followed by the sector data.
|
||||||
|
|
||||||
|
0. Ending - This sector is empty, and marks the end of the chunk data (This may change in the future.
|
||||||
|
1. Data - This sector contains chunk data for a single chunk. The second byte of this sector contains a counter byte, which is a form of "checksum" to make sure that the program is reading the proper sectors in order. This starts at 0 for the first data sector and increments by one for each new data sector.
|
||||||
|
2. Partition Link - This sector only contains another offset value, which is where the next sector is. This allows for infinite chunk size, avoiding "chunk dupes" as were present in Minecraft without reverting any chunks.
|
||||||
|
3. Bulk Data - These would be used for many chunks in the same region that contain exactly the same data, e.g. all solid chunks underground. Exists so the program knows not to overwrite them, and just make new chunk data if modified. Not yet implemented.
|
@ -18,21 +18,42 @@
|
|||||||
|
|
||||||
package ru.windcorp.progressia.client;
|
package ru.windcorp.progressia.client;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.comms.DefaultClientCommsListener;
|
import ru.windcorp.progressia.client.comms.DefaultClientCommsListener;
|
||||||
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
|
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
|
||||||
|
import ru.windcorp.progressia.client.events.ClientEvent;
|
||||||
|
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
import ru.windcorp.progressia.client.graphics.world.Camera;
|
import ru.windcorp.progressia.client.graphics.world.Camera;
|
||||||
import ru.windcorp.progressia.client.graphics.world.EntityAnchor;
|
import ru.windcorp.progressia.client.graphics.world.EntityAnchor;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
|
||||||
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
|
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDManager;
|
||||||
import ru.windcorp.progressia.client.world.WorldRender;
|
import ru.windcorp.progressia.client.world.WorldRender;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
||||||
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.test.LayerAbout;
|
||||||
|
import ru.windcorp.progressia.test.LayerDebug;
|
||||||
|
import ru.windcorp.progressia.test.LayerTestUI;
|
||||||
|
|
||||||
public class Client {
|
public class Client {
|
||||||
|
|
||||||
private final WorldRender world;
|
private final WorldRender world;
|
||||||
|
|
||||||
|
private final LayerWorld layerWorld = new LayerWorld(this);
|
||||||
|
private final LayerTestUI layerTestUI = new LayerTestUI();
|
||||||
|
private final LayerAbout layerAbout = new LayerAbout();
|
||||||
|
private final LayerDebug layerDebug = new LayerDebug();
|
||||||
|
|
||||||
private final LocalPlayer localPlayer = new LocalPlayer(this);
|
private final LocalPlayer localPlayer = new LocalPlayer(this);
|
||||||
|
|
||||||
private final Camera camera = new Camera((float) Math.toRadians(70));
|
private final Camera camera = new Camera((float) Math.toRadians(70));
|
||||||
|
|
||||||
|
private final EventBus eventBus = ReportingEventBus.create("ClientEvents");
|
||||||
|
|
||||||
|
private final HUDManager hudManager = new HUDManager(this);
|
||||||
|
|
||||||
private final ServerCommsChannel comms;
|
private final ServerCommsChannel comms;
|
||||||
|
|
||||||
@ -41,6 +62,22 @@ public class Client {
|
|||||||
this.comms = comms;
|
this.comms = comms;
|
||||||
|
|
||||||
comms.addListener(new DefaultClientCommsListener(this));
|
comms.addListener(new DefaultClientCommsListener(this));
|
||||||
|
subscribe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void install() {
|
||||||
|
GUI.addBottomLayer(layerWorld);
|
||||||
|
GUI.addTopLayer(layerTestUI);
|
||||||
|
hudManager.install();
|
||||||
|
GUI.addTopLayer(layerAbout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
GUI.removeLayer(layerWorld);
|
||||||
|
GUI.removeLayer(layerTestUI);
|
||||||
|
hudManager.remove();
|
||||||
|
GUI.removeLayer(layerAbout);
|
||||||
|
GUI.removeLayer(layerDebug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldRender getWorld() {
|
public WorldRender getWorld() {
|
||||||
@ -62,18 +99,45 @@ public class Client {
|
|||||||
public ServerCommsChannel getComms() {
|
public ServerCommsChannel getComms() {
|
||||||
return comms;
|
return comms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HUDManager getHUD() {
|
||||||
|
return hudManager;
|
||||||
|
}
|
||||||
|
|
||||||
public void onLocalPlayerEntityChanged(EntityData entity, EntityData lastKnownEntity) {
|
public void toggleDebugLayer() {
|
||||||
if (entity == null) {
|
if (GUI.getLayers().contains(layerDebug)) {
|
||||||
|
GUI.removeLayer(layerDebug);
|
||||||
|
} else {
|
||||||
|
GUI.addTopLayer(layerDebug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onLocalPlayerEntityChanged(NewLocalEntityEvent e) {
|
||||||
|
if (e.getNewEntity() == null) {
|
||||||
getCamera().setAnchor(null);
|
getCamera().setAnchor(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCamera().setAnchor(
|
getCamera().setAnchor(
|
||||||
new EntityAnchor(
|
new EntityAnchor(
|
||||||
getWorld().getEntityRenderable(entity)
|
getWorld().getEntityRenderable(e.getNewEntity())
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void subscribe(Object object) {
|
||||||
|
eventBus.register(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(Object object) {
|
||||||
|
eventBus.unregister(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postEvent(ClientEvent event) {
|
||||||
|
event.setClient(this);
|
||||||
|
eventBus.post(event);
|
||||||
|
event.setClient(null);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader;
|
|||||||
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
||||||
import ru.windcorp.progressia.client.graphics.texture.Atlases;
|
import ru.windcorp.progressia.client.graphics.texture.Atlases;
|
||||||
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDTextures;
|
||||||
import ru.windcorp.progressia.client.localization.Localizer;
|
import ru.windcorp.progressia.client.localization.Localizer;
|
||||||
import ru.windcorp.progressia.common.resource.ResourceManager;
|
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
@ -47,6 +48,7 @@ public class ClientProxy implements Proxy {
|
|||||||
() -> Typefaces
|
() -> Typefaces
|
||||||
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
|
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
|
||||||
);
|
);
|
||||||
|
RenderTaskQueue.waitAndInvoke(HUDTextures::loadItemAmountTypeface);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw CrashReports.report(e, "ClientProxy failed");
|
throw CrashReports.report(e, "ClientProxy failed");
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,10 @@ package ru.windcorp.progressia.client;
|
|||||||
|
|
||||||
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
|
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
|
||||||
import ru.windcorp.progressia.client.graphics.GUI;
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
import ru.windcorp.progressia.client.graphics.Layer;
|
|
||||||
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
|
|
||||||
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
||||||
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||||
import ru.windcorp.progressia.server.ServerState;
|
import ru.windcorp.progressia.server.ServerState;
|
||||||
import ru.windcorp.progressia.test.LayerAbout;
|
|
||||||
import ru.windcorp.progressia.test.LayerTestText;
|
import ru.windcorp.progressia.test.LayerTestText;
|
||||||
import ru.windcorp.progressia.test.LayerTestUI;
|
|
||||||
import ru.windcorp.progressia.test.TestContent;
|
import ru.windcorp.progressia.test.TestContent;
|
||||||
|
|
||||||
public class ClientState {
|
public class ClientState {
|
||||||
@ -70,24 +66,14 @@ public class ClientState {
|
|||||||
|
|
||||||
if (client != null && client.getLocalPlayer().hasEntity()) {
|
if (client != null && client.getLocalPlayer().hasEntity()) {
|
||||||
GUI.removeLayer(layer);
|
GUI.removeLayer(layer);
|
||||||
|
client.install();
|
||||||
// TODO refactor, this shouldn't be here
|
|
||||||
LayerWorld layerWorld = new LayerWorld(client);
|
|
||||||
LayerTestUI layerUI = new LayerTestUI();
|
|
||||||
LayerAbout layerAbout = new LayerAbout();
|
|
||||||
GUI.addBottomLayer(layerWorld);
|
|
||||||
GUI.addTopLayer(layerUI);
|
|
||||||
GUI.addTopLayer(layerAbout);
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void disconnectFromLocalServer() {
|
public static void disconnectFromLocalServer() {
|
||||||
getInstance().getComms().disconnect();
|
getInstance().getComms().disconnect();
|
||||||
|
getInstance().remove();
|
||||||
for (Layer layer : GUI.getLayers()) {
|
|
||||||
GUI.removeLayer(layer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClientState() {
|
private ClientState() {
|
||||||
|
@ -143,20 +143,6 @@ public class ControlTriggers {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
//
|
|
||||||
///
|
|
||||||
///
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
public static ControlTriggerInputBased localOf(
|
public static ControlTriggerInputBased localOf(
|
||||||
String id,
|
String id,
|
||||||
Consumer<InputEvent> action,
|
Consumer<InputEvent> action,
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
package ru.windcorp.progressia.client.comms.controls;
|
package ru.windcorp.progressia.client.comms.controls;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.Client;
|
import ru.windcorp.progressia.client.Client;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
import ru.windcorp.progressia.common.comms.packets.Packet;
|
import ru.windcorp.progressia.common.comms.packets.Packet;
|
||||||
|
|
||||||
public class InputBasedControls {
|
public class InputBasedControls {
|
||||||
@ -36,12 +36,12 @@ public class InputBasedControls {
|
|||||||
.toArray(ControlTriggerInputBased[]::new);
|
.toArray(ControlTriggerInputBased[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleInput(Input input) {
|
public void handleInput(InputEvent event) {
|
||||||
for (ControlTriggerInputBased c : controls) {
|
for (ControlTriggerInputBased c : controls) {
|
||||||
Packet packet = c.onInputEvent(input.getEvent());
|
Packet packet = c.onInputEvent(event);
|
||||||
|
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
input.consume();
|
event.consume();
|
||||||
client.getComms().sendPacket(packet);
|
client.getComms().sendPacket(packet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.events;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for all events issued by a {@link Client}.
|
||||||
|
*/
|
||||||
|
public interface ClientEvent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the client instance that this event happened on.
|
||||||
|
*
|
||||||
|
* @return the client
|
||||||
|
*/
|
||||||
|
Client getClient();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the client instance that the event is posted on. The value provided
|
||||||
|
* to this method must be returned by subsequent calls to
|
||||||
|
* {@link #getClient()}. Do not call this method when handling the event.
|
||||||
|
*
|
||||||
|
* @param client the client dispatching the event or {@code null} to unbind
|
||||||
|
* any previously bound client
|
||||||
|
*/
|
||||||
|
void setClient(Client client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A default implementation of {@link ClientEvent}. This is not necessarily
|
||||||
|
* extended by client events.
|
||||||
|
*/
|
||||||
|
public static abstract class Default implements ClientEvent {
|
||||||
|
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
public Default(Client client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Client getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setClient(Client client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.events;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
|
public interface NewLocalEntityEvent extends ClientEvent {
|
||||||
|
|
||||||
|
EntityDataPlayer getNewEntity();
|
||||||
|
EntityDataPlayer getPreviousEntity();
|
||||||
|
|
||||||
|
public class Immutable extends ClientEvent.Default implements NewLocalEntityEvent {
|
||||||
|
|
||||||
|
private final EntityDataPlayer newEntity;
|
||||||
|
private final EntityDataPlayer previousEntity;
|
||||||
|
|
||||||
|
public Immutable(Client client, EntityDataPlayer newEntity, EntityDataPlayer previousEntity) {
|
||||||
|
super(client);
|
||||||
|
this.newEntity = newEntity;
|
||||||
|
this.previousEntity = previousEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDataPlayer getNewEntity() {
|
||||||
|
return newEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDataPlayer getPreviousEntity() {
|
||||||
|
return previousEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -55,6 +55,25 @@ public class Colors {
|
|||||||
output = new Vec4();
|
output = new Vec4();
|
||||||
return color.mul(multiplier, multiplier, multiplier, 1, output);
|
return color.mul(multiplier, multiplier, multiplier, 1, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vec4 mix(Vec4 zero, Vec4 one, float t, Vec4 output) {
|
||||||
|
if (output == null) {
|
||||||
|
output = new Vec4();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t <= 0) {
|
||||||
|
return output.set(zero);
|
||||||
|
} else if (t >= 1) {
|
||||||
|
return output.set(one);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.set(
|
||||||
|
zero.x * (1 - t) + one.x * t,
|
||||||
|
zero.y * (1 - t) + one.y * t,
|
||||||
|
zero.z * (1 - t) + one.z * t,
|
||||||
|
zero.w * (1 - t) + one.w * t
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public static Vec4 toVector(int argb, Vec4 output) {
|
public static Vec4 toVector(int argb, Vec4 output) {
|
||||||
output.w = ((argb & 0xFF000000) >>> 24) / (float) 0xFF; // Alpha
|
output.w = ((argb & 0xFF000000) >>> 24) / (float) 0xFF; // Alpha
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
|
|
||||||
|
public class ExponentAnimation {
|
||||||
|
|
||||||
|
private final float speed;
|
||||||
|
private float value;
|
||||||
|
|
||||||
|
public ExponentAnimation(float speed, float value) {
|
||||||
|
this.speed = speed;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSpeed() {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(float value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float update(float target, double timeStep) {
|
||||||
|
float difference = value - target;
|
||||||
|
value += difference * (1 - Math.exp(speed * timeStep));
|
||||||
|
|
||||||
|
float newDifference = value - target;
|
||||||
|
if (difference * newDifference < 0) {
|
||||||
|
// Whoops, we've overshot
|
||||||
|
value = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float updateForFrame(float target) {
|
||||||
|
return update(target, GraphicsInterface.getFrameLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,15 +23,8 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
import ru.windcorp.progressia.client.graphics.input.CursorEvent;
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent;
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.WheelEvent;
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
|
||||||
|
|
||||||
public class GUI {
|
public class GUI {
|
||||||
|
|
||||||
@ -46,15 +39,6 @@ public class GUI {
|
|||||||
private static final List<LayerStackModification> MODIFICATION_QUEUE = Collections
|
private static final List<LayerStackModification> MODIFICATION_QUEUE = Collections
|
||||||
.synchronizedList(new ArrayList<>());
|
.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
private static class ModifiableInput extends Input {
|
|
||||||
@Override
|
|
||||||
public void initialize(InputEvent event, Target target) {
|
|
||||||
super.initialize(event, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final ModifiableInput THE_INPUT = new ModifiableInput();
|
|
||||||
|
|
||||||
private GUI() {
|
private GUI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +65,12 @@ public class GUI {
|
|||||||
layer.onRemoved();
|
layer.onRemoved();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void updateLayer(Layer layer) {
|
||||||
|
modify(layers -> {
|
||||||
|
// Do nothing
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static void modify(LayerStackModification mod) {
|
private static void modify(LayerStackModification mod) {
|
||||||
MODIFICATION_QUEUE.add(mod);
|
MODIFICATION_QUEUE.add(mod);
|
||||||
@ -126,43 +116,12 @@ public class GUI {
|
|||||||
LAYERS.forEach(Layer::invalidate);
|
LAYERS.forEach(Layer::invalidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dispatchInputEvent(InputEvent event) {
|
public static void dispatchInput(InputEvent event) {
|
||||||
Input.Target target;
|
synchronized (LAYERS) {
|
||||||
|
for (int i = 0; i < LAYERS.size(); ++i) {
|
||||||
if (event instanceof KeyEvent) {
|
LAYERS.get(i).handleInput(event);
|
||||||
if (((KeyEvent) event).isMouse()) {
|
|
||||||
target = Input.Target.HOVERED;
|
|
||||||
} else {
|
|
||||||
target = Input.Target.FOCUSED;
|
|
||||||
}
|
}
|
||||||
} else if (event instanceof CursorEvent) {
|
|
||||||
target = Input.Target.HOVERED;
|
|
||||||
} else if (event instanceof WheelEvent) {
|
|
||||||
target = Input.Target.HOVERED;
|
|
||||||
} else if (event instanceof FrameResizeEvent) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
target = Input.Target.ALL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
THE_INPUT.initialize(event, target);
|
|
||||||
LAYERS.forEach(l -> l.handleInput(THE_INPUT));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object getEventSubscriber() {
|
|
||||||
return new Object() {
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onFrameResized(FrameResizeEvent event) {
|
|
||||||
GUI.invalidateEverything();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onInput(InputEvent event) {
|
|
||||||
dispatchInputEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ package ru.windcorp.progressia.client.graphics;
|
|||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
|
||||||
public abstract class Layer {
|
public abstract class Layer {
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ public abstract class Layer {
|
|||||||
|
|
||||||
protected abstract void doRender();
|
protected abstract void doRender();
|
||||||
|
|
||||||
protected abstract void handleInput(Input input);
|
public abstract void handleInput(InputEvent input);
|
||||||
|
|
||||||
protected int getWidth() {
|
protected int getWidth() {
|
||||||
return GraphicsInterface.getFrameWidth();
|
return GraphicsInterface.getFrameWidth();
|
||||||
|
@ -68,6 +68,10 @@ public class GraphicsInterface {
|
|||||||
public static void subscribeToInputEvents(Object listener) {
|
public static void subscribeToInputEvents(Object listener) {
|
||||||
InputHandler.register(listener);
|
InputHandler.register(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void unsubscribeFromInputEvents(Object listener) {
|
||||||
|
InputHandler.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
public static void startNextLayer() {
|
public static void startNextLayer() {
|
||||||
GraphicsBackend.startNextLayer();
|
GraphicsBackend.startNextLayer();
|
||||||
|
@ -39,6 +39,7 @@ public class InputHandler {
|
|||||||
|
|
||||||
public void initialize(int key, int scancode, int action, int mods) {
|
public void initialize(int key, int scancode, int action, int mods) {
|
||||||
this.setTime(GraphicsInterface.getTime());
|
this.setTime(GraphicsInterface.getTime());
|
||||||
|
this.setConsumed(false);
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.scancode = scancode;
|
this.scancode = scancode;
|
||||||
this.action = action;
|
this.action = action;
|
||||||
@ -59,7 +60,7 @@ public class InputHandler {
|
|||||||
if (GraphicsBackend.getWindowHandle() != window)
|
if (GraphicsBackend.getWindowHandle() != window)
|
||||||
return;
|
return;
|
||||||
THE_KEY_EVENT.initialize(key, scancode, action, mods);
|
THE_KEY_EVENT.initialize(key, scancode, action, mods);
|
||||||
dispatch(THE_KEY_EVENT);
|
INPUT_EVENT_BUS.post(THE_KEY_EVENT);
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case GLFW.GLFW_PRESS:
|
case GLFW.GLFW_PRESS:
|
||||||
@ -90,6 +91,7 @@ public class InputHandler {
|
|||||||
|
|
||||||
public void initialize(double x, double y) {
|
public void initialize(double x, double y) {
|
||||||
this.setTime(GraphicsInterface.getTime());
|
this.setTime(GraphicsInterface.getTime());
|
||||||
|
this.setConsumed(false);
|
||||||
getNewPosition().set(x, y);
|
getNewPosition().set(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +111,7 @@ public class InputHandler {
|
|||||||
InputTracker.initializeCursorPosition(x, y);
|
InputTracker.initializeCursorPosition(x, y);
|
||||||
|
|
||||||
THE_CURSOR_MOVE_EVENT.initialize(x, y);
|
THE_CURSOR_MOVE_EVENT.initialize(x, y);
|
||||||
dispatch(THE_CURSOR_MOVE_EVENT);
|
INPUT_EVENT_BUS.post(THE_CURSOR_MOVE_EVENT);
|
||||||
|
|
||||||
InputTracker.getCursorPosition().set(x, y);
|
InputTracker.getCursorPosition().set(x, y);
|
||||||
}
|
}
|
||||||
@ -124,6 +126,7 @@ public class InputHandler {
|
|||||||
|
|
||||||
public void initialize(double xOffset, double yOffset) {
|
public void initialize(double xOffset, double yOffset) {
|
||||||
this.setTime(GraphicsInterface.getTime());
|
this.setTime(GraphicsInterface.getTime());
|
||||||
|
this.setConsumed(false);
|
||||||
this.getOffset().set(xOffset, yOffset);
|
this.getOffset().set(xOffset, yOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +142,7 @@ public class InputHandler {
|
|||||||
if (GraphicsBackend.getWindowHandle() != window)
|
if (GraphicsBackend.getWindowHandle() != window)
|
||||||
return;
|
return;
|
||||||
THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset);
|
THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset);
|
||||||
dispatch(THE_WHEEL_SCROLL_EVENT);
|
INPUT_EVENT_BUS.post(THE_WHEEL_SCROLL_EVENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FrameResizeEvent
|
// FrameResizeEvent
|
||||||
@ -152,6 +155,7 @@ public class InputHandler {
|
|||||||
|
|
||||||
public void initialize(int width, int height) {
|
public void initialize(int width, int height) {
|
||||||
this.setTime(GraphicsInterface.getTime());
|
this.setTime(GraphicsInterface.getTime());
|
||||||
|
this.setConsumed(false);
|
||||||
this.getNewSize().set(width, height);
|
this.getNewSize().set(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,17 +171,17 @@ public class InputHandler {
|
|||||||
int height
|
int height
|
||||||
) {
|
) {
|
||||||
THE_FRAME_RESIZE_EVENT.initialize(width, height);
|
THE_FRAME_RESIZE_EVENT.initialize(width, height);
|
||||||
dispatch(THE_FRAME_RESIZE_EVENT);
|
INPUT_EVENT_BUS.post(THE_FRAME_RESIZE_EVENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
|
|
||||||
private static void dispatch(InputEvent event) {
|
|
||||||
INPUT_EVENT_BUS.post(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void register(Object listener) {
|
public static void register(Object listener) {
|
||||||
INPUT_EVENT_BUS.register(listener);
|
INPUT_EVENT_BUS.register(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void unregister(Object listener) {
|
||||||
|
INPUT_EVENT_BUS.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,11 @@ import static org.lwjgl.system.MemoryUtil.*;
|
|||||||
|
|
||||||
import org.lwjgl.opengl.GL;
|
import org.lwjgl.opengl.GL;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.graphics.GUI;
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
|
||||||
class LWJGLInitializer {
|
class LWJGLInitializer {
|
||||||
|
|
||||||
@ -107,7 +111,20 @@ class LWJGLInitializer {
|
|||||||
|
|
||||||
glfwSetScrollCallback(handle, InputHandler::handleWheelScroll);
|
glfwSetScrollCallback(handle, InputHandler::handleWheelScroll);
|
||||||
|
|
||||||
GraphicsInterface.subscribeToInputEvents(GUI.getEventSubscriber());
|
GraphicsInterface.subscribeToInputEvents(new Object() {
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onFrameResized(FrameResizeEvent event) {
|
||||||
|
GUI.invalidateEverything();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onInputEvent(InputEvent event) {
|
||||||
|
GUI.dispatchInput(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,8 @@ public class RenderTarget {
|
|||||||
assembleCurrentClipFromFaces();
|
assembleCurrentClipFromFaces();
|
||||||
|
|
||||||
float depth = this.depth--;
|
float depth = this.depth--;
|
||||||
Mat4 transform = new Mat4().translate(0, 0, depth).mul(getTransform());
|
final float kostyl = 1e-2f;
|
||||||
|
Mat4 transform = new Mat4().translate(0, 0, depth).scale(1, 1, kostyl).mul(getTransform());
|
||||||
assembled.add(new Clip(maskStack, transform, renderable));
|
assembled.add(new Clip(maskStack, transform, renderable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,20 +32,23 @@ public class Font {
|
|||||||
private final int style;
|
private final int style;
|
||||||
private final float align;
|
private final float align;
|
||||||
private final Vec4 color;
|
private final Vec4 color;
|
||||||
|
|
||||||
|
private final int scale;
|
||||||
|
|
||||||
public Font(Typeface typeface, int style, float align, Vec4 color) {
|
public Font(Typeface typeface, int style, float align, Vec4 color, int scale) {
|
||||||
this.typeface = typeface;
|
this.typeface = typeface;
|
||||||
this.style = style;
|
this.style = style;
|
||||||
this.align = align;
|
this.align = align;
|
||||||
this.color = color;
|
this.color = color;
|
||||||
|
this.scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font(Typeface typeface, int style, float align, int color) {
|
public Font(Typeface typeface, int style, float align, int color, int scale) {
|
||||||
this(typeface, style, align, Colors.toVector(color));
|
this(typeface, style, align, Colors.toVector(color), scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font(Typeface typeface) {
|
public Font(Typeface typeface) {
|
||||||
this(typeface, Typeface.Style.PLAIN, Typeface.ALIGN_LEFT, Colors.WHITE);
|
this(typeface, Typeface.Style.PLAIN, Typeface.ALIGN_LEFT, Colors.WHITE, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font() {
|
public Font() {
|
||||||
@ -67,31 +70,63 @@ public class Font {
|
|||||||
public Vec4 getColor() {
|
public Vec4 getColor() {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Renderable assemble(
|
public int getScale() {
|
||||||
CharSequence chars,
|
return scale;
|
||||||
float maxWidth
|
}
|
||||||
) {
|
|
||||||
return typeface.assembleStatic(chars, style, align, maxWidth, color);
|
private Renderable applyScale(Renderable unscaled) {
|
||||||
|
if (scale == 1) {
|
||||||
|
return unscaled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderer -> {
|
||||||
|
renderer.pushTransform().scale(scale);
|
||||||
|
unscaled.render(renderer);
|
||||||
|
renderer.popTransform();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public Renderable assembleDynamic(
|
public Renderable assemble(CharSequence chars, float maxWidth) {
|
||||||
Supplier<CharSequence> supplier,
|
return applyScale(typeface.assembleStatic(chars, style, align, maxWidth, color));
|
||||||
float maxWidth
|
}
|
||||||
) {
|
|
||||||
return typeface.assembleDynamic(supplier, style, align, maxWidth, color);
|
public Renderable assembleDynamic(Supplier<CharSequence> supplier, float maxWidth) {
|
||||||
|
return applyScale(typeface.assembleDynamic(supplier, style, align, maxWidth, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Renderable assemble(CharSequence chars) {
|
||||||
|
return assemble(chars, Float.POSITIVE_INFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Renderable assembleDynamic(Supplier<CharSequence> supplier) {
|
||||||
|
return assembleDynamic(supplier, Float.POSITIVE_INFINITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWidth(CharSequence chars, float maxWidth) {
|
public int getWidth(CharSequence chars, float maxWidth) {
|
||||||
return typeface.getWidth(chars, style, align, maxWidth);
|
return scale * typeface.getWidth(chars, style, align, maxWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHeight(CharSequence chars, float maxWidth) {
|
public int getHeight(CharSequence chars, float maxWidth) {
|
||||||
return typeface.getHeight(chars, style, align, maxWidth);
|
return scale * typeface.getHeight(chars, style, align, maxWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec2i getSize(CharSequence chars, float maxWidth, Vec2i result) {
|
public Vec2i getSize(CharSequence chars, float maxWidth, Vec2i result) {
|
||||||
return typeface.getSize(chars, style, align, maxWidth, result);
|
result = typeface.getSize(chars, style, align, maxWidth, result);
|
||||||
|
result.mul(scale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth(CharSequence chars) {
|
||||||
|
return getWidth(chars, Float.POSITIVE_INFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight(CharSequence chars) {
|
||||||
|
return getHeight(chars, Float.POSITIVE_INFINITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec2i getSize(CharSequence chars, Vec2i result) {
|
||||||
|
return getSize(chars, Float.POSITIVE_INFINITY, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean supports(char c) {
|
public boolean supports(char c) {
|
||||||
@ -106,7 +141,7 @@ public class Font {
|
|||||||
* @return the new font
|
* @return the new font
|
||||||
*/
|
*/
|
||||||
public Font withStyle(int style) {
|
public Font withStyle(int style) {
|
||||||
return new Font(getTypeface(), style, getAlign(), getColor());
|
return new Font(getTypeface(), style, getAlign(), getColor(), getScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font deriveBold() {
|
public Font deriveBold() {
|
||||||
@ -158,15 +193,19 @@ public class Font {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Font withAlign(float align) {
|
public Font withAlign(float align) {
|
||||||
return new Font(getTypeface(), getStyle(), align, getColor());
|
return new Font(getTypeface(), getStyle(), align, getColor(), getScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font withColor(Vec4 color) {
|
public Font withColor(Vec4 color) {
|
||||||
return new Font(getTypeface(), getStyle(), getAlign(), color);
|
return new Font(getTypeface(), getStyle(), getAlign(), color, getScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font withColor(int color) {
|
public Font withColor(int color) {
|
||||||
return new Font(getTypeface(), getStyle(), getAlign(), color);
|
return new Font(getTypeface(), getStyle(), getAlign(), color, getScale());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Font withScale(int scale) {
|
||||||
|
return new Font(getTypeface(), getStyle(), getAlign(), getColor(), scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,24 +48,25 @@ public abstract class BasicButton extends Component {
|
|||||||
this.label = label;
|
this.label = label;
|
||||||
|
|
||||||
setLayout(new LayoutAlign(10));
|
setLayout(new LayoutAlign(10));
|
||||||
addChild(this.label);
|
if (label != null) {
|
||||||
|
addChild(this.label);
|
||||||
|
}
|
||||||
|
|
||||||
setFocusable(true);
|
setFocusable(true);
|
||||||
reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE);
|
reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE);
|
||||||
|
|
||||||
// Click triggers
|
// Click triggers
|
||||||
addListener(KeyEvent.class, e -> {
|
addInputListener(KeyEvent.class, e -> {
|
||||||
if (e.isRepeat()) {
|
if (e.isRepeat())
|
||||||
return false;
|
return;
|
||||||
} else if (
|
|
||||||
|
if (
|
||||||
e.isLeftMouseButton() ||
|
e.isLeftMouseButton() ||
|
||||||
e.getKey() == GLFW.GLFW_KEY_SPACE ||
|
e.getKey() == GLFW.GLFW_KEY_SPACE ||
|
||||||
e.getKey() == GLFW.GLFW_KEY_ENTER
|
e.getKey() == GLFW.GLFW_KEY_ENTER
|
||||||
) {
|
) {
|
||||||
setPressed(e.isPress());
|
setPressed(e.isPress());
|
||||||
return true;
|
e.consume();
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -152,5 +153,9 @@ public abstract class BasicButton extends Component {
|
|||||||
public Label getLabel() {
|
public Label getLabel() {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasLabel() {
|
||||||
|
return label != null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,9 @@ import ru.windcorp.progressia.client.graphics.Colors;
|
|||||||
|
|
||||||
public class Button extends BasicButton {
|
public class Button extends BasicButton {
|
||||||
|
|
||||||
|
public static final int MARGIN = 2;
|
||||||
|
public static final int BORDER = 2;
|
||||||
|
|
||||||
public Button(String name, String label, Font labelFont) {
|
public Button(String name, String label, Font labelFont) {
|
||||||
super(name, label, labelFont);
|
super(name, label, labelFont);
|
||||||
}
|
}
|
||||||
@ -60,15 +63,23 @@ public class Button extends BasicButton {
|
|||||||
} else {
|
} else {
|
||||||
backgroundColor = Colors.WHITE;
|
backgroundColor = Colors.WHITE;
|
||||||
}
|
}
|
||||||
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor);
|
target.fill(
|
||||||
|
getX() + MARGIN,
|
||||||
|
getY() + MARGIN,
|
||||||
|
getWidth() - 2 * MARGIN,
|
||||||
|
getHeight() - 2 * MARGIN,
|
||||||
|
backgroundColor
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change label font color
|
// Change label font color
|
||||||
|
|
||||||
if (isPressed()) {
|
if (hasLabel()) {
|
||||||
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
|
if (isPressed()) {
|
||||||
} else {
|
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
|
||||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
} else {
|
||||||
|
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,25 +25,27 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
|
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
import glm.vec._2.i.Vec2i;
|
import glm.vec._2.i.Vec2i;
|
||||||
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.AssembledFlatRenderHelper;
|
||||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget.Clip;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.ChildAddedEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.ChildRemovedEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.EnableEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.FocusEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.gui.event.ParentChangedEvent;
|
import ru.windcorp.progressia.client.graphics.gui.event.ParentChangedEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
|
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
|
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
import ru.windcorp.progressia.common.util.Named;
|
import ru.windcorp.progressia.common.util.Named;
|
||||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
||||||
@ -55,7 +57,7 @@ public class Component extends Named {
|
|||||||
private Component parent = null;
|
private Component parent = null;
|
||||||
|
|
||||||
private EventBus eventBus = null;
|
private EventBus eventBus = null;
|
||||||
private InputBus inputBus = null;
|
private final InputBus inputBus = new InputBus(this);
|
||||||
|
|
||||||
private int x, y;
|
private int x, y;
|
||||||
private int width, height;
|
private int width, height;
|
||||||
@ -76,6 +78,9 @@ public class Component extends Named {
|
|||||||
|
|
||||||
public Component(String name) {
|
public Component(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
|
// Update hover flag when cursor moves
|
||||||
|
addInputListener(CursorMoveEvent.class, this::updateHoverFlag, InputBus.Option.ALWAYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Component getParent() {
|
public Component getParent() {
|
||||||
@ -521,6 +526,10 @@ public class Component extends Named {
|
|||||||
dispatchEvent(new HoverEvent(this, isHovered));
|
dispatchEvent(new HoverEvent(this, isHovered));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateHoverFlag(CursorMoveEvent e) {
|
||||||
|
setHovered(contains((int) InputTracker.getCursorX(), (int) InputTracker.getCursorY()));
|
||||||
|
}
|
||||||
|
|
||||||
public void addListener(Object listener) {
|
public void addListener(Object listener) {
|
||||||
if (eventBus == null) {
|
if (eventBus == null) {
|
||||||
@ -542,121 +551,30 @@ public class Component extends Named {
|
|||||||
eventBus.post(event);
|
eventBus.post(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends InputEvent> void addListener(
|
public <T extends InputEvent> void addInputListener(Class<? extends T> type, InputListener<T> listener, InputBus.Option... options) {
|
||||||
Class<? extends T> type,
|
inputBus.register(type, listener, options);
|
||||||
boolean handlesConsumed,
|
}
|
||||||
InputListener<T> listener
|
|
||||||
) {
|
public void addKeyListener(KeyMatcher matcher, InputListener<? super KeyEvent> listener, InputBus.Option... options) {
|
||||||
if (inputBus == null) {
|
inputBus.register(matcher, listener, options);
|
||||||
inputBus = new InputBus();
|
|
||||||
}
|
|
||||||
|
|
||||||
inputBus.register(type, handlesConsumed, listener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends InputEvent> void addListener(Class<? extends T> type, InputListener<T> listener) {
|
public void removeInputListener(InputListener<?> listener) {
|
||||||
if (inputBus == null) {
|
inputBus.unregister(listener);
|
||||||
inputBus = new InputBus();
|
|
||||||
}
|
|
||||||
|
|
||||||
inputBus.register(type, listener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeListener(InputListener<?> listener) {
|
protected boolean passInputToChildren(InputEvent e) {
|
||||||
if (inputBus != null) {
|
return true;
|
||||||
inputBus.unregister(listener);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleInput(Input input) {
|
InputBus getInputBus() {
|
||||||
if (inputBus != null && isEnabled()) {
|
return inputBus;
|
||||||
inputBus.dispatch(input);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispatchInput(Input input) {
|
|
||||||
try {
|
|
||||||
switch (input.getTarget()) {
|
|
||||||
case FOCUSED:
|
|
||||||
dispatchInputToFocused(input);
|
|
||||||
break;
|
|
||||||
case HOVERED:
|
|
||||||
dispatchInputToHovered(input);
|
|
||||||
break;
|
|
||||||
case ALL:
|
|
||||||
default:
|
|
||||||
dispatchInputToAll(input);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw CrashReports.report(e, "Could not dispatch input to Component %s", this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dispatchInputToFocused(Input input) {
|
|
||||||
Component c = findFocused();
|
|
||||||
|
|
||||||
if (c == null)
|
|
||||||
return;
|
|
||||||
if (attemptFocusTransfer(input, c))
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (c != null) {
|
|
||||||
c.handleInput(input);
|
|
||||||
c = c.getParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dispatchInputToHovered(Input input) {
|
|
||||||
getChildren().forEach(child -> {
|
|
||||||
if (child.containsCursor()) {
|
|
||||||
child.setHovered(true);
|
|
||||||
|
|
||||||
if (!input.isConsumed()) {
|
|
||||||
child.dispatchInput(input);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
child.setHovered(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
handleInput(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dispatchInputToAll(Input input) {
|
|
||||||
getChildren().forEach(c -> c.dispatchInput(input));
|
|
||||||
handleInput(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean attemptFocusTransfer(Input input, Component focused) {
|
|
||||||
if (input.isConsumed())
|
|
||||||
return false;
|
|
||||||
if (!(input.getEvent() instanceof KeyEvent))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
KeyEvent keyInput = (KeyEvent) input.getEvent();
|
|
||||||
|
|
||||||
if (keyInput.getKey() == GLFW.GLFW_KEY_TAB && !keyInput.isRelease()) {
|
|
||||||
input.consume();
|
|
||||||
if (keyInput.hasShift()) {
|
|
||||||
focused.focusPrevious();
|
|
||||||
} else {
|
|
||||||
focused.focusNext();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized boolean contains(int x, int y) {
|
public synchronized boolean contains(int x, int y) {
|
||||||
return x >= getX() && x < getX() + getWidth() && y >= getY() && y < getY() + getHeight();
|
return x >= getX() && x < getX() + getWidth() && y >= getY() && y < getY() + getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean containsCursor() {
|
|
||||||
return contains((int) InputTracker.getCursorX(), (int) InputTracker.getCursorY());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestReassembly() {
|
public void requestReassembly() {
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
parent.requestReassembly();
|
parent.requestReassembly();
|
||||||
@ -844,6 +762,20 @@ public class Component extends Named {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Renderable assembleToRenderable() {
|
||||||
|
|
||||||
|
RenderTarget target = new RenderTarget();
|
||||||
|
assemble(target);
|
||||||
|
Clip[] clips = target.assemble();
|
||||||
|
|
||||||
|
return renderer -> {
|
||||||
|
for (Clip clip : clips) {
|
||||||
|
clip.render((AssembledFlatRenderHelper) renderer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// /**
|
// /**
|
||||||
// * Returns a component that displays this component in its center.
|
// * Returns a component that displays this component in its center.
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.gui;
|
||||||
|
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||||
|
|
||||||
|
public class Components {
|
||||||
|
|
||||||
|
public static Component center(Component c) {
|
||||||
|
return new Group(c.getName() + ".Centerer", new LayoutAlign(), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Component hide(Component c, BooleanSupplier shouldHide) {
|
||||||
|
return new Hider(c.getName() + ".Hider", c, shouldHide);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Components() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.gui;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import glm.vec._2.d.Vec2d;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.event.DragEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.event.DragStartEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.event.DragStopEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.CursorMoveEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
|
||||||
|
|
||||||
|
public class DragManager {
|
||||||
|
|
||||||
|
private Component component;
|
||||||
|
|
||||||
|
private boolean isDragged = false;
|
||||||
|
private final Vec2d change = new Vec2d();
|
||||||
|
|
||||||
|
public void install(Component c) {
|
||||||
|
Objects.requireNonNull(c, "c");
|
||||||
|
if (c == component) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (component != null) {
|
||||||
|
throw new IllegalStateException("Already installed on " + component + "; attempted to install on " + c);
|
||||||
|
}
|
||||||
|
|
||||||
|
component = c;
|
||||||
|
|
||||||
|
c.addInputListener(CursorMoveEvent.class, this::onCursorMove, InputBus.Option.ALWAYS);
|
||||||
|
c.addKeyListener(KeyMatcher.LMB, this::onLMB, InputBus.Option.ALWAYS, InputBus.Option.IGNORE_ACTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCursorMove(CursorMoveEvent e) {
|
||||||
|
if (isDragged) {
|
||||||
|
Vec2d currentChange = e.getChange(null);
|
||||||
|
change.add(currentChange);
|
||||||
|
component.dispatchEvent(new DragEvent(component, currentChange, change));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onLMB(KeyEvent e) {
|
||||||
|
if (isDragged && e.isRelease()) {
|
||||||
|
|
||||||
|
isDragged = false;
|
||||||
|
component.dispatchEvent(new DragStopEvent(component, change));
|
||||||
|
|
||||||
|
} else if (!isDragged && !e.isConsumed() && e.isPress() && component.isHovered()) {
|
||||||
|
|
||||||
|
isDragged = true;
|
||||||
|
change.set(0, 0);
|
||||||
|
component.dispatchEvent(new DragStartEvent(component));
|
||||||
|
e.consume();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -33,7 +33,7 @@ public class DynamicLabel extends Component {
|
|||||||
super(name);
|
super(name);
|
||||||
this.font = font;
|
this.font = font;
|
||||||
this.contents = contents;
|
this.contents = contents;
|
||||||
setPreferredSize(width, font.getHeight("", Float.POSITIVE_INFINITY) * 2);
|
setPreferredSize(width, font.getHeight("", Float.POSITIVE_INFINITY));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Font getFont() {
|
public Font getFont() {
|
||||||
@ -46,7 +46,7 @@ public class DynamicLabel extends Component {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void assembleSelf(RenderTarget target) {
|
protected void assembleSelf(RenderTarget target) {
|
||||||
target.pushTransform(new Mat4().identity().translate(getX(), getY(), -1000).scale(2));
|
target.pushTransform(new Mat4().identity().translate(getX(), getY(), -1000));
|
||||||
target.addCustomRenderer(font.assembleDynamic(getContentSupplier(), Float.POSITIVE_INFINITY));
|
target.addCustomRenderer(font.assembleDynamic(getContentSupplier(), Float.POSITIVE_INFINITY));
|
||||||
target.popTransform();
|
target.popTransform();
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,20 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ru.windcorp.progressia.client.graphics.gui;
|
package ru.windcorp.progressia.client.graphics.gui;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer;
|
import ru.windcorp.progressia.client.graphics.flat.AssembledFlatLayer;
|
||||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
|
||||||
|
import ru.windcorp.progressia.common.util.LowOverheadCache;
|
||||||
|
import ru.windcorp.progressia.common.util.StashingStack;
|
||||||
|
|
||||||
public abstract class GUILayer extends AssembledFlatLayer {
|
public abstract class GUILayer extends AssembledFlatLayer {
|
||||||
|
|
||||||
@ -33,7 +41,9 @@ public abstract class GUILayer extends AssembledFlatLayer {
|
|||||||
|
|
||||||
public GUILayer(String name, Layout layout) {
|
public GUILayer(String name, Layout layout) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
getRoot().setLayout(layout);
|
getRoot().setLayout(layout);
|
||||||
|
getRoot().addInputListener(KeyEvent.class, this::attemptFocusTransfer, InputBus.Option.IGNORE_FOCUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Component getRoot() {
|
public Component getRoot() {
|
||||||
@ -47,9 +57,85 @@ public abstract class GUILayer extends AssembledFlatLayer {
|
|||||||
getRoot().assemble(target);
|
getRoot().assemble(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stack frame for {@link #handleInput(InputEvent)}.
|
||||||
|
*/
|
||||||
|
private static class EventHandlingFrame {
|
||||||
|
Component component;
|
||||||
|
Iterator<Component> children;
|
||||||
|
|
||||||
|
void init(Component c) {
|
||||||
|
component = c;
|
||||||
|
children = c.getChildren().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
component = null;
|
||||||
|
children = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stacks for {@link #handleInput(InputEvent)}.
|
||||||
|
*/
|
||||||
|
private final LowOverheadCache<StashingStack<EventHandlingFrame>> pathCache = new LowOverheadCache<>(
|
||||||
|
() -> new StashingStack<>(64, EventHandlingFrame::new)
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is essentially a depth-first iteration of the component tree. The
|
||||||
|
* recursive procedure has been unrolled to reduce call stack length.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void handleInput(Input input) {
|
public void handleInput(InputEvent event) {
|
||||||
getRoot().dispatchInput(input);
|
StashingStack<EventHandlingFrame> path = pathCache.grab();
|
||||||
|
|
||||||
|
if (!path.isEmpty()) {
|
||||||
|
throw new IllegalStateException("path is not empty: " + path);
|
||||||
|
}
|
||||||
|
|
||||||
|
path.push().init(root);
|
||||||
|
|
||||||
|
while (!path.isEmpty()) {
|
||||||
|
|
||||||
|
Iterator<Component> it = path.peek().children;
|
||||||
|
if (it.hasNext()) {
|
||||||
|
|
||||||
|
Component c = it.next();
|
||||||
|
|
||||||
|
if (c.isEnabled()) {
|
||||||
|
if (c.getChildren().isEmpty() || !c.passInputToChildren(event)) {
|
||||||
|
c.getInputBus().dispatch(event);
|
||||||
|
} else {
|
||||||
|
path.push().init(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
path.peek().component.getInputBus().dispatch(event);
|
||||||
|
path.pop().reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pathCache.release(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void attemptFocusTransfer(KeyEvent e) {
|
||||||
|
Component focused = getRoot().findFocused();
|
||||||
|
|
||||||
|
if (focused == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.getKey() == GLFW.GLFW_KEY_TAB && !e.isRelease()) {
|
||||||
|
e.consume();
|
||||||
|
if (e.hasShift()) {
|
||||||
|
focused.focusPrevious();
|
||||||
|
} else {
|
||||||
|
focused.focusNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -24,5 +24,13 @@ public class Group extends Component {
|
|||||||
super(name);
|
super(name);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Group(String name, Layout layout, Component... children) {
|
||||||
|
this(name, layout);
|
||||||
|
|
||||||
|
for (Component child : children) {
|
||||||
|
addChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.gui;
|
||||||
|
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
|
||||||
|
public class Hider extends Component {
|
||||||
|
|
||||||
|
private final BooleanSupplier shouldHide;
|
||||||
|
private final Component contents;
|
||||||
|
|
||||||
|
public Hider(String name, Component contents, BooleanSupplier shouldHide) {
|
||||||
|
super(name);
|
||||||
|
this.contents = contents;
|
||||||
|
this.shouldHide = shouldHide;
|
||||||
|
|
||||||
|
setLayout(new LayoutFill());
|
||||||
|
addChild(contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean passInputToChildren(InputEvent e) {
|
||||||
|
return !shouldHide.getAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized Component findFocused() {
|
||||||
|
if (shouldHide.getAsBoolean()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.findFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleChildren(RenderTarget target) {
|
||||||
|
Renderable renderable = contents.assembleToRenderable();
|
||||||
|
target.addCustomRenderer(renderer -> {
|
||||||
|
if (!shouldHide.getAsBoolean()) {
|
||||||
|
renderable.render(renderer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -70,7 +70,7 @@ public class Label extends Component {
|
|||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
currentText = contents.get();
|
currentText = contents.get();
|
||||||
currentSize = font.getSize(currentText, maxWidth, null).mul(2);
|
currentSize = font.getSize(currentText, maxWidth, null);
|
||||||
requestReassembly();
|
requestReassembly();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,12 +99,8 @@ public class Label extends Component {
|
|||||||
protected void assembleSelf(RenderTarget target) {
|
protected void assembleSelf(RenderTarget target) {
|
||||||
float startX = getX() + font.getAlign() * (getWidth() - currentSize.x);
|
float startX = getX() + font.getAlign() * (getWidth() - currentSize.x);
|
||||||
|
|
||||||
target.pushTransform(
|
target.pushTransform(new Mat4().identity().translate(startX, getY(), 0));
|
||||||
new Mat4().identity().translate(startX, getY(), 0).scale(2)
|
|
||||||
);
|
|
||||||
|
|
||||||
target.addCustomRenderer(font.assemble(currentText, maxWidth));
|
target.addCustomRenderer(font.assemble(currentText, maxWidth));
|
||||||
|
|
||||||
target.popTransform();
|
target.popTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,26 +104,22 @@ public class RadioButton extends BasicButton {
|
|||||||
group.addChild(basicChild);
|
group.addChild(basicChild);
|
||||||
addChild(group);
|
addChild(group);
|
||||||
|
|
||||||
addListener(KeyEvent.class, e -> {
|
addInputListener(KeyEvent.class, e -> {
|
||||||
if (e.isRelease())
|
if (e.isRelease()) return;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) {
|
if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) {
|
||||||
if (this.group != null) {
|
if (this.group != null) {
|
||||||
this.group.selectPrevious();
|
this.group.selectPrevious();
|
||||||
this.group.getSelected().takeFocus();
|
this.group.getSelected().takeFocus();
|
||||||
}
|
}
|
||||||
|
e.consume();
|
||||||
return true;
|
|
||||||
} else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) {
|
} else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) {
|
||||||
if (this.group != null) {
|
if (this.group != null) {
|
||||||
this.group.selectNext();
|
this.group.selectNext();
|
||||||
this.group.getSelected().takeFocus();
|
this.group.getSelected().takeFocus();
|
||||||
}
|
}
|
||||||
return true;
|
e.consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
addAction(b -> setChecked(true));
|
addAction(b -> setChecked(true));
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.gui.event;
|
||||||
|
|
||||||
|
import glm.vec._2.d.Vec2d;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
|
||||||
|
public class DragEvent extends ComponentEvent {
|
||||||
|
|
||||||
|
private final Vec2d currentChange = new Vec2d();
|
||||||
|
private final Vec2d totalChange = new Vec2d();
|
||||||
|
|
||||||
|
public DragEvent(Component component, Vec2d currentChange, Vec2d totalChange) {
|
||||||
|
super(component);
|
||||||
|
this.currentChange.set(currentChange.x, currentChange.y);
|
||||||
|
this.totalChange.set(totalChange.x, totalChange.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec2d getCurrentChange() {
|
||||||
|
return currentChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCurrentChangeX() {
|
||||||
|
return currentChange.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCurrentChangeY() {
|
||||||
|
return currentChange.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec2d getTotalChange() {
|
||||||
|
return totalChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTotalChangeX() {
|
||||||
|
return totalChange.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTotalChangeY() {
|
||||||
|
return totalChange.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.gui.event;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
|
||||||
|
public class DragStartEvent extends ComponentEvent {
|
||||||
|
|
||||||
|
public DragStartEvent(Component component) {
|
||||||
|
super(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.gui.event;
|
||||||
|
|
||||||
|
import glm.vec._2.d.Vec2d;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
|
||||||
|
public class DragStopEvent extends ComponentEvent {
|
||||||
|
|
||||||
|
private final Vec2d totalChange = new Vec2d();
|
||||||
|
|
||||||
|
public DragStopEvent(Component component, Vec2d totalChange) {
|
||||||
|
super(component);
|
||||||
|
this.totalChange.set(totalChange.x, totalChange.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec2d getTotalChange() {
|
||||||
|
return totalChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTotalChangeX() {
|
||||||
|
return totalChange.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTotalChangeY() {
|
||||||
|
return totalChange.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -33,7 +33,6 @@ import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
|||||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
|
||||||
import ru.windcorp.progressia.client.localization.MutableString;
|
import ru.windcorp.progressia.client.localization.MutableString;
|
||||||
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||||
|
|
||||||
@ -97,11 +96,9 @@ public class MenuLayer extends GUILayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleInput(Input input) {
|
public void handleInput(InputEvent event) {
|
||||||
|
|
||||||
if (!input.isConsumed()) {
|
if (!event.isConsumed()) {
|
||||||
InputEvent event = input.getEvent();
|
|
||||||
|
|
||||||
if (event instanceof KeyEvent) {
|
if (event instanceof KeyEvent) {
|
||||||
KeyEvent keyEvent = (KeyEvent) event;
|
KeyEvent keyEvent = (KeyEvent) event;
|
||||||
if (keyEvent.isPress() && keyEvent.getKey() == GLFW.GLFW_KEY_ESCAPE) {
|
if (keyEvent.isPress() && keyEvent.getKey() == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
@ -110,8 +107,8 @@ public class MenuLayer extends GUILayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.handleInput(input);
|
super.handleInput(event);
|
||||||
input.consume();
|
event.consume();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
package ru.windcorp.progressia.client.graphics.input;
|
package ru.windcorp.progressia.client.graphics.input;
|
||||||
|
|
||||||
import glm.vec._2.Vec2;
|
|
||||||
import glm.vec._2.d.Vec2d;
|
import glm.vec._2.d.Vec2d;
|
||||||
|
|
||||||
public class CursorMoveEvent extends CursorEvent {
|
public class CursorMoveEvent extends CursorEvent {
|
||||||
@ -81,7 +80,10 @@ public class CursorMoveEvent extends CursorEvent {
|
|||||||
return getNewY() - getPreviousY();
|
return getNewY() - getPreviousY();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec2 getChange(Vec2 result) {
|
public Vec2d getChange(Vec2d result) {
|
||||||
|
if (result == null) {
|
||||||
|
result = new Vec2d();
|
||||||
|
}
|
||||||
return result.set(getChangeX(), getChangeY());
|
return result.set(getChangeX(), getChangeY());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,13 +15,35 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ru.windcorp.progressia.client.graphics.input;
|
package ru.windcorp.progressia.client.graphics.input;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of user input.
|
||||||
|
* <p>
|
||||||
|
* User input events are typically generated by graphics backend between frames
|
||||||
|
* and passed to the graphics layers from top to bottom. Layers that use
|
||||||
|
* {@link Component}s will forward this event through the Component hierarchy.
|
||||||
|
* <p>
|
||||||
|
* Events have a {@code consumed} flag. A freshly-generated event will have this
|
||||||
|
* flag set to {@code false}. Event listeners that process the event will
|
||||||
|
* usually choose to raise the flag ("consume the event") to ask future
|
||||||
|
* listeners to ignore this event. This is done to avoid multiple UI interfaces
|
||||||
|
* reacting to single input. By default, listeners will not receive consumed
|
||||||
|
* events; however, some listeners may choose to receive, handle and even
|
||||||
|
* un-consume the event.
|
||||||
|
* <p>
|
||||||
|
* {@code InputEvent} objects may be reused for future input events after their
|
||||||
|
* processing is complete; to obtain a static copy, use {@link #snapshot()}.
|
||||||
|
*/
|
||||||
public abstract class InputEvent {
|
public abstract class InputEvent {
|
||||||
|
|
||||||
private double time;
|
private double time;
|
||||||
|
|
||||||
|
private boolean isConsumed = false;
|
||||||
|
|
||||||
public InputEvent(double time) {
|
public InputEvent(double time) {
|
||||||
this.time = time;
|
this.time = time;
|
||||||
}
|
}
|
||||||
@ -36,4 +58,16 @@ public abstract class InputEvent {
|
|||||||
|
|
||||||
public abstract InputEvent snapshot();
|
public abstract InputEvent snapshot();
|
||||||
|
|
||||||
|
public boolean isConsumed() {
|
||||||
|
return isConsumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConsumed(boolean isConsumed) {
|
||||||
|
this.isConsumed = isConsumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void consume() {
|
||||||
|
setConsumed(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,75 @@
|
|||||||
|
|
||||||
package ru.windcorp.progressia.client.graphics.input;
|
package ru.windcorp.progressia.client.graphics.input;
|
||||||
|
|
||||||
import java.util.function.Predicate;
|
import java.util.Map;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
public class KeyMatcher {
|
public class KeyMatcher {
|
||||||
|
|
||||||
|
private static final Pattern DECLAR_SPLIT_REGEX = Pattern.compile("\\s*\\+\\s*");
|
||||||
|
private static final Map<String, Integer> MOD_TOKENS = ImmutableMap.of(
|
||||||
|
"SHIFT", GLFW.GLFW_MOD_SHIFT,
|
||||||
|
"CONTROL", GLFW.GLFW_MOD_CONTROL,
|
||||||
|
"ALT", GLFW.GLFW_MOD_ALT,
|
||||||
|
"SUPER", GLFW.GLFW_MOD_SUPER
|
||||||
|
);
|
||||||
|
|
||||||
|
public static final KeyMatcher LMB = new KeyMatcher(GLFW.GLFW_MOUSE_BUTTON_LEFT);
|
||||||
|
public static final KeyMatcher RMB = new KeyMatcher(GLFW.GLFW_MOUSE_BUTTON_RIGHT);
|
||||||
|
public static final KeyMatcher MMB = new KeyMatcher(GLFW.GLFW_MOUSE_BUTTON_MIDDLE);
|
||||||
|
|
||||||
private final int key;
|
private final int key;
|
||||||
private final int mods;
|
private final int mods;
|
||||||
|
|
||||||
protected KeyMatcher(int key, int mods) {
|
public KeyMatcher(int key, int mods) {
|
||||||
|
this.key = key;
|
||||||
|
this.mods = mods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyMatcher(int key) {
|
||||||
|
this.key = key;
|
||||||
|
this.mods = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyMatcher(String declar) {
|
||||||
|
String[] tokens = DECLAR_SPLIT_REGEX.split(declar);
|
||||||
|
if (tokens.length == 0) {
|
||||||
|
throw new IllegalArgumentException("No tokens found in \"" + declar + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
int key = -1;
|
||||||
|
int mods = 0;
|
||||||
|
|
||||||
|
for (String token : tokens) {
|
||||||
|
token = token.toUpperCase();
|
||||||
|
|
||||||
|
if (MOD_TOKENS.containsKey(token)) {
|
||||||
|
int mod = MOD_TOKENS.get(token);
|
||||||
|
if ((mods & mod) != 0) {
|
||||||
|
throw new IllegalArgumentException("Duplicate modifier \"" + token + "\" in \"" + declar + "\"");
|
||||||
|
}
|
||||||
|
mods |= mod;
|
||||||
|
} else if (key != -1) {
|
||||||
|
throw new IllegalArgumentException("Too many non-modifier tokens in \"" + declar + "\": maximum one key, first offender: \"" + token + "\"");
|
||||||
|
} else {
|
||||||
|
token = token.replace(' ', '_');
|
||||||
|
|
||||||
|
if (token.startsWith("KEYPAD_")) {
|
||||||
|
token = "KP_" + token.substring("KEYPAD_".length());
|
||||||
|
}
|
||||||
|
|
||||||
|
key = Keys.getCode(token);
|
||||||
|
|
||||||
|
if (key == -1) {
|
||||||
|
throw new IllegalArgumentException("Unknown token \"" + token + "\" in \"" + declar + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.mods = mods;
|
this.mods = mods;
|
||||||
}
|
}
|
||||||
@ -42,6 +101,15 @@ public class KeyMatcher {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean matchesIgnoringAction(KeyEvent event) {
|
||||||
|
if (event.getKey() != getKey())
|
||||||
|
return false;
|
||||||
|
if ((event.getMods() & getMods()) != getMods())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public int getKey() {
|
public int getKey() {
|
||||||
return key;
|
return key;
|
||||||
@ -50,49 +118,25 @@ public class KeyMatcher {
|
|||||||
public int getMods() {
|
public int getMods() {
|
||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static KeyMatcher.Builder of(int key) {
|
public KeyMatcher with(int modifier) {
|
||||||
return new KeyMatcher.Builder(key);
|
return new KeyMatcher(key, mods | modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public KeyMatcher withShift() {
|
||||||
|
return with(GLFW.GLFW_MOD_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
private final int key;
|
public KeyMatcher withCtrl() {
|
||||||
private int mods = 0;
|
return with(GLFW.GLFW_MOD_CONTROL);
|
||||||
|
}
|
||||||
|
|
||||||
public Builder(int key) {
|
public KeyMatcher withAlt() {
|
||||||
this.key = key;
|
return with(GLFW.GLFW_MOD_ALT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder with(int modifier) {
|
|
||||||
this.mods += modifier;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withShift() {
|
|
||||||
return with(GLFW.GLFW_MOD_SHIFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withCtrl() {
|
|
||||||
return with(GLFW.GLFW_MOD_CONTROL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withAlt() {
|
|
||||||
return with(GLFW.GLFW_MOD_ALT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder withSuper() {
|
|
||||||
return with(GLFW.GLFW_MOD_SUPER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyMatcher build() {
|
|
||||||
return new KeyMatcher(key, mods);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Predicate<KeyEvent> matcher() {
|
|
||||||
return build()::matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public KeyMatcher withSuper() {
|
||||||
|
return with(GLFW.GLFW_MOD_SUPER);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ public class Keys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int getCode(String internalName) {
|
public static int getCode(String internalName) {
|
||||||
if (NAMES_TO_CODES.containsKey(internalName)) {
|
if (!NAMES_TO_CODES.containsKey(internalName)) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return NAMES_TO_CODES.get(internalName);
|
return NAMES_TO_CODES.get(internalName);
|
||||||
|
@ -15,73 +15,401 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ru.windcorp.progressia.client.graphics.input.bus;
|
package ru.windcorp.progressia.client.graphics.input.bus;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import ru.windcorp.jputil.ArrayUtil;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.CursorEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.WheelEvent;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event bus optionally related to a {@link Component} that delivers input
|
||||||
|
* events to input listeners. This bus may skip listeners based on circumstance;
|
||||||
|
* behavior can be customized for each listener with {@link Option}s.
|
||||||
|
* <p>
|
||||||
|
* By default, events are filtered by four checks before being delivered to each
|
||||||
|
* listener:
|
||||||
|
* <ol>
|
||||||
|
* <li><em>Consumption check</em>: unless {@link Option#RECEIVE_CONSUMED
|
||||||
|
* RECEIVE_CONSUMED} is set, events that are consumed will not be
|
||||||
|
* delivered.</li>
|
||||||
|
* <li><em>Hover check</em>: for certain event types (for example,
|
||||||
|
* {@link WheelEvent} or {@link KeyEvent} that {@link KeyEvent#isMouse()
|
||||||
|
* isMouse()}), the event will only be delivered if the component is hovered.
|
||||||
|
* This check may be bypassed with option {@link Option#IGNORE_HOVER
|
||||||
|
* IGNORE_HOVER} or made mandatory for all events with
|
||||||
|
* {@link Option#REQUIRE_HOVER REQUIRE_HOVER}. Hover check automatically
|
||||||
|
* succeeds if no component is provided.</li>
|
||||||
|
* <li><em>Focus check</em>: for certain event types (for example,
|
||||||
|
* {@link KeyEvent} that {@code !isMouse()}), the event will only be delivered
|
||||||
|
* if the component has focus. This check may be bypassed with option
|
||||||
|
* {@link Option#IGNORE_FOCUS IGNORE_FOCUS} or made mandatory for all events
|
||||||
|
* with {@link Option#REQUIRE_FOCUS REQUIRE_FOCUS}. Focus check automatically
|
||||||
|
* succeeds if no component is provided.</li>
|
||||||
|
* <li><em>Type check</em>: events of type {@code E} are only delivered to
|
||||||
|
* listeners registered with event type {@code T} if objects of type {@code E}
|
||||||
|
* can be cast to {@code T}.</li>
|
||||||
|
* </ol>
|
||||||
|
* Checks 1-3 are bypassed when option {@link Option#ALWAYS ALWAYS} is
|
||||||
|
* specified.
|
||||||
|
*/
|
||||||
public class InputBus {
|
public class InputBus {
|
||||||
|
|
||||||
private static class WrappedListener {
|
/**
|
||||||
|
* Options that allow customization of checks for listeners.
|
||||||
|
*/
|
||||||
|
public enum Option {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore checks for consumed events, hover and focus; deliver event if
|
||||||
|
* at all possible. This is shorthand for {@link #RECEIVE_CONSUMED},
|
||||||
|
* {@link #IGNORE_HOVER} and {@link #IGNORE_FOCUS}.
|
||||||
|
*/
|
||||||
|
ALWAYS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive events that were previously consumed.
|
||||||
|
*/
|
||||||
|
RECEIVE_CONSUMED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not process events if the listener is registered with a component
|
||||||
|
* and the component is not hovered.
|
||||||
|
*/
|
||||||
|
REQUIRE_HOVER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deliver events even if the event is limited to hovered components by
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
IGNORE_HOVER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not process events if the listener is registered with a component
|
||||||
|
* and the component is not focused.
|
||||||
|
*/
|
||||||
|
REQUIRE_FOCUS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deliver events even if the event is limited to focused components by
|
||||||
|
* default.
|
||||||
|
*/
|
||||||
|
IGNORE_FOCUS,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deliver events according to
|
||||||
|
* {@link KeyMatcher#matchesIgnoringAction(KeyEvent)} rather than
|
||||||
|
* {@link KeyMatcher#matches(KeyEvent)} when a {@link KeyMatcher} is
|
||||||
|
* specified.
|
||||||
|
*/
|
||||||
|
IGNORE_ACTION;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum YesNoDefault {
|
||||||
|
YES, NO, DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A listener with check preferences resolved and type specified.
|
||||||
|
*/
|
||||||
|
private class WrappedListener {
|
||||||
|
|
||||||
private final Class<?> type;
|
private final Class<?> type;
|
||||||
private final boolean handleConsumed;
|
|
||||||
|
private final boolean dropIfConsumed;
|
||||||
|
private final YesNoDefault dropIfNotHovered;
|
||||||
|
private final YesNoDefault dropIfNotFocused;
|
||||||
|
|
||||||
private final InputListener<?> listener;
|
private final InputListener<?> listener;
|
||||||
|
|
||||||
public WrappedListener(
|
public WrappedListener(
|
||||||
Class<?> type,
|
Class<?> type,
|
||||||
boolean handleConsumed,
|
boolean dropIfConsumed,
|
||||||
|
YesNoDefault dropIfNotHovered,
|
||||||
|
YesNoDefault dropIfNotFocused,
|
||||||
InputListener<?> listener
|
InputListener<?> listener
|
||||||
) {
|
) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.handleConsumed = handleConsumed;
|
this.dropIfConsumed = dropIfConsumed;
|
||||||
|
this.dropIfNotHovered = dropIfNotHovered;
|
||||||
|
this.dropIfNotFocused = dropIfNotFocused;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handles(Input input) {
|
private boolean handles(InputEvent input) {
|
||||||
return (!input.isConsumed() || handleConsumed) &&
|
if (dropIfConsumed && input.isConsumed())
|
||||||
type.isInstance(input.getEvent());
|
return false;
|
||||||
|
|
||||||
|
switch (dropIfNotHovered) {
|
||||||
|
case YES:
|
||||||
|
if (!isHovered())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case NO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
if (isHovered())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (input instanceof KeyEvent && ((KeyEvent) input).isMouse())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (input instanceof CursorEvent)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (input instanceof WheelEvent)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dropIfNotFocused) {
|
||||||
|
case YES:
|
||||||
|
if (!isFocused())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case NO:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
if (isFocused())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (input instanceof KeyEvent && !((KeyEvent) input).isMouse())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type.isInstance(input))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes the listener if the event is deemed appropriate by the four
|
||||||
|
* checks.
|
||||||
|
*
|
||||||
|
* @param event the event to deliver
|
||||||
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void handle(Input input) {
|
public void handle(InputEvent event) {
|
||||||
if (handles(input)) {
|
if (handles(event)) {
|
||||||
boolean consumed = ((InputListener<InputEvent>) listener)
|
// A runtime check of types has been performed; this is safe.
|
||||||
.handle(
|
InputListener<InputEvent> castListener = (InputListener<InputEvent>) listener;
|
||||||
(InputEvent) type.cast(input.getEvent())
|
|
||||||
);
|
|
||||||
|
|
||||||
input.setConsumed(consumed);
|
try {
|
||||||
|
castListener.handle(event);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw CrashReports.report(
|
||||||
|
e,
|
||||||
|
"InputListener %s for component %s has failed to receive event %s",
|
||||||
|
listener,
|
||||||
|
owner,
|
||||||
|
event
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The component queried for focus and hover. May be {@code null}.
|
||||||
|
*/
|
||||||
|
private final Component owner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registered listeners.
|
||||||
|
*/
|
||||||
private final Collection<WrappedListener> listeners = new ArrayList<>(4);
|
private final Collection<WrappedListener> listeners = new ArrayList<>(4);
|
||||||
|
|
||||||
public void dispatch(Input input) {
|
/**
|
||||||
listeners.forEach(l -> l.handle(input));
|
* Creates a new input bus that consults the specified {@link Component} to
|
||||||
|
* determine hover and focus.
|
||||||
|
*
|
||||||
|
* @param owner the component to use for hover and focus tests
|
||||||
|
* @see #InputBus()
|
||||||
|
*/
|
||||||
|
public InputBus(Component owner) {
|
||||||
|
this.owner = Objects.requireNonNull(owner, "owner");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new input bus that assumes all hover and focus checks are
|
||||||
|
* successful.
|
||||||
|
*
|
||||||
|
* @see #InputBus(Component)
|
||||||
|
*/
|
||||||
|
public InputBus() {
|
||||||
|
this.owner = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether hover should be assumed for this event bus.
|
||||||
|
*
|
||||||
|
* @return {@code true} iff no component is linked or the linked component
|
||||||
|
* is hovered
|
||||||
|
*/
|
||||||
|
private boolean isHovered() {
|
||||||
|
return owner == null ? true : owner.isHovered();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether focus should be assumed for this event bus.
|
||||||
|
*
|
||||||
|
* @return {@code true} iff no component is linked or the linked component
|
||||||
|
* is focused
|
||||||
|
*/
|
||||||
|
private boolean isFocused() {
|
||||||
|
return owner == null ? true : owner.isFocused();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches (delivers) the provided event to all appropriate listeners.
|
||||||
|
*
|
||||||
|
* @param event the event to process
|
||||||
|
*/
|
||||||
|
public void dispatch(InputEvent event) {
|
||||||
|
Objects.requireNonNull(event, "event");
|
||||||
|
for (WrappedListener listener : listeners) {
|
||||||
|
listener.handle(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a listener on this bus.
|
||||||
|
* <p>
|
||||||
|
* {@code type} specifies the class of events that should be passed to this
|
||||||
|
* listener. Only events of types that extend, implement or equal
|
||||||
|
* {@code type} are processed.
|
||||||
|
* <p>
|
||||||
|
* Zero or more {@link Option}s may be specified to enable or disable the
|
||||||
|
* processing of certain events in certain circumstances. See
|
||||||
|
* {@linkplain InputBus class description} for a detailed breakdown of the
|
||||||
|
* checks performed and the effects of various options. When providing
|
||||||
|
* options to this method, later options override the effects of previous
|
||||||
|
* options.
|
||||||
|
* <p>
|
||||||
|
* Option {@link Option#IGNORE_ACTION IGNORE_ACTION} is ignored silently.
|
||||||
|
*
|
||||||
|
* @param type the event class to deliver
|
||||||
|
* @param listener the listener
|
||||||
|
* @param options the options for this listener
|
||||||
|
*/
|
||||||
public <T extends InputEvent> void register(
|
public <T extends InputEvent> void register(
|
||||||
Class<? extends T> type,
|
Class<? extends T> type,
|
||||||
boolean handlesConsumed,
|
InputListener<T> listener,
|
||||||
InputListener<T> listener
|
Option... options
|
||||||
) {
|
) {
|
||||||
listeners.add(new WrappedListener(type, handlesConsumed, listener));
|
Objects.requireNonNull(type, "type");
|
||||||
|
Objects.requireNonNull(listener, "listener");
|
||||||
|
|
||||||
|
boolean dropIfConsumed = true;
|
||||||
|
YesNoDefault dropIfNotHovered = YesNoDefault.DEFAULT;
|
||||||
|
YesNoDefault dropIfNotFocused = YesNoDefault.DEFAULT;
|
||||||
|
|
||||||
|
if (options != null) {
|
||||||
|
for (Option option : options) {
|
||||||
|
switch (option) {
|
||||||
|
case ALWAYS:
|
||||||
|
dropIfConsumed = false;
|
||||||
|
dropIfNotHovered = YesNoDefault.NO;
|
||||||
|
dropIfNotFocused = YesNoDefault.NO;
|
||||||
|
break;
|
||||||
|
case RECEIVE_CONSUMED:
|
||||||
|
dropIfConsumed = false;
|
||||||
|
break;
|
||||||
|
case REQUIRE_HOVER:
|
||||||
|
dropIfNotHovered = YesNoDefault.YES;
|
||||||
|
break;
|
||||||
|
case IGNORE_HOVER:
|
||||||
|
dropIfNotFocused = YesNoDefault.NO;
|
||||||
|
break;
|
||||||
|
case REQUIRE_FOCUS:
|
||||||
|
dropIfNotHovered = YesNoDefault.YES;
|
||||||
|
break;
|
||||||
|
case IGNORE_FOCUS:
|
||||||
|
dropIfNotFocused = YesNoDefault.NO;
|
||||||
|
break;
|
||||||
|
case IGNORE_ACTION:
|
||||||
|
// Ignore
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unexpected option " + option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners.add(new WrappedListener(type, dropIfConsumed, dropIfNotHovered, dropIfNotFocused, listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends InputEvent> void register(
|
/**
|
||||||
Class<? extends T> type,
|
* Registers a {@link KeyEvent} listener on this bus. An event has to match
|
||||||
InputListener<T> listener
|
* the provided {@link KeyMatcher} to be delivered to the listener.
|
||||||
) {
|
* <p>
|
||||||
register(type, false, listener);
|
* Zero or more {@link Option}s may be specified to enable or disable the
|
||||||
|
* processing of certain events in certain circumstances. See
|
||||||
|
* {@linkplain InputBus class description} for a detailed breakdown of the
|
||||||
|
* checks performed and the effects of various options. When providing
|
||||||
|
* options to this method, later options override the effects of previous
|
||||||
|
* options.
|
||||||
|
* <p>
|
||||||
|
* Option {@link Option#IGNORE_ACTION IGNORE_ACTION} requests that events
|
||||||
|
* are delivered according to
|
||||||
|
* {@link KeyMatcher#matchesIgnoringAction(KeyEvent)} rather than
|
||||||
|
* {@link KeyMatcher#matches(KeyEvent)}.
|
||||||
|
* specified.
|
||||||
|
*
|
||||||
|
* @param matcher an event filter
|
||||||
|
* @param listener the listener
|
||||||
|
* @param options the options for this listener
|
||||||
|
*/
|
||||||
|
public void register(KeyMatcher matcher, InputListener<? super KeyEvent> listener, Option... options) {
|
||||||
|
Objects.requireNonNull(matcher, "matcher");
|
||||||
|
Objects.requireNonNull(listener, "listener");
|
||||||
|
|
||||||
|
InputListener<KeyEvent> filteringListener;
|
||||||
|
|
||||||
|
if (ArrayUtil.firstIndexOf(options, Option.IGNORE_ACTION) != -1) {
|
||||||
|
filteringListener = e -> {
|
||||||
|
if (matcher.matchesIgnoringAction(e)) {
|
||||||
|
listener.handle(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
filteringListener = e -> {
|
||||||
|
if (matcher.matches(e)) {
|
||||||
|
listener.handle(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
register(KeyEvent.class, filteringListener, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all occurrences of the provided listener from this bus.
|
||||||
|
*
|
||||||
|
* @param listener the listener to unregister
|
||||||
|
*/
|
||||||
public void unregister(InputListener<?> listener) {
|
public void unregister(InputListener<?> listener) {
|
||||||
|
if (listener == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
listeners.removeIf(l -> l.listener == listener);
|
listeners.removeIf(l -> l.listener == listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,6 @@ import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
|||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface InputListener<T extends InputEvent> {
|
public interface InputListener<T extends InputEvent> {
|
||||||
|
|
||||||
boolean handle(T event);
|
void handle(T event);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,14 @@ import glm.vec._3.Vec3;
|
|||||||
import glm.vec._4.Vec4;
|
import glm.vec._4.Vec4;
|
||||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder;
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder;
|
||||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram.WRPVertexBuilder;
|
||||||
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
import ru.windcorp.progressia.common.world.rels.AbsFace;
|
||||||
|
|
||||||
public class ShapeParts {
|
public class ShapeParts {
|
||||||
|
|
||||||
private ShapeParts() {
|
private ShapeParts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShapePart createRectangle(
|
public static ShapePart createRectangle(
|
||||||
ShapeRenderProgram program,
|
ShapeRenderProgram program,
|
||||||
Texture texture,
|
Texture texture,
|
||||||
@ -41,25 +42,65 @@ public class ShapeParts {
|
|||||||
Vec3 height,
|
Vec3 height,
|
||||||
boolean flip
|
boolean flip
|
||||||
) {
|
) {
|
||||||
VertexBuilder builder = program.getVertexBuilder();
|
return createRectangle(program, texture, colorMultiplier, origin, width, height, flip, null);
|
||||||
|
}
|
||||||
|
|
||||||
builder.addVertex(
|
public static ShapePart createRectangle(
|
||||||
origin,
|
ShapeRenderProgram program,
|
||||||
colorMultiplier,
|
Texture texture,
|
||||||
new Vec2(0, 0)
|
Vec4 colorMultiplier,
|
||||||
).addVertex(
|
Vec3 origin,
|
||||||
origin.add_(height),
|
Vec3 width,
|
||||||
colorMultiplier,
|
Vec3 height,
|
||||||
new Vec2(0, 1)
|
boolean flip,
|
||||||
).addVertex(
|
Vec3 forcedNormals
|
||||||
origin.add_(width),
|
) {
|
||||||
colorMultiplier,
|
VertexBuilder builder = program.getVertexBuilder();
|
||||||
new Vec2(1, 0)
|
|
||||||
).addVertex(
|
if (forcedNormals != null && builder instanceof WRPVertexBuilder) {
|
||||||
origin.add_(width).add(height),
|
((WRPVertexBuilder) builder).addVertex(
|
||||||
colorMultiplier,
|
origin,
|
||||||
new Vec2(1, 1)
|
colorMultiplier,
|
||||||
);
|
new Vec2(0, 0),
|
||||||
|
forcedNormals
|
||||||
|
);
|
||||||
|
((WRPVertexBuilder) builder).addVertex(
|
||||||
|
origin.add_(height),
|
||||||
|
colorMultiplier,
|
||||||
|
new Vec2(0, 1),
|
||||||
|
forcedNormals
|
||||||
|
);
|
||||||
|
((WRPVertexBuilder) builder).addVertex(
|
||||||
|
origin.add_(width),
|
||||||
|
colorMultiplier,
|
||||||
|
new Vec2(1, 0),
|
||||||
|
forcedNormals
|
||||||
|
);
|
||||||
|
((WRPVertexBuilder) builder).addVertex(
|
||||||
|
origin.add_(width).add(height),
|
||||||
|
colorMultiplier,
|
||||||
|
new Vec2(1, 1),
|
||||||
|
forcedNormals
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
builder.addVertex(
|
||||||
|
origin,
|
||||||
|
colorMultiplier,
|
||||||
|
new Vec2(0, 0)
|
||||||
|
).addVertex(
|
||||||
|
origin.add_(height),
|
||||||
|
colorMultiplier,
|
||||||
|
new Vec2(0, 1)
|
||||||
|
).addVertex(
|
||||||
|
origin.add_(width),
|
||||||
|
colorMultiplier,
|
||||||
|
new Vec2(1, 0)
|
||||||
|
).addVertex(
|
||||||
|
origin.add_(width).add(height),
|
||||||
|
colorMultiplier,
|
||||||
|
new Vec2(1, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ShortBuffer buffer = flip ? ShortBuffer.wrap(
|
ShortBuffer buffer = flip ? ShortBuffer.wrap(
|
||||||
new short[] {
|
new short[] {
|
||||||
@ -112,6 +153,6 @@ public class ShapeParts {
|
|||||||
height,
|
height,
|
||||||
inner
|
inner
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.model;
|
||||||
|
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import glm.mat._3.Mat3;
|
||||||
|
import glm.mat._4.Mat4;
|
||||||
|
import glm.vec._2.Vec2;
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import glm.vec._4.Vec4;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram.WRPVertexBuilder;
|
||||||
|
import ru.windcorp.progressia.common.util.StashingStack;
|
||||||
|
import ru.windcorp.progressia.common.util.VectorUtil;
|
||||||
|
|
||||||
|
public class ShapePrototype {
|
||||||
|
|
||||||
|
private final ShapeRenderProgram program;
|
||||||
|
|
||||||
|
private Texture texture;
|
||||||
|
|
||||||
|
private final Vec3[] positions;
|
||||||
|
private final Vec4[] colorMultipliers;
|
||||||
|
private final Vec2[] textureCoords;
|
||||||
|
private final Vec3[] forcedNormals;
|
||||||
|
|
||||||
|
private ShortBuffer indices;
|
||||||
|
private ShortBuffer flippedIndices = null;
|
||||||
|
|
||||||
|
protected static final int TRANSFORM_STACK_SIZE = 64;
|
||||||
|
private final StashingStack<Mat4> transformStack = new StashingStack<>(
|
||||||
|
TRANSFORM_STACK_SIZE,
|
||||||
|
Mat4::new
|
||||||
|
);
|
||||||
|
|
||||||
|
public ShapePrototype(
|
||||||
|
ShapeRenderProgram program,
|
||||||
|
Texture texture,
|
||||||
|
Vec3[] positions,
|
||||||
|
Vec4[] colorMultipliers,
|
||||||
|
Vec2[] textureCoords,
|
||||||
|
Vec3[] forcedNormals,
|
||||||
|
ShortBuffer indices
|
||||||
|
) {
|
||||||
|
this.program = Objects.requireNonNull(program, "program");
|
||||||
|
this.texture = texture;
|
||||||
|
this.indices = Objects.requireNonNull(indices, "indices");
|
||||||
|
|
||||||
|
Objects.requireNonNull(positions, "positions");
|
||||||
|
Objects.requireNonNull(colorMultipliers, "colorMultipliers");
|
||||||
|
Objects.requireNonNull(textureCoords, "textureCoords");
|
||||||
|
|
||||||
|
if (forcedNormals != null && !(program instanceof WorldRenderProgram)) {
|
||||||
|
throw new IllegalArgumentException("Cannot force normals on non-WorldRenderPrograms cuz javahorse stupiddd");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forcedNormals == null) {
|
||||||
|
forcedNormals = new Vec3[positions.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.positions = positions;
|
||||||
|
this.colorMultipliers = colorMultipliers;
|
||||||
|
this.textureCoords = textureCoords;
|
||||||
|
this.forcedNormals = forcedNormals;
|
||||||
|
|
||||||
|
if (positions.length != colorMultipliers.length) {
|
||||||
|
throw new IllegalArgumentException("positions.length (" + positions.length + ") != colorMultipliers.length (" + colorMultipliers + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (positions.length != textureCoords.length) {
|
||||||
|
throw new IllegalArgumentException("positions.length (" + positions.length + ") != textureCoords.length (" + textureCoords + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (positions.length != forcedNormals.length) {
|
||||||
|
throw new IllegalArgumentException("positions.length (" + positions.length + ") != forcedNormals.length (" + forcedNormals + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
transformStack.push().identity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePart build() {
|
||||||
|
VertexBuilder builder = program.getVertexBuilder();
|
||||||
|
|
||||||
|
Vec3 transformedPosition = new Vec3();
|
||||||
|
|
||||||
|
for (int i = 0; i < positions.length; ++i) {
|
||||||
|
|
||||||
|
transformedPosition.set(positions[i]);
|
||||||
|
if (transformStack.getSize() > 1) {
|
||||||
|
VectorUtil.applyMat4(transformedPosition, transformStack.getHead());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forcedNormals[i] != null && builder instanceof WRPVertexBuilder) {
|
||||||
|
((WRPVertexBuilder) builder).addVertex(
|
||||||
|
transformedPosition, colorMultipliers[i], textureCoords[i], forcedNormals[i]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
builder.addVertex(transformedPosition, colorMultipliers[i], textureCoords[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ShapePart(texture, builder.assemble(), indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype apply(Mat4 transform) {
|
||||||
|
for (Vec3 vector : positions) {
|
||||||
|
VectorUtil.applyMat4(vector, transform);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype apply(Mat3 transform) {
|
||||||
|
for (Vec3 vector : positions) {
|
||||||
|
transform.mul(vector);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Mat4 push() {
|
||||||
|
Mat4 previous = transformStack.getHead();
|
||||||
|
return transformStack.push().set(previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype pop() {
|
||||||
|
transformStack.pop();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype setTexture(Texture texture) {
|
||||||
|
this.texture = texture;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype deleteTexture() {
|
||||||
|
this.texture = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype resetColorMultiplier() {
|
||||||
|
for (Vec4 color : colorMultipliers) {
|
||||||
|
color.set(Colors.WHITE);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype addColorMultiplier(Vec4 color) {
|
||||||
|
for (Vec4 c : colorMultipliers) {
|
||||||
|
c.mul(color);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype flip() {
|
||||||
|
ShortBuffer tmp = indices;
|
||||||
|
indices = flippedIndices;
|
||||||
|
flippedIndices = tmp;
|
||||||
|
|
||||||
|
if (indices == null) {
|
||||||
|
int length = flippedIndices.limit();
|
||||||
|
indices = ShortBuffer.allocate(length);
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
indices.put(i, flippedIndices.get(length - i - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShapePrototype makeDoubleSided() {
|
||||||
|
int length = indices.limit();
|
||||||
|
ShortBuffer newIndices = ShortBuffer.allocate(length * 2);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
newIndices.put(i, indices.get(i));
|
||||||
|
}
|
||||||
|
for (int i = 0; i < length; ++i) {
|
||||||
|
newIndices.put(i + length, indices.get(length - i - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
indices = flippedIndices = newIndices;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShapePrototype unitSquare(Texture texture, Vec4 color, ShapeRenderProgram program) {
|
||||||
|
return new ShapePrototype(
|
||||||
|
program,
|
||||||
|
texture,
|
||||||
|
new Vec3[] {
|
||||||
|
new Vec3(0, 0, 0),
|
||||||
|
new Vec3(0, 1, 0),
|
||||||
|
new Vec3(1, 0, 0),
|
||||||
|
new Vec3(1, 1, 0)
|
||||||
|
},
|
||||||
|
new Vec4[] {
|
||||||
|
new Vec4(color),
|
||||||
|
new Vec4(color),
|
||||||
|
new Vec4(color),
|
||||||
|
new Vec4(color)
|
||||||
|
},
|
||||||
|
new Vec2[] {
|
||||||
|
new Vec2(0, 0),
|
||||||
|
new Vec2(0, 1),
|
||||||
|
new Vec2(1, 0),
|
||||||
|
new Vec2(1, 1)
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
ShortBuffer.wrap(new short[] {3, 1, 0, 2, 3, 0})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShapePrototype unitSquare(Texture texture, Vec4 color) {
|
||||||
|
return unitSquare(texture, color, WorldRenderProgram.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShapePrototype unitSquare(Texture texture) {
|
||||||
|
return unitSquare(texture, Colors.WHITE, WorldRenderProgram.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShapePrototype unitSquare(Vec4 color) {
|
||||||
|
return unitSquare(null, color, WorldRenderProgram.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ShapePrototype unitSquare() {
|
||||||
|
return unitSquare(null, Colors.WHITE, WorldRenderProgram.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -125,6 +125,36 @@ public class Shapes {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Shape createParallelogram(
|
||||||
|
// Try saying that 10 times fast
|
||||||
|
ShapeRenderProgram program,
|
||||||
|
|
||||||
|
Vec3 origin,
|
||||||
|
|
||||||
|
Vec3 width,
|
||||||
|
Vec3 height,
|
||||||
|
|
||||||
|
Vec4 colorMultiplier,
|
||||||
|
|
||||||
|
Texture texture
|
||||||
|
) {
|
||||||
|
Shape result = new Shape(
|
||||||
|
Usage.STATIC,
|
||||||
|
program,
|
||||||
|
ShapeParts.createRectangle(
|
||||||
|
program,
|
||||||
|
texture,
|
||||||
|
colorMultiplier,
|
||||||
|
origin,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static class PppBuilder {
|
public static class PppBuilder {
|
||||||
|
|
||||||
@ -315,4 +345,108 @@ public class Shapes {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PgmBuilder {
|
||||||
|
|
||||||
|
private final ShapeRenderProgram program;
|
||||||
|
|
||||||
|
private final Vec3 origin = new Vec3(0, 0, 0);
|
||||||
|
|
||||||
|
private final Vec3 width = new Vec3(1, 0, 0);
|
||||||
|
private final Vec3 height = new Vec3(0, 1, 0);
|
||||||
|
|
||||||
|
private final Vec4 colorMultiplier = new Vec4(1, 1, 1, 1);
|
||||||
|
|
||||||
|
private final Texture texture;
|
||||||
|
|
||||||
|
public PgmBuilder(ShapeRenderProgram program, Texture texture) {
|
||||||
|
this.program = program;
|
||||||
|
this.texture = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setOrigin(Vec3 origin) {
|
||||||
|
this.origin.set(origin);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setOrigin(float x, float y, float z) {
|
||||||
|
this.origin.set(x, y, z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setColorMultiplier(Vec4 colorMultiplier) {
|
||||||
|
this.colorMultiplier.set(colorMultiplier);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setColorMultiplier(float r, float g, float b) {
|
||||||
|
this.colorMultiplier.set(r, g, b, 1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setColorMultiplier(float r, float g, float b, float a) {
|
||||||
|
this.colorMultiplier.set(r, g, b, a);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setWidth(Vec3 vector) {
|
||||||
|
this.width.set(vector);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setWidth(float x, float y, float z) {
|
||||||
|
this.width.set(x, y, z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setWidth(float x) {
|
||||||
|
this.width.set(x, 0, 0);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setHeight(Vec3 vector) {
|
||||||
|
this.height.set(vector);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setHeight(float x, float y, float z) {
|
||||||
|
this.height.set(x, y, z);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setHeight(float y) {
|
||||||
|
this.height.set(0, y, 0);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setSize(float x, float y) {
|
||||||
|
return this.setWidth(x).setHeight(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder setSize(float size) {
|
||||||
|
return this.setSize(size, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PgmBuilder centerAt(float x, float y, float z) {
|
||||||
|
origin.set(x, y, z);
|
||||||
|
|
||||||
|
origin.mul(2);
|
||||||
|
origin.sub(width);
|
||||||
|
origin.div(2);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Shape create() {
|
||||||
|
return createParallelogram(
|
||||||
|
program,
|
||||||
|
origin,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
colorMultiplier,
|
||||||
|
texture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import javax.imageio.ImageIO;
|
|||||||
|
|
||||||
import ru.windcorp.progressia.common.resource.Resource;
|
import ru.windcorp.progressia.common.resource.Resource;
|
||||||
import ru.windcorp.progressia.common.util.BinUtil;
|
import ru.windcorp.progressia.common.util.BinUtil;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
|
|
||||||
public class TextureLoader {
|
public class TextureLoader {
|
||||||
|
|
||||||
@ -99,7 +100,12 @@ public class TextureLoader {
|
|||||||
TextureSettings settings
|
TextureSettings settings
|
||||||
)
|
)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return loadPixels(resource.getInputStream(), settings);
|
|
||||||
|
InputStream stream = resource.getInputStream();
|
||||||
|
if (stream == null) {
|
||||||
|
throw CrashReports.report(null, "Texture \"%s\" not found", resource.getName());
|
||||||
|
}
|
||||||
|
return loadPixels(stream, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextureLoader() {
|
private TextureLoader() {
|
||||||
|
@ -91,5 +91,14 @@ public class EntityAnchor implements Anchor {
|
|||||||
public Collection<Mode> getCameraModes() {
|
public Collection<Mode> getCameraModes() {
|
||||||
return modes;
|
return modes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EntityData getEntity() {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Anchor for entity " + entity;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ import ru.windcorp.progressia.client.comms.controls.InputBasedControls;
|
|||||||
import ru.windcorp.progressia.client.graphics.Layer;
|
import ru.windcorp.progressia.client.graphics.Layer;
|
||||||
import ru.windcorp.progressia.client.graphics.backend.FaceCulling;
|
import ru.windcorp.progressia.client.graphics.backend.FaceCulling;
|
||||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
import ru.windcorp.progressia.client.graphics.input.bus.Input;
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram;
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram;
|
||||||
import ru.windcorp.progressia.client.graphics.model.Shapes.PppBuilder;
|
import ru.windcorp.progressia.client.graphics.model.Shapes.PppBuilder;
|
||||||
@ -45,7 +45,7 @@ import ru.windcorp.progressia.common.util.Vectors;
|
|||||||
import ru.windcorp.progressia.common.world.GravityModel;
|
import ru.windcorp.progressia.common.world.GravityModel;
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
import ru.windcorp.progressia.test.CollisionModelRenderer;
|
import ru.windcorp.progressia.test.CollisionModelRenderer;
|
||||||
import ru.windcorp.progressia.test.TestPlayerControls;
|
import ru.windcorp.progressia.test.controls.TestPlayerControls;
|
||||||
|
|
||||||
public class LayerWorld extends Layer {
|
public class LayerWorld extends Layer {
|
||||||
|
|
||||||
@ -214,6 +214,9 @@ public class LayerWorld extends Layer {
|
|||||||
if (ClientState.getInstance().getLocalPlayer().getEntity() == entity && tmp_testControls.isFlying()) {
|
if (ClientState.getInstance().getLocalPlayer().getEntity() == entity && tmp_testControls.isFlying()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (entity.getId().equals("Test:NoclipCamera")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Vec3 gravitationalAcceleration = Vectors.grab3();
|
Vec3 gravitationalAcceleration = Vectors.grab3();
|
||||||
gm.getGravity(entity.getPosition(), gravitationalAcceleration);
|
gm.getGravity(entity.getPosition(), gravitationalAcceleration);
|
||||||
@ -225,14 +228,9 @@ public class LayerWorld extends Layer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleInput(Input input) {
|
public void handleInput(InputEvent event) {
|
||||||
if (input.isConsumed())
|
if (!event.isConsumed()) {
|
||||||
return;
|
inputBasedControls.handleInput(event);
|
||||||
|
|
||||||
tmp_testControls.handleInput(input);
|
|
||||||
|
|
||||||
if (!input.isConsumed()) {
|
|
||||||
inputBasedControls.handleInput(input);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,20 +15,25 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ru.windcorp.progressia.client.graphics.world;
|
package ru.windcorp.progressia.client.graphics.world;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.Client;
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.client.events.ClientEvent;
|
||||||
|
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
|
||||||
import ru.windcorp.progressia.client.world.WorldRender;
|
import ru.windcorp.progressia.client.world.WorldRender;
|
||||||
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
public class LocalPlayer {
|
public class LocalPlayer {
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
|
|
||||||
private long entityId = EntityData.NULL_ENTITY_ID;
|
private long entityId = EntityData.NULL_ENTITY_ID;
|
||||||
private EntityData lastKnownEntity = null;
|
private EntityDataPlayer lastKnownEntity = null;
|
||||||
|
|
||||||
private final Selection selection = new Selection();
|
private final Selection selection = new Selection();
|
||||||
|
|
||||||
@ -59,19 +64,32 @@ public class LocalPlayer {
|
|||||||
return getEntity() != null;
|
return getEntity() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityData getEntity() {
|
public EntityDataPlayer getEntity() {
|
||||||
if (!hasEntityId()) {
|
if (!hasEntityId()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityData entity = getClient().getWorld().getData().getEntity(getEntityId());
|
EntityData entity = getClient().getWorld().getData().getEntity(getEntityId());
|
||||||
|
EntityDataPlayer playerEntity;
|
||||||
|
|
||||||
if (entity != lastKnownEntity) {
|
if (entity == null || entity instanceof EntityDataPlayer) {
|
||||||
getClient().onLocalPlayerEntityChanged(entity, lastKnownEntity);
|
playerEntity = (EntityDataPlayer) entity;
|
||||||
this.lastKnownEntity = entity;
|
} else {
|
||||||
|
LogManager.getLogger().warn(
|
||||||
|
"Entity ID of local player is {}, but the entity is not an EntityDataPlayer: {}",
|
||||||
|
EntityData.formatEntityId(getEntityId()),
|
||||||
|
entity
|
||||||
|
);
|
||||||
|
playerEntity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entity;
|
if (playerEntity != lastKnownEntity) {
|
||||||
|
ClientEvent event = new NewLocalEntityEvent.Immutable(getClient(), playerEntity, lastKnownEntity);
|
||||||
|
this.lastKnownEntity = playerEntity;
|
||||||
|
getClient().postEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Selection getSelection() {
|
public Selection getSelection() {
|
||||||
|
@ -199,6 +199,10 @@ public class WorldRenderProgram extends ShapeRenderProgram {
|
|||||||
int offset = vertices.position() + index * getBytesPerVertex() + (3 * Float.BYTES +
|
int offset = vertices.position() + index * getBytesPerVertex() + (3 * Float.BYTES +
|
||||||
4 * Float.BYTES +
|
4 * Float.BYTES +
|
||||||
2 * Float.BYTES);
|
2 * Float.BYTES);
|
||||||
|
|
||||||
|
if (!Float.isNaN(vertices.getFloat(offset + 0 * Float.BYTES))) {
|
||||||
|
return; // normals are forced
|
||||||
|
}
|
||||||
|
|
||||||
vertices.putFloat(offset + 0 * Float.BYTES, normal.x);
|
vertices.putFloat(offset + 0 * Float.BYTES, normal.x);
|
||||||
vertices.putFloat(offset + 1 * Float.BYTES, normal.y);
|
vertices.putFloat(offset + 1 * Float.BYTES, normal.y);
|
||||||
@ -212,7 +216,7 @@ public class WorldRenderProgram extends ShapeRenderProgram {
|
|||||||
return new WRPVertexBuilder();
|
return new WRPVertexBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class WRPVertexBuilder implements VertexBuilder {
|
public static class WRPVertexBuilder implements VertexBuilder {
|
||||||
// TODO Throw VertexBuilders out the window and rewrite completely.
|
// TODO Throw VertexBuilders out the window and rewrite completely.
|
||||||
// I want to _extend_ VBs, not re-implement them for children of SRP
|
// I want to _extend_ VBs, not re-implement them for children of SRP
|
||||||
|
|
||||||
@ -220,11 +224,17 @@ public class WorldRenderProgram extends ShapeRenderProgram {
|
|||||||
final Vec3 position;
|
final Vec3 position;
|
||||||
final Vec4 colorMultiplier;
|
final Vec4 colorMultiplier;
|
||||||
final Vec2 textureCoords;
|
final Vec2 textureCoords;
|
||||||
|
final Vec3 normals;
|
||||||
|
|
||||||
Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) {
|
Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) {
|
||||||
|
this(position, colorMultiplier, textureCoords, new Vec3(Float.NaN, Float.NaN, Float.NaN));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords, Vec3 normals) {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.colorMultiplier = colorMultiplier;
|
this.colorMultiplier = colorMultiplier;
|
||||||
this.textureCoords = textureCoords;
|
this.textureCoords = textureCoords;
|
||||||
|
this.normals = normals;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +301,24 @@ public class WorldRenderProgram extends ShapeRenderProgram {
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VertexBuilder addVertex(
|
||||||
|
Vec3 position,
|
||||||
|
Vec4 colorMultiplier,
|
||||||
|
Vec2 textureCoords,
|
||||||
|
Vec3 normals
|
||||||
|
) {
|
||||||
|
vertices.add(
|
||||||
|
new Vertex(
|
||||||
|
new Vec3(position),
|
||||||
|
new Vec4(colorMultiplier),
|
||||||
|
new Vec2(textureCoords),
|
||||||
|
new Vec3(normals)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer assemble() {
|
public ByteBuffer assemble() {
|
||||||
@ -309,9 +337,9 @@ public class WorldRenderProgram extends ShapeRenderProgram {
|
|||||||
.putFloat(v.colorMultiplier.w)
|
.putFloat(v.colorMultiplier.w)
|
||||||
.putFloat(v.textureCoords.x)
|
.putFloat(v.textureCoords.x)
|
||||||
.putFloat(v.textureCoords.y)
|
.putFloat(v.textureCoords.y)
|
||||||
.putFloat(Float.NaN)
|
.putFloat(v.normals.x)
|
||||||
.putFloat(Float.NaN)
|
.putFloat(v.normals.y)
|
||||||
.putFloat(Float.NaN);
|
.putFloat(v.normals.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.flip();
|
result.flip();
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import glm.vec._4.Vec4;
|
||||||
|
import ru.windcorp.jputil.functions.FloatSupplier;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.Usage;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Shape;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeParts;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||||
|
|
||||||
|
public class Bar extends Component {
|
||||||
|
|
||||||
|
private static final int THICKNESS = 5;
|
||||||
|
|
||||||
|
private final boolean isVertical;
|
||||||
|
|
||||||
|
private final FloatSupplier value;
|
||||||
|
private final FloatSupplier maxValue;
|
||||||
|
|
||||||
|
private final Vec4 color;
|
||||||
|
private final Vec4 backgroundColor;
|
||||||
|
|
||||||
|
private static Renderable unitSquare = null;
|
||||||
|
|
||||||
|
public Bar(String name, boolean isVertical, Vec4 color, FloatSupplier value, FloatSupplier maxValue) {
|
||||||
|
super(name);
|
||||||
|
this.isVertical = isVertical;
|
||||||
|
this.value = value;
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
|
||||||
|
this.color = color;
|
||||||
|
this.backgroundColor = Colors.mix(color, Colors.WHITE, 0.75f, null);
|
||||||
|
|
||||||
|
if (unitSquare == null) {
|
||||||
|
unitSquare = new Shape(
|
||||||
|
Usage.STATIC,
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
ShapeParts.createRectangle(
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
null,
|
||||||
|
Colors.WHITE,
|
||||||
|
new Vec3(0, 0, 0),
|
||||||
|
new Vec3(1, 0, 0),
|
||||||
|
new Vec3(0, 1, 0),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPreferredSize(THICKNESS, THICKNESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleSelf(RenderTarget target) {
|
||||||
|
target.addCustomRenderer(this::renderSelf);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderSelf(ShapeRenderHelper renderer) {
|
||||||
|
renderer.pushTransform()
|
||||||
|
.translate(getX(), getY(), 0)
|
||||||
|
.scale(getWidth(), getHeight(), 1);
|
||||||
|
|
||||||
|
float length = value.getAsFloat() / maxValue.getAsFloat();
|
||||||
|
if (length < 0) {
|
||||||
|
length = 0;
|
||||||
|
} else if (length > 1) {
|
||||||
|
length = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO why is the order reverse????
|
||||||
|
renderRectangle(renderer, color, length);
|
||||||
|
renderRectangle(renderer, backgroundColor, 1);
|
||||||
|
|
||||||
|
renderer.popTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderRectangle(ShapeRenderHelper renderer, Vec4 color, float length) {
|
||||||
|
renderer.pushColorMultiplier().mul(color);
|
||||||
|
if (length != 1) {
|
||||||
|
renderer.pushTransform().scale(isVertical ? 1 : length, isVertical ? length : 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
unitSquare.render(renderer);
|
||||||
|
|
||||||
|
if (length != 1) {
|
||||||
|
renderer.popTransform();
|
||||||
|
}
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
import ru.windcorp.progressia.client.graphics.ExponentAnimation;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||||
|
import ru.windcorp.progressia.client.world.entity.SpeciesRender;
|
||||||
|
import ru.windcorp.progressia.client.world.entity.SpeciesRenderRegistry;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerHand;
|
||||||
|
|
||||||
|
public class CursorHUD extends Component {
|
||||||
|
|
||||||
|
private class CursorBoundSlot {
|
||||||
|
|
||||||
|
private final SlotComponent component;
|
||||||
|
private final Renderable renderable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 is not selected, 1 is selected
|
||||||
|
*/
|
||||||
|
private final ExponentAnimation selection = new ExponentAnimation(10, 0);
|
||||||
|
private final double angle;
|
||||||
|
|
||||||
|
public CursorBoundSlot(SlotComponent component, double angle) {
|
||||||
|
this.component = component;
|
||||||
|
this.angle = angle;
|
||||||
|
|
||||||
|
Vec2i size = component.getPreferredSize();
|
||||||
|
component.setBounds(-size.x / 2, -size.y / 2, size);
|
||||||
|
|
||||||
|
this.renderable = component.assembleToRenderable();
|
||||||
|
|
||||||
|
if (player.getHandCount() == 1) {
|
||||||
|
// Disable opening animation hint
|
||||||
|
selection.setValue(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render(ShapeRenderHelper renderer) {
|
||||||
|
|
||||||
|
float target = player.getSelectedHand() == component.getSlot().getContainer() ? 1 : 0;
|
||||||
|
float sel = selection.updateForFrame(target);
|
||||||
|
|
||||||
|
float distance = CursorHUD.this.distance * (1 - sel);
|
||||||
|
float x = (float) Math.cos(angle) * distance;
|
||||||
|
float y = (float) Math.sin(angle) * distance;
|
||||||
|
float scale = 0.5f + 0.5f * sel;
|
||||||
|
|
||||||
|
renderer.pushTransform().translate(x, y, 0).scale(scale);
|
||||||
|
|
||||||
|
boolean popColor = false;
|
||||||
|
if (sel > 0.5f && component.getSlot().isEmpty()) {
|
||||||
|
renderer.pushColorMultiplier().mul(1, 1, 1, 1 - 2 * (sel - 0.5f));
|
||||||
|
popColor = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderable.render(renderer);
|
||||||
|
|
||||||
|
if (popColor) {
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.popTransform();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final EntityDataPlayer player;
|
||||||
|
|
||||||
|
private final float distance = 50;
|
||||||
|
private final double startAngle = Math.PI / 4;
|
||||||
|
private final double endAngle = -3 * Math.PI / 4;
|
||||||
|
|
||||||
|
private final CursorBoundSlot[] slots;
|
||||||
|
|
||||||
|
public CursorHUD(String name, EntityDataPlayer player) {
|
||||||
|
super(name);
|
||||||
|
this.player = player;
|
||||||
|
|
||||||
|
this.slots = new CursorBoundSlot[player.getHandCount()];
|
||||||
|
|
||||||
|
// This produces NaN when there is only one hand, but then it is unused
|
||||||
|
double angleStep = (endAngle - startAngle) / (slots.length - 1);
|
||||||
|
|
||||||
|
double angle = startAngle;
|
||||||
|
for (int i = 0; i < slots.length; ++i) {
|
||||||
|
|
||||||
|
SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(player);
|
||||||
|
|
||||||
|
ItemContainerHand container = player.getHand(i);
|
||||||
|
Hand hand = container.getHand();
|
||||||
|
|
||||||
|
SlotComponent component = new SlotComponent(name + ".Hand" + hand.getName(), container, 0)
|
||||||
|
.setBackground(speciesRender.getHandBackground(hand));
|
||||||
|
|
||||||
|
addChild(component);
|
||||||
|
|
||||||
|
slots[i] = new CursorBoundSlot(component, angle);
|
||||||
|
|
||||||
|
angle += angleStep;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayout(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleChildren(RenderTarget target) {
|
||||||
|
|
||||||
|
target.addCustomRenderer(renderer -> {
|
||||||
|
|
||||||
|
renderer.pushTransform().translate(
|
||||||
|
(float) InputTracker.getCursorX(),
|
||||||
|
(float) InputTracker.getCursorY(),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
for (CursorBoundSlot slot : slots) {
|
||||||
|
slot.render(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.popTransform();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryRender;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryRenderRegistry;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryClosingEvent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryOpenedEvent;
|
||||||
|
|
||||||
|
public class HUDManager implements HUDWorkspace {
|
||||||
|
|
||||||
|
private final Client client;
|
||||||
|
private final LayerHUD layer;
|
||||||
|
|
||||||
|
public HUDManager(Client client) {
|
||||||
|
this.client = client;
|
||||||
|
this.layer = new LayerHUD(this);
|
||||||
|
client.subscribe(new Object() {
|
||||||
|
@Subscribe
|
||||||
|
public void onLocalEntityChanged(NewLocalEntityEvent e) {
|
||||||
|
if (e.getNewEntity() != null) {
|
||||||
|
e.getNewEntity().subscribe(HUDManager.this);
|
||||||
|
}
|
||||||
|
if (e.getPreviousEntity() != null) {
|
||||||
|
e.getPreviousEntity().unsubscribe(HUDManager.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void install() {
|
||||||
|
GUI.addTopLayer(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
GUI.removeLayer(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void openInventory(InventoryComponent component) {
|
||||||
|
InventoryWindow window = new InventoryWindow("Window", component, this);
|
||||||
|
layer.getWindowManager().addWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeEverything() {
|
||||||
|
System.err.println("closeEverything NYI");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHidden() {
|
||||||
|
return layer.isHidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHidden(boolean hide) {
|
||||||
|
layer.setHidden(hide);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInventoryShown() {
|
||||||
|
return layer.isInventoryShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInventoryShown(boolean showInventory) {
|
||||||
|
layer.setInventoryShown(showInventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Client getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onInventoryOpened(InventoryOpenedEvent event) {
|
||||||
|
Inventory inventory = event.getInventory();
|
||||||
|
InventoryRender render = InventoryRenderRegistry.getInstance().get(inventory.getId());
|
||||||
|
|
||||||
|
if (render == null) {
|
||||||
|
throw CrashReports.report(null, "InventoryRender not found for ID %s", inventory.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
InventoryComponent component = render.createComponent(inventory, this);
|
||||||
|
openInventory(component);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw CrashReports.report(e, "Could not open inventory %s", inventory.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onInventoryClosing(InventoryClosingEvent event) {
|
||||||
|
Inventory inventory = event.getInventory();
|
||||||
|
|
||||||
|
for (Component component : layer.getWindowManager().getChildren()) {
|
||||||
|
if (component instanceof InventoryWindow) {
|
||||||
|
InventoryWindow window = (InventoryWindow) component;
|
||||||
|
if (window.getContent().getInventory() == inventory) {
|
||||||
|
layer.getWindowManager().closeWindow(window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Atlases;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.SimpleTexture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Atlases.AtlasGroup;
|
||||||
|
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||||
|
|
||||||
|
public class HUDTextures {
|
||||||
|
|
||||||
|
private static final AtlasGroup HUD_ATLAS_GROUP = new AtlasGroup("HUD", 1 << 12);
|
||||||
|
|
||||||
|
private static ItemAmountTypeface itemAmountTypeface = null;
|
||||||
|
|
||||||
|
public static Texture getHUDTexture(String name) {
|
||||||
|
return new SimpleTexture(
|
||||||
|
Atlases.getSprite(
|
||||||
|
ResourceManager.getTextureResource("gui/" + name),
|
||||||
|
HUD_ATLAS_GROUP
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AtlasGroup getHUDAtlasGroup() {
|
||||||
|
return HUD_ATLAS_GROUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemAmountTypeface getItemAmountTypeface() {
|
||||||
|
return itemAmountTypeface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadItemAmountTypeface() {
|
||||||
|
try {
|
||||||
|
itemAmountTypeface = new ItemAmountTypeface();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw CrashReports.report(e, "Could not load item amount typeface");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.Client;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerHand;
|
||||||
|
|
||||||
|
public interface HUDWorkspace {
|
||||||
|
|
||||||
|
Client getClient();
|
||||||
|
|
||||||
|
default LocalPlayer getPlayer() {
|
||||||
|
return getClient().getLocalPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
default EntityDataPlayer getPlayerEntity() {
|
||||||
|
return getClient().getLocalPlayer().getEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
default ItemContainerHand getHand() {
|
||||||
|
return getClient().getLocalPlayer().getEntity().getSelectedHand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void openInventory(InventoryComponent component);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
import ru.windcorp.progressia.client.graphics.ExponentAnimation;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
import ru.windcorp.progressia.client.world.entity.SpeciesRender;
|
||||||
|
import ru.windcorp.progressia.client.world.entity.SpeciesRenderRegistry;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
|
||||||
|
|
||||||
|
public class HandsHUD extends Component {
|
||||||
|
|
||||||
|
public class ScaledSlotComponent extends Component {
|
||||||
|
|
||||||
|
private final SlotComponent slotComponent;
|
||||||
|
private final ExponentAnimation selected = new ExponentAnimation(10, 1);
|
||||||
|
|
||||||
|
public ScaledSlotComponent(SlotComponent component) {
|
||||||
|
super(component.getName() + ".Scaled");
|
||||||
|
this.slotComponent = component;
|
||||||
|
addChild(component);
|
||||||
|
|
||||||
|
Vec2i size = slotComponent.getPreferredSize();
|
||||||
|
setPreferredSize(size.x * 2, size.y * 2);
|
||||||
|
slotComponent.setBounds(-size.x / 2, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleChildren(RenderTarget target) {
|
||||||
|
Renderable renderable = slotComponent.assembleToRenderable();
|
||||||
|
|
||||||
|
target.addCustomRenderer(renderer -> {
|
||||||
|
float scale = manager.getHand() == slotComponent.getSlot().getContainer() ? 2 : 1;
|
||||||
|
renderer.pushTransform()
|
||||||
|
.translate(getX() + getWidth() / 2, getY(), 0)
|
||||||
|
.scale(selected.updateForFrame(scale));
|
||||||
|
|
||||||
|
renderable.render(renderer);
|
||||||
|
|
||||||
|
renderer.popTransform();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Side {
|
||||||
|
LEFT("Left", LayoutBorderHorizontal.LEFT, 0.0),
|
||||||
|
RIGHT("Right", LayoutBorderHorizontal.RIGHT, 1.0),
|
||||||
|
CENTER("Center", LayoutBorderHorizontal.CENTER, 0.5);
|
||||||
|
|
||||||
|
private final String ccName;
|
||||||
|
private final Object lbhHint;
|
||||||
|
private final double align;
|
||||||
|
|
||||||
|
private Side(String ccName, Object lbhHint, double align) {
|
||||||
|
this.ccName = ccName;
|
||||||
|
this.lbhHint = lbhHint;
|
||||||
|
this.align = align;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final HUDManager manager;
|
||||||
|
|
||||||
|
public HandsHUD(String name, HUDManager manager) {
|
||||||
|
super(name);
|
||||||
|
this.manager = manager;
|
||||||
|
|
||||||
|
EntityDataPlayer entity = manager.getPlayerEntity();
|
||||||
|
String speciesId = entity.getSpecies().getId();
|
||||||
|
SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(speciesId);
|
||||||
|
|
||||||
|
Map<Side, Component> containers = Maps.toMap(
|
||||||
|
Arrays.asList(Side.values()),
|
||||||
|
side -> new Group(name + "." + side.ccName, new LayoutHorizontal(15))
|
||||||
|
);
|
||||||
|
|
||||||
|
for (int i = 0; i < entity.getHandCount(); ++i) {
|
||||||
|
|
||||||
|
Hand hand = entity.getSpecies().getHands().get(i);
|
||||||
|
|
||||||
|
SlotComponent display = new SlotComponent(name + "." + hand.getName(), entity.getHand(i), 0)
|
||||||
|
.setBackground(speciesRender.getHandBackground(hand), this::shouldRenderHandPlaceholder)
|
||||||
|
.setScale(2);
|
||||||
|
|
||||||
|
Component scaledDisplay = new ScaledSlotComponent(display);
|
||||||
|
|
||||||
|
containers.get(speciesRender.getHandSide(hand)).addChild(scaledDisplay);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayout(new LayoutBorderHorizontal());
|
||||||
|
|
||||||
|
containers.forEach((side, comp) -> {
|
||||||
|
addChild(
|
||||||
|
new Group(name + "." + side.ccName + ".Aligner", new LayoutAlign(side.align, 0.5, 0), comp)
|
||||||
|
.setLayoutHint(side.lbhHint)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldRenderHandPlaceholder() {
|
||||||
|
return manager.isInventoryShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Button;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Label;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent;
|
||||||
|
import ru.windcorp.progressia.common.Units;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemSlot;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Items;
|
||||||
|
|
||||||
|
public class InteractiveSlotComponent extends Button {
|
||||||
|
|
||||||
|
private static final double MIN_PICK_ALL_DELAY = Units.get("0.5 s");
|
||||||
|
|
||||||
|
private double lastMainAction = Double.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
private final SlotComponent slotComponent;
|
||||||
|
private final HUDWorkspace workspace;
|
||||||
|
|
||||||
|
public InteractiveSlotComponent(String name, ItemContainer container, int index, HUDWorkspace workspace) {
|
||||||
|
this(name, new SlotComponent(name, container, index), workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InteractiveSlotComponent(SlotComponent component, HUDWorkspace workspace) {
|
||||||
|
this(component.getName() + ".Interactive", component, workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InteractiveSlotComponent(String name, SlotComponent component, HUDWorkspace workspace) {
|
||||||
|
super(name, (Label) null);
|
||||||
|
this.slotComponent = component;
|
||||||
|
this.workspace = workspace;
|
||||||
|
|
||||||
|
Vec2i size = slotComponent.getPreferredSize().add(2 * BORDER);
|
||||||
|
setPreferredSize(size);
|
||||||
|
|
||||||
|
addChild(this.slotComponent);
|
||||||
|
setLayout(new LayoutFill(MARGIN));
|
||||||
|
|
||||||
|
addListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addListeners() {
|
||||||
|
addAction(button -> onMainAction());
|
||||||
|
|
||||||
|
addKeyListener(KeyMatcher.RMB, this::onAltAction);
|
||||||
|
|
||||||
|
addInputListener(WheelScrollEvent.class, event -> {
|
||||||
|
if (event.hasVerticalMovement()) {
|
||||||
|
onSingleMoveAction(event.isDown());
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onMainAction() {
|
||||||
|
ItemSlot handSlot = workspace.getHand().slot();
|
||||||
|
ItemSlot invSlot = getSlot();
|
||||||
|
if (invSlot == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
double now = GraphicsInterface.getTime();
|
||||||
|
if (now - lastMainAction < MIN_PICK_ALL_DELAY) {
|
||||||
|
lastMainAction = Double.NEGATIVE_INFINITY;
|
||||||
|
pickAll(handSlot);
|
||||||
|
success = true;
|
||||||
|
} else {
|
||||||
|
lastMainAction = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
success = Items.pour(handSlot, invSlot) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
success = Items.swap(handSlot, invSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success && handSlot.isEmpty()) {
|
||||||
|
success = Items.pour(invSlot, handSlot) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pickAll(ItemSlot handSlot) {
|
||||||
|
int maxIndex = getSlot().getContainer().getMaxIndex();
|
||||||
|
for (int index = 0; index < maxIndex; ++index) {
|
||||||
|
Items.pour(new ItemSlot(getSlot().getContainer(), index), handSlot);
|
||||||
|
if (handSlot.isEmpty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAltAction(KeyEvent e) {
|
||||||
|
ItemSlot handSlot = workspace.getHand().slot();
|
||||||
|
ItemSlot invSlot = getSlot();
|
||||||
|
if (invSlot == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean success = false;
|
||||||
|
|
||||||
|
if (handSlot.isEmpty()) {
|
||||||
|
success = tryToOpen(invSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success && handSlot.isEmpty()) {
|
||||||
|
success = Items.pour(invSlot, handSlot, invSlot.getCount() / 2) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
success = Items.pour(handSlot, invSlot, 1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
success = Items.swap(handSlot, invSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryToOpen(ItemSlot invSlot) {
|
||||||
|
if (invSlot.getCount() != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!(invSlot.getItem() instanceof ItemDataContainer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemDataContainer item = (ItemDataContainer) invSlot.getItem();
|
||||||
|
return item.open(workspace.getPlayerEntity()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSingleMoveAction(boolean fromHand) {
|
||||||
|
ItemSlot handSlot = workspace.getHand().slot();
|
||||||
|
ItemSlot invSlot = getSlot();
|
||||||
|
|
||||||
|
ItemSlot from = fromHand ? handSlot : invSlot;
|
||||||
|
ItemSlot into = fromHand ? invSlot : handSlot;
|
||||||
|
|
||||||
|
if (Items.pour(from, into, 1) != 0) {
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSlot getSlot() {
|
||||||
|
return slotComponent.getSlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||||
|
import ru.windcorp.progressia.client.world.entity.SpeciesRender;
|
||||||
|
import ru.windcorp.progressia.client.world.entity.SpeciesRenderRegistry;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData.EquipmentSlot;
|
||||||
|
|
||||||
|
public class InventoryHUD extends Component {
|
||||||
|
|
||||||
|
public enum Side {
|
||||||
|
LEFT("Left", LayoutBorderHorizontal.LEFT),
|
||||||
|
RIGHT("Right", LayoutBorderHorizontal.RIGHT);
|
||||||
|
|
||||||
|
private final String ccName;
|
||||||
|
private final Object lbhHint;
|
||||||
|
|
||||||
|
private Side(String ccName, Object lbhHint) {
|
||||||
|
this.ccName = ccName;
|
||||||
|
this.lbhHint = lbhHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryHUD(String name, HUDWorkspace workspace) {
|
||||||
|
super(name);
|
||||||
|
setLayout(new LayoutBorderHorizontal());
|
||||||
|
|
||||||
|
EntityDataPlayer entity = workspace.getPlayerEntity();
|
||||||
|
String speciesId = entity.getSpecies().getId();
|
||||||
|
SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(speciesId);
|
||||||
|
|
||||||
|
Map<Side, Component> containers = Maps.toMap(
|
||||||
|
Arrays.asList(Side.values()),
|
||||||
|
side -> new Group(name + "." + side.ccName, new LayoutVertical(15))
|
||||||
|
);
|
||||||
|
|
||||||
|
for (int i = 0; i < entity.getEquipmentCount(); ++i) {
|
||||||
|
|
||||||
|
EquipmentSlot slot = entity.getSpecies().getEquipmentSlots().get(i);
|
||||||
|
|
||||||
|
SlotComponent display = new SlotComponent(name + "." + slot.getName(), entity.getEquipmentSlot(i), 0)
|
||||||
|
.setBackground(speciesRender.getEquipmentSlotBackground(slot))
|
||||||
|
.setScale(2);
|
||||||
|
|
||||||
|
InteractiveSlotComponent interactiveDisplay = new InteractiveSlotComponent(
|
||||||
|
display,
|
||||||
|
workspace
|
||||||
|
);
|
||||||
|
|
||||||
|
containers.get(speciesRender.getEquipmentSlotSide(slot)).addChild(interactiveDisplay);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
containers.forEach((side, comp) -> {
|
||||||
|
addChild(
|
||||||
|
new Group(name + "." + side.ccName + ".Aligner", new LayoutAlign(0, 1, 0), comp)
|
||||||
|
.setLayoutHint(side.lbhHint)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import glm.vec._2.Vec2;
|
||||||
|
import glm.vec._4.Vec4;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.Typeface;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Button;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.DragManager;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Label;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Panel;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.event.DragEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||||
|
import ru.windcorp.progressia.client.localization.MutableString;
|
||||||
|
import ru.windcorp.progressia.client.localization.MutableStringConcat;
|
||||||
|
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||||
|
import ru.windcorp.progressia.client.world.item.inventory.InventoryComponent;
|
||||||
|
|
||||||
|
public class InventoryWindow extends Panel {
|
||||||
|
|
||||||
|
private static final String CLOSE_CHAR = "\u2715";
|
||||||
|
private static final String HANDLE_CHAR = "\u2800";
|
||||||
|
private static final Vec4 CLOSE_BUTTON_IDLE = Colors.toVector(0xFFBC1515);
|
||||||
|
private static final Vec4 CLOSE_BUTTON_HOVER = Colors.toVector(0xFFFA6464);
|
||||||
|
private static final Vec4 CLOSE_BUTTON_PRESSED = Colors.BLACK;
|
||||||
|
|
||||||
|
private final InventoryComponent content;
|
||||||
|
private final HUDWorkspace workspace;
|
||||||
|
|
||||||
|
private final Vec2 relativePosition = new Vec2(Float.NaN);
|
||||||
|
|
||||||
|
public InventoryWindow(String name, InventoryComponent component, HUDWorkspace workspace) {
|
||||||
|
super(name, new LayoutVertical(15, 15));
|
||||||
|
this.content = component;
|
||||||
|
this.workspace = workspace;
|
||||||
|
|
||||||
|
Group titleBar = new Group(getName() + ".TitleBar", new LayoutBorderHorizontal());
|
||||||
|
titleBar.addChild(createLabel(component).setLayoutHint(LayoutBorderHorizontal.CENTER));
|
||||||
|
titleBar.addChild(createCloseButton(component).setLayoutHint(LayoutBorderHorizontal.RIGHT));
|
||||||
|
|
||||||
|
new DragManager().install(titleBar);
|
||||||
|
titleBar.addListener(new Object() {
|
||||||
|
@Subscribe
|
||||||
|
public void onWindowDragged(DragEvent e) {
|
||||||
|
Vec2 change = new Vec2((float) e.getCurrentChangeX(), (float) e.getCurrentChangeY());
|
||||||
|
change.div(getParent().getWidth(), getParent().getHeight());
|
||||||
|
relativePosition.add(change);
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
addChild(titleBar);
|
||||||
|
|
||||||
|
addChild(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Label createLabel(InventoryComponent component) {
|
||||||
|
String translationKey = "Inventory." + component.getInventory().getId() + ".Title";
|
||||||
|
MutableString titleText = new MutableStringConcat(
|
||||||
|
HANDLE_CHAR + " ",
|
||||||
|
new MutableStringLocalized(translationKey)
|
||||||
|
);
|
||||||
|
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(Typeface.ALIGN_LEFT);
|
||||||
|
|
||||||
|
return new Label(getName() + ".Title", titleFont, titleText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private WindowedHUD getManager() {
|
||||||
|
Component parent = getParent();
|
||||||
|
if (parent instanceof WindowedHUD) {
|
||||||
|
return (WindowedHUD) parent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the relativePosition
|
||||||
|
*/
|
||||||
|
public Vec2 getRelativePosition() {
|
||||||
|
return relativePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component createCloseButton(InventoryComponent component) {
|
||||||
|
|
||||||
|
Button button = new Button(getName() + ".CloseButton", CLOSE_CHAR) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleSelf(RenderTarget target) {
|
||||||
|
|
||||||
|
Vec4 color = CLOSE_BUTTON_IDLE;
|
||||||
|
if (isPressed()) {
|
||||||
|
color = CLOSE_BUTTON_PRESSED;
|
||||||
|
} else if (isHovered()) {
|
||||||
|
color = CLOSE_BUTTON_HOVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasLabel()) {
|
||||||
|
getLabel().setFont(getLabel().getFont().withColor(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
button.addAction(b -> {
|
||||||
|
|
||||||
|
content.getInventory().close(workspace.getPlayerEntity());
|
||||||
|
|
||||||
|
WindowedHUD manager = getManager();
|
||||||
|
if (manager == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.closeWindow(this);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
button.setLayout(new LayoutFill());
|
||||||
|
|
||||||
|
int height = button.getLabel().getFont().getHeight(button.getLabel().getCurrentText());
|
||||||
|
button.setPreferredSize(height, height);
|
||||||
|
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InventoryComponent getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.SpriteTypeface;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.ComplexTexture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.TextureLoader;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.TexturePrimitive;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.TextureSettings;
|
||||||
|
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||||
|
|
||||||
|
public class ItemAmountTypeface extends SpriteTypeface {
|
||||||
|
|
||||||
|
public static final int HEIGHT = 5;
|
||||||
|
public static final int WIDTH = 3;
|
||||||
|
|
||||||
|
private final Texture[] textures = new Texture[10];
|
||||||
|
|
||||||
|
public ItemAmountTypeface() throws IOException {
|
||||||
|
super("ItemAmount", HEIGHT, 1);
|
||||||
|
|
||||||
|
ComplexTexture atlas = new ComplexTexture(new TexturePrimitive(
|
||||||
|
TextureLoader.loadPixels(
|
||||||
|
ResourceManager.getTextureResource("gui/ItemAmountTypeface"),
|
||||||
|
new TextureSettings(false)
|
||||||
|
).getData()
|
||||||
|
), 30, 5);
|
||||||
|
|
||||||
|
for (int i = 0; i <= 9; ++i) {
|
||||||
|
textures[i] = atlas.get(i * WIDTH, 0, WIDTH, HEIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Texture getTexture(char c) {
|
||||||
|
if (!supports(c))
|
||||||
|
return textures[0];
|
||||||
|
return textures[c - '0'];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShapeRenderProgram getProgram() {
|
||||||
|
return FlatRenderProgram.getDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(char c) {
|
||||||
|
return c >= '0' && c <= '9';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.events.NewLocalEntityEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.GUI;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Components;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.KeyMatcher;
|
||||||
|
import ru.windcorp.progressia.client.graphics.input.bus.InputBus;
|
||||||
|
import ru.windcorp.progressia.test.controls.TestPlayerControls;
|
||||||
|
|
||||||
|
public class LayerHUD extends GUILayer {
|
||||||
|
|
||||||
|
private final HUDManager manager;
|
||||||
|
private WindowedHUD windowManager = null;
|
||||||
|
|
||||||
|
private boolean showInventory = false;
|
||||||
|
private boolean isHidden = false;
|
||||||
|
|
||||||
|
public LayerHUD(HUDManager manager) {
|
||||||
|
super("LayerHUD", new LayoutFill(15));
|
||||||
|
this.manager = manager;
|
||||||
|
|
||||||
|
setCursorPolicy(CursorPolicy.INDIFFERENT);
|
||||||
|
|
||||||
|
manager.getClient().subscribe(this);
|
||||||
|
|
||||||
|
getRoot().addKeyListener(new KeyMatcher("Escape"), e -> {
|
||||||
|
setInventoryShown(!showInventory);
|
||||||
|
e.consume();
|
||||||
|
}, InputBus.Option.IGNORE_FOCUS);
|
||||||
|
|
||||||
|
getRoot().addKeyListener(new KeyMatcher("E"), e -> {
|
||||||
|
setInventoryShown(!showInventory);
|
||||||
|
e.consume();
|
||||||
|
}, InputBus.Option.IGNORE_FOCUS);
|
||||||
|
|
||||||
|
getRoot().addKeyListener(new KeyMatcher("Left Control"), e -> {
|
||||||
|
TestPlayerControls.getInstance().getInventoryControls().switchHandsWithCtrl(e);
|
||||||
|
e.consume();
|
||||||
|
}, InputBus.Option.IGNORE_ACTION, InputBus.Option.IGNORE_FOCUS);
|
||||||
|
|
||||||
|
getRoot().addKeyListener(new KeyMatcher("Right Control"), e -> {
|
||||||
|
TestPlayerControls.getInstance().getInventoryControls().switchHandsWithCtrl(e);
|
||||||
|
e.consume();
|
||||||
|
}, InputBus.Option.IGNORE_ACTION, InputBus.Option.IGNORE_FOCUS);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onEntityChanged(NewLocalEntityEvent e) {
|
||||||
|
while (!getRoot().getChildren().isEmpty()) {
|
||||||
|
getRoot().removeChild(getRoot().getChild(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.getNewEntity() == null) {
|
||||||
|
getRoot().requestReassembly();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoot().addChild(new PermanentHUD(getName() + ".Permanent", manager));
|
||||||
|
|
||||||
|
Component inventoryGroup = new Group(getName() + ".InventoryGroup", new LayoutFill());
|
||||||
|
|
||||||
|
inventoryGroup.addChild(new InventoryHUD(getName() + ".Equipment", manager));
|
||||||
|
|
||||||
|
windowManager = new WindowedHUD(getName() + ".Windows");
|
||||||
|
inventoryGroup.addChild(windowManager);
|
||||||
|
|
||||||
|
inventoryGroup.addChild(new CursorHUD(getName() + ".Cursor", manager.getPlayerEntity()));
|
||||||
|
|
||||||
|
getRoot().addChild(Components.hide(inventoryGroup, () -> !showInventory));
|
||||||
|
|
||||||
|
getRoot().requestReassembly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public WindowedHUD getWindowManager() {
|
||||||
|
return windowManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInventoryShown() {
|
||||||
|
return showInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInventoryShown(boolean showInventory) {
|
||||||
|
this.showInventory = showInventory;
|
||||||
|
updateCursorPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHidden() {
|
||||||
|
return isHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHidden(boolean isHidden) {
|
||||||
|
this.isHidden = isHidden;
|
||||||
|
updateCursorPolicy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCursorPolicy() {
|
||||||
|
if (showInventory && !isHidden) {
|
||||||
|
setCursorPolicy(CursorPolicy.REQUIRE);
|
||||||
|
} else {
|
||||||
|
setCursorPolicy(CursorPolicy.INDIFFERENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.updateLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleInput(InputEvent event) {
|
||||||
|
if (isHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.handleInput(event);
|
||||||
|
|
||||||
|
if (getCursorPolicy() == CursorPolicy.REQUIRE) {
|
||||||
|
event.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doRender() {
|
||||||
|
if (isHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.doRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderVertical;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
|
public class PermanentHUD extends Component {
|
||||||
|
|
||||||
|
public PermanentHUD(String name, HUDManager manager) {
|
||||||
|
super(name);
|
||||||
|
setLayout(new LayoutBorderVertical());
|
||||||
|
|
||||||
|
EntityDataPlayer entity = manager.getPlayerEntity();
|
||||||
|
if (entity == null) {
|
||||||
|
throw new IllegalStateException("Player " + manager.getPlayer() + " does not have an associated entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(new HandsHUD(name + ".Hands", manager).setLayoutHint(LayoutBorderVertical.UP));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
import glm.mat._4.Mat4;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||||
|
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.DynamicLabel;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Shapes.PgmBuilder;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.world.item.ItemRenderRegistry;
|
||||||
|
import ru.windcorp.progressia.client.world.item.ItemRenderable;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemDataContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemSlot;
|
||||||
|
|
||||||
|
public class SlotComponent extends Component {
|
||||||
|
|
||||||
|
static final float TEXTURE_SIZE = 24;
|
||||||
|
|
||||||
|
private static boolean drawVirtualSlots;
|
||||||
|
static {
|
||||||
|
String key = SlotComponent.class.getName() + ".drawVirtualSlots";
|
||||||
|
drawVirtualSlots = Boolean.parseBoolean(System.getProperty(key, "true"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Renderable containerOpenDecoration = null;
|
||||||
|
private static Renderable containerOpenableDecoration = null;
|
||||||
|
|
||||||
|
private final ItemSlot slot;
|
||||||
|
|
||||||
|
private float scale = 2;
|
||||||
|
|
||||||
|
private ItemRenderable itemRenderer = null;
|
||||||
|
|
||||||
|
private int amountDisplayInt = 0;
|
||||||
|
private String amountDisplayString = "";
|
||||||
|
|
||||||
|
private Renderable background = null;
|
||||||
|
private BooleanSupplier backgroundCondition = null;
|
||||||
|
|
||||||
|
public SlotComponent(String name, ItemContainer container, int index) {
|
||||||
|
super(name);
|
||||||
|
this.slot = new ItemSlot(container, index);
|
||||||
|
|
||||||
|
setScale(2);
|
||||||
|
|
||||||
|
Font sizeFont = new Font(HUDTextures.getItemAmountTypeface()).deriveOutlined().withScale(2);
|
||||||
|
addChild(new DynamicLabel(getName() + ".Size", sizeFont, () -> amountDisplayString, getPreferredSize().x));
|
||||||
|
|
||||||
|
setLayout(new LayoutAlign(0, 0, 0));
|
||||||
|
|
||||||
|
if (containerOpenDecoration == null) {
|
||||||
|
containerOpenDecoration = new PgmBuilder(
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
HUDTextures.getHUDTexture("DecorationContainerOpen")
|
||||||
|
).setSize(TEXTURE_SIZE + 2).setOrigin(-1, -1, 0).create();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (containerOpenableDecoration == null) {
|
||||||
|
containerOpenableDecoration = new PgmBuilder(
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
HUDTextures.getHUDTexture("DecorationContainerOpenable")
|
||||||
|
).setSize(TEXTURE_SIZE + 2).setOrigin(-1, -1, 0).create();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the container
|
||||||
|
*/
|
||||||
|
public ItemContainer getSlotContainer() {
|
||||||
|
return slot.getContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the index
|
||||||
|
*/
|
||||||
|
public int getSlotIndex() {
|
||||||
|
return slot.getIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemSlot getSlot() {
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotComponent setScale(float scale) {
|
||||||
|
this.scale = scale;
|
||||||
|
|
||||||
|
int side = (int) (TEXTURE_SIZE * scale);
|
||||||
|
setPreferredSize(side, side);
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotComponent setBackground(Texture texture, BooleanSupplier when) {
|
||||||
|
background = new PgmBuilder(FlatRenderProgram.getDefault(), texture).setSize(TEXTURE_SIZE).create();
|
||||||
|
setBackgroundDisplayCondition(when);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotComponent setBackground(Texture texture) {
|
||||||
|
return setBackground(texture, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotComponent setBackgroundDisplayCondition(BooleanSupplier backgroundCondition) {
|
||||||
|
this.backgroundCondition = backgroundCondition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void assembleSelf(RenderTarget target) {
|
||||||
|
super.assembleSelf(target);
|
||||||
|
assembleItem(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateItemRenderer() {
|
||||||
|
ItemData contents;
|
||||||
|
contents = slot.getItem();
|
||||||
|
|
||||||
|
if (contents == null) {
|
||||||
|
itemRenderer = null;
|
||||||
|
amountDisplayInt = 0;
|
||||||
|
amountDisplayString = "";
|
||||||
|
} else {
|
||||||
|
if (itemRenderer == null || itemRenderer.getData() != contents) {
|
||||||
|
itemRenderer = ItemRenderRegistry.getInstance().get(contents.getId()).createRenderable(contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
int newAmount = slot.getCount();
|
||||||
|
if (newAmount != amountDisplayInt) {
|
||||||
|
amountDisplayInt = newAmount;
|
||||||
|
amountDisplayString = newAmount == 1 ? "" : Integer.toString(newAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assembleItem(RenderTarget target) {
|
||||||
|
target.pushTransform(new Mat4().translate(getX(), getY(), 0).scale(scale, scale, 1));
|
||||||
|
target.addCustomRenderer(renderer -> {
|
||||||
|
|
||||||
|
updateItemRenderer();
|
||||||
|
|
||||||
|
if (drawVirtualSlots && getSlot() == null) {
|
||||||
|
renderer.pushColorMultiplier().set(Colors.DEBUG_GREEN);
|
||||||
|
containerOpenDecoration.render(renderer);
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemRenderer != null) {
|
||||||
|
itemRenderer.render(renderer);
|
||||||
|
renderDecorations(renderer);
|
||||||
|
} else if (background != null) {
|
||||||
|
if (backgroundCondition == null || backgroundCondition.getAsBoolean()) {
|
||||||
|
background.render(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
target.popTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderDecorations(ShapeRenderHelper renderer) {
|
||||||
|
ItemData contents = getSlot().getItem();
|
||||||
|
|
||||||
|
if (contents instanceof ItemDataContainer) {
|
||||||
|
ItemDataContainer asContainer = (ItemDataContainer) contents;
|
||||||
|
|
||||||
|
if (asContainer.isOpen()) {
|
||||||
|
renderer.pushColorMultiplier().mul(Colors.BLUE);
|
||||||
|
containerOpenDecoration.render(renderer);
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
double dx = InputTracker.getCursorX() - (getX() + getWidth() / 2);
|
||||||
|
double dy = InputTracker.getCursorY() - (getY() + getHeight() / 2);
|
||||||
|
double distanceToCursorSquared = dx*dx + dy*dy;
|
||||||
|
final double maxDistanceSquared = (scale * TEXTURE_SIZE * 4) * (scale * TEXTURE_SIZE * 4);
|
||||||
|
|
||||||
|
float opacity = (float) (1 - distanceToCursorSquared / maxDistanceSquared);
|
||||||
|
|
||||||
|
if (opacity > 0) {
|
||||||
|
renderer.pushColorMultiplier().mul(Colors.BLUE.x, Colors.BLUE.y, Colors.BLUE.z, opacity);
|
||||||
|
containerOpenableDecoration.render(renderer);
|
||||||
|
renderer.popColorMultiplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
|
||||||
|
public class WindowedHUD extends Component {
|
||||||
|
|
||||||
|
public WindowedHUD(String name) {
|
||||||
|
super(name);
|
||||||
|
setLayout(new WindowedLayout());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addWindow(InventoryWindow window) {
|
||||||
|
addChild(window);
|
||||||
|
window.setSize(window.getPreferredSize());
|
||||||
|
|
||||||
|
centerWindow(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeWindow(InventoryWindow window) {
|
||||||
|
removeChild(window);
|
||||||
|
requestReassembly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void centerWindow(InventoryWindow window) {
|
||||||
|
window.setPosition(
|
||||||
|
(getWidth() - window.getWidth()) / 2,
|
||||||
|
(getHeight() - window.getHeight()) / 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.graphics.world.hud;
|
||||||
|
|
||||||
|
import glm.Glm;
|
||||||
|
import glm.vec._2.Vec2;
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||||
|
|
||||||
|
public class WindowedLayout implements Layout {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void layout(Component c) {
|
||||||
|
for (Component component : c.getChildren()) {
|
||||||
|
InventoryWindow window = (InventoryWindow) component;
|
||||||
|
|
||||||
|
Vec2i size = new Vec2i(c.getWidth(), c.getHeight());
|
||||||
|
Glm.min(window.getPreferredSize(), size, size);
|
||||||
|
window.setSize(size);
|
||||||
|
|
||||||
|
Vec2 relPos = window.getRelativePosition();
|
||||||
|
|
||||||
|
if (Float.isNaN(relPos.x) || Float.isNaN(relPos.y)) {
|
||||||
|
relPos.x = 0.5f;
|
||||||
|
relPos.y = 2 / 3.0f;
|
||||||
|
} else {
|
||||||
|
float minPosX = 0;
|
||||||
|
float minPosY = window.getHeight() / (float) c.getHeight();
|
||||||
|
float maxPosX = 1;
|
||||||
|
float maxPosY = 1;
|
||||||
|
|
||||||
|
relPos.x = Glm.clamp(relPos.x, minPosX, maxPosX);
|
||||||
|
relPos.y = Glm.clamp(relPos.y, minPosY, maxPosY);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setPosition(
|
||||||
|
(int) (relPos.x * c.getWidth() - window.getWidth() / 2.0f),
|
||||||
|
(int) (relPos.y * c.getHeight() - window.getHeight())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vec2i calculatePreferredSize(Component c) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -72,6 +72,12 @@ public class Localizer {
|
|||||||
public synchronized String getLanguage() {
|
public synchronized String getLanguage() {
|
||||||
return language;
|
return language;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getLanguages() {
|
||||||
|
List<String> result = new ArrayList<>(langList.keySet());
|
||||||
|
result.sort(null);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized String getValue(String key) {
|
public synchronized String getValue(String key) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||||
|
|
||||||
|
public abstract class UpdatingRenderable implements Renderable {
|
||||||
|
|
||||||
|
private long stateComputedForFrame = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the state of this model. This method is invoked exactly once per
|
||||||
|
* renderable per frame before this model is queried for the first time.
|
||||||
|
*/
|
||||||
|
protected void update() {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateIfNecessary() {
|
||||||
|
if (stateComputedForFrame != GraphicsInterface.getFramesRendered()) {
|
||||||
|
update();
|
||||||
|
stateComputedForFrame = GraphicsInterface.getFramesRendered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void render(ShapeRenderHelper renderer) {
|
||||||
|
updateIfNecessary();
|
||||||
|
doRender(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doRender(ShapeRenderHelper renderer);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.entity;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
|
public class EntityRenderPlayer extends EntityRender {
|
||||||
|
|
||||||
|
public EntityRenderPlayer(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityRenderable createRenderable(EntityData entity) {
|
||||||
|
EntityDataPlayer playerEntity = (EntityDataPlayer) entity;
|
||||||
|
|
||||||
|
String speciesId = playerEntity.getSpecies().getId();
|
||||||
|
SpeciesRender speciesRender = SpeciesRenderRegistry.getInstance().get(speciesId);
|
||||||
|
|
||||||
|
return speciesRender.createRenderable(playerEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,45 +19,18 @@
|
|||||||
package ru.windcorp.progressia.client.world.entity;
|
package ru.windcorp.progressia.client.world.entity;
|
||||||
|
|
||||||
import glm.vec._3.Vec3;
|
import glm.vec._3.Vec3;
|
||||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
import ru.windcorp.progressia.client.world.UpdatingRenderable;
|
||||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
|
||||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
|
||||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||||
import ru.windcorp.progressia.common.world.generic.EntityGeneric;
|
import ru.windcorp.progressia.common.world.generic.EntityGeneric;
|
||||||
|
|
||||||
public abstract class EntityRenderable implements Renderable, EntityGeneric {
|
public abstract class EntityRenderable extends UpdatingRenderable implements EntityGeneric {
|
||||||
|
|
||||||
private final EntityData data;
|
private final EntityData data;
|
||||||
|
|
||||||
private long stateComputedForFrame = -1;
|
|
||||||
|
|
||||||
public EntityRenderable(EntityData data) {
|
public EntityRenderable(EntityData data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the state of this model. This method is invoked exactly once per
|
|
||||||
* renderable per frame before this entity is queried for the first time.
|
|
||||||
*/
|
|
||||||
protected void update() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateIfNecessary() {
|
|
||||||
if (stateComputedForFrame != GraphicsInterface.getFramesRendered()) {
|
|
||||||
update();
|
|
||||||
stateComputedForFrame = GraphicsInterface.getFramesRendered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void render(ShapeRenderHelper renderer) {
|
|
||||||
updateIfNecessary();
|
|
||||||
doRender(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void doRender(ShapeRenderHelper renderer);
|
|
||||||
|
|
||||||
public EntityData getData() {
|
public EntityData getData() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.entity;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.InventoryHUD;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDTextures;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HandsHUD;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData.EquipmentSlot;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
|
||||||
|
|
||||||
|
public abstract class SpeciesRender extends Namespaced {
|
||||||
|
|
||||||
|
public SpeciesRender(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract EntityRenderable createRenderable(EntityDataPlayer entity);
|
||||||
|
|
||||||
|
public abstract HandsHUD.Side getHandSide(Hand hand);
|
||||||
|
public abstract InventoryHUD.Side getEquipmentSlotSide(EquipmentSlot equipmentSlot);
|
||||||
|
|
||||||
|
public Texture getTexture(String name) {
|
||||||
|
return HUDTextures.getHUDTexture(getNamespace() + "_" + getName() + "/" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Texture getHandBackground(Hand hand) {
|
||||||
|
return getTexture("Hand" + hand.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Texture getEquipmentSlotBackground(EquipmentSlot slot) {
|
||||||
|
return getTexture("EquipmentSlot" + slot.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.entity;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||||
|
|
||||||
|
public class SpeciesRenderRegistry extends NamespacedInstanceRegistry<SpeciesRender> {
|
||||||
|
|
||||||
|
private static final SpeciesRenderRegistry INSTANCE = new SpeciesRenderRegistry();
|
||||||
|
|
||||||
|
public static SpeciesRenderRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeciesRender get(EntityDataPlayer player) {
|
||||||
|
return get(player.getSpecies().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
|
||||||
|
public abstract class ItemRender extends Namespaced {
|
||||||
|
|
||||||
|
public ItemRender(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract ItemRenderable createRenderable(ItemData data);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ru.windcorp.progressia.client.world.item;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Atlases;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.SimpleTexture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Atlases.AtlasGroup;
|
||||||
|
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
|
||||||
|
|
||||||
|
public class ItemRenderRegistry extends NamespacedInstanceRegistry<ItemRender> {
|
||||||
|
|
||||||
|
private static final ItemRenderRegistry INSTANCE = new ItemRenderRegistry();
|
||||||
|
|
||||||
|
private static final AtlasGroup ITEMS_ATLAS_GROUP = new AtlasGroup("Items", 1 << 12);
|
||||||
|
|
||||||
|
public static ItemRenderRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Texture getItemTexture(String name) {
|
||||||
|
return new SimpleTexture(
|
||||||
|
Atlases.getSprite(
|
||||||
|
ResourceManager.getTextureResource("items/" + name),
|
||||||
|
ITEMS_ATLAS_GROUP
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AtlasGroup getItemsAtlasGroup() {
|
||||||
|
return ITEMS_ATLAS_GROUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item;
|
||||||
|
|
||||||
|
import glm.vec._3.Vec3;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
import ru.windcorp.progressia.client.graphics.backend.Usage;
|
||||||
|
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.Shape;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeParts;
|
||||||
|
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||||
|
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
|
||||||
|
public class ItemRenderSimple extends ItemRender {
|
||||||
|
|
||||||
|
private Texture texture;
|
||||||
|
private Renderable renderable;
|
||||||
|
|
||||||
|
public ItemRenderSimple(String id, Texture texture) {
|
||||||
|
super(id);
|
||||||
|
this.texture = texture;
|
||||||
|
|
||||||
|
this.renderable = new Shape(
|
||||||
|
Usage.STATIC,
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
ShapeParts.createRectangle(
|
||||||
|
FlatRenderProgram.getDefault(),
|
||||||
|
texture,
|
||||||
|
Colors.WHITE,
|
||||||
|
new Vec3(0, 0, 0),
|
||||||
|
new Vec3(24, 0, 0),
|
||||||
|
new Vec3(0, 24, 0),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Texture getTexture() {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemRenderable createRenderable(ItemData data) {
|
||||||
|
return new ItemRenderable(data) {
|
||||||
|
@Override
|
||||||
|
protected void doRender(ShapeRenderHelper renderer) {
|
||||||
|
renderable.render(renderer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,48 +15,21 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item;
|
||||||
package ru.windcorp.progressia.client.graphics.input.bus;
|
|
||||||
|
|
||||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
import ru.windcorp.progressia.client.world.UpdatingRenderable;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
|
||||||
public class Input {
|
public abstract class ItemRenderable extends UpdatingRenderable {
|
||||||
|
|
||||||
public static enum Target {
|
private final ItemData data;
|
||||||
FOCUSED, HOVERED, ALL
|
|
||||||
|
public ItemRenderable(ItemData data) {
|
||||||
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InputEvent event;
|
public ItemData getData() {
|
||||||
|
return data;
|
||||||
private boolean isConsumed;
|
|
||||||
|
|
||||||
private Target target;
|
|
||||||
|
|
||||||
protected void initialize(InputEvent event, Target target) {
|
|
||||||
this.event = event;
|
|
||||||
this.target = target;
|
|
||||||
|
|
||||||
this.isConsumed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputEvent getEvent() {
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isConsumed() {
|
|
||||||
return isConsumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConsumed(boolean isConsumed) {
|
|
||||||
this.isConsumed = isConsumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void consume() {
|
|
||||||
setConsumed(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Target getTarget() {
|
|
||||||
return target;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.InteractiveSlotComponent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
|
||||||
|
public abstract class ContainerComponent extends Component {
|
||||||
|
|
||||||
|
public ContainerComponent(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract ItemContainer getContainer();
|
||||||
|
|
||||||
|
public abstract Collection<InteractiveSlotComponent> getSlots();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import glm.vec._2.i.Vec2i;
|
||||||
|
import ru.windcorp.progressia.client.graphics.Colors;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderHorizontal;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutBorderVertical;
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutGrid;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.Bar;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.InteractiveSlotComponent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.ItemSlotChangedEvent;
|
||||||
|
|
||||||
|
public class ContainerComponentSimple extends ContainerComponent {
|
||||||
|
|
||||||
|
private final Group slots = new Group("Inventory.Slots", new LayoutGrid(0, 15));
|
||||||
|
private final List<InteractiveSlotComponent> slotCollection = new ArrayList<>();
|
||||||
|
|
||||||
|
private final ItemContainer container;
|
||||||
|
private final HUDWorkspace workspace;
|
||||||
|
|
||||||
|
private int tmp__getSlotsPerRow() {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContainerComponentSimple(ItemContainer container, HUDWorkspace workspace) {
|
||||||
|
super("Inventory");
|
||||||
|
this.container = container;
|
||||||
|
this.workspace = workspace;
|
||||||
|
|
||||||
|
if (container.getInventory() != null) {
|
||||||
|
container.getInventory().subscribe(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayout(new LayoutBorderHorizontal(15));
|
||||||
|
|
||||||
|
Bar massBar = new Bar(
|
||||||
|
"MassBar",
|
||||||
|
true,
|
||||||
|
Colors.toVector(0xFF44AAAA),
|
||||||
|
container::getMass,
|
||||||
|
container::getMassLimit
|
||||||
|
);
|
||||||
|
Bar volumeBar = new Bar(
|
||||||
|
"VolumeBar",
|
||||||
|
false,
|
||||||
|
Colors.toVector(0xFFAA4444),
|
||||||
|
container::getVolume,
|
||||||
|
container::getVolumeLimit
|
||||||
|
);
|
||||||
|
|
||||||
|
Component slotsAndVolumeBar = new Group(
|
||||||
|
"SlotsAndVolumeBar",
|
||||||
|
new LayoutBorderVertical(15),
|
||||||
|
slots.setLayoutHint(LayoutBorderVertical.CENTER),
|
||||||
|
volumeBar.setLayoutHint(LayoutBorderVertical.UP)
|
||||||
|
);
|
||||||
|
|
||||||
|
addChild(slotsAndVolumeBar.setLayoutHint(LayoutBorderHorizontal.CENTER));
|
||||||
|
addChild(massBar.setLayoutHint(LayoutBorderHorizontal.LEFT));
|
||||||
|
|
||||||
|
onSlotChanged(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSlot(int index) {
|
||||||
|
final int maxX = tmp__getSlotsPerRow();
|
||||||
|
|
||||||
|
InteractiveSlotComponent component = new InteractiveSlotComponent("Inventory.Slot." + index, container, index, workspace);
|
||||||
|
|
||||||
|
Vec2i pos = new Vec2i(index % maxX, index / maxX);
|
||||||
|
slots.addChild(component.setLayoutHint(pos));
|
||||||
|
slotCollection.add(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeSlot(int index) {
|
||||||
|
slots.removeChild(slotCollection.remove(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemContainer getContainer() {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<InteractiveSlotComponent> getSlots() {
|
||||||
|
return slotCollection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onSlotChanged(ItemSlotChangedEvent e) {
|
||||||
|
if (e != null && e.getContainer() != container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int wantSlots = container.getLastFilledSlot();
|
||||||
|
int slotsPerRow = tmp__getSlotsPerRow();
|
||||||
|
|
||||||
|
wantSlots = (wantSlots / slotsPerRow + 2) * slotsPerRow;
|
||||||
|
if (wantSlots < slotsPerRow) {
|
||||||
|
wantSlots = slotsPerRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (wantSlots > slotCollection.size()) {
|
||||||
|
addSlot(slotCollection.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (wantSlots < slotCollection.size()) {
|
||||||
|
removeSlot(slotCollection.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
|
||||||
|
public abstract class InventoryComponent extends Component {
|
||||||
|
|
||||||
|
public InventoryComponent(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Inventory getInventory();
|
||||||
|
|
||||||
|
public abstract Collection<? extends ContainerComponent> getContainers();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainer;
|
||||||
|
|
||||||
|
public class InventoryComponentSimple extends InventoryComponent {
|
||||||
|
|
||||||
|
private final Inventory inventory;
|
||||||
|
private final Collection<ContainerComponentSimple> containers = new ArrayList<>();
|
||||||
|
|
||||||
|
public InventoryComponentSimple(String name, Inventory inventory, HUDWorkspace workspace) {
|
||||||
|
super(name);
|
||||||
|
setLayout(new LayoutFill());
|
||||||
|
this.inventory = inventory;
|
||||||
|
|
||||||
|
for (ItemContainer container : inventory.getContainers()) {
|
||||||
|
ContainerComponentSimple component = new ContainerComponentSimple(container, workspace);
|
||||||
|
containers.add(component);
|
||||||
|
addChild(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Inventory getInventory() {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<? extends ContainerComponent> getContainers() {
|
||||||
|
return containers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.client.graphics.world.hud.HUDWorkspace;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.Inventory;
|
||||||
|
|
||||||
|
public abstract class InventoryRender extends Namespaced {
|
||||||
|
|
||||||
|
public InventoryRender(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract InventoryComponent createComponent(Inventory inventory, HUDWorkspace workspace);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.client.world.item.inventory;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
|
||||||
|
|
||||||
|
public class InventoryRenderRegistry extends NamespacedInstanceRegistry<InventoryRender> {
|
||||||
|
|
||||||
|
private static final InventoryRenderRegistry INSTANCE = new InventoryRenderRegistry();
|
||||||
|
|
||||||
|
public static InventoryRenderRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -114,7 +114,8 @@ public class TileRenderCross extends TileRender implements TileOptimizedCustom {
|
|||||||
origin,
|
origin,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
false
|
false,
|
||||||
|
new Vec3(0, 0, 1)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
output.accept(
|
output.accept(
|
||||||
@ -125,7 +126,8 @@ public class TileRenderCross extends TileRender implements TileOptimizedCustom {
|
|||||||
origin,
|
origin,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
true
|
true,
|
||||||
|
new Vec3(0, 0, 1)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,8 @@ public class Units {
|
|||||||
|
|
||||||
// Volume
|
// Volume
|
||||||
public static final float CUBIC_CENTIMETERS = CENTIMETERS * CENTIMETERS * CENTIMETERS;
|
public static final float CUBIC_CENTIMETERS = CENTIMETERS * CENTIMETERS * CENTIMETERS;
|
||||||
|
@RegisteredUnit("L")
|
||||||
|
public static final float LITERS = (10 * CENTIMETERS) * (10 * CENTIMETERS) * (10 * CENTIMETERS);
|
||||||
public static final float CUBIC_METERS = METERS * METERS * METERS;
|
public static final float CUBIC_METERS = METERS * METERS * METERS;
|
||||||
public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS;
|
public static final float CUBIC_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS;
|
||||||
public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS;
|
public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS;
|
||||||
|
@ -105,6 +105,9 @@ public class Collider {
|
|||||||
// For every pair of colls
|
// For every pair of colls
|
||||||
for (int i = 0; i < colls.size(); ++i) {
|
for (int i = 0; i < colls.size(); ++i) {
|
||||||
Collideable a = colls.get(i);
|
Collideable a = colls.get(i);
|
||||||
|
if (a.getCollisionModel() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
tuneWorldCollisionHelper(a, tickLength, world, workspace);
|
tuneWorldCollisionHelper(a, tickLength, world, workspace);
|
||||||
|
|
||||||
@ -115,6 +118,10 @@ public class Collider {
|
|||||||
|
|
||||||
for (int j = i + 1; j < colls.size(); ++j) {
|
for (int j = i + 1; j < colls.size(); ++j) {
|
||||||
Collideable b = colls.get(j);
|
Collideable b = colls.get(j);
|
||||||
|
if (b.getCollisionModel() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Collision collision = getCollision(a, b, tickLength, workspace);
|
Collision collision = getCollision(a, b, tickLength, workspace);
|
||||||
result = workspace.updateLatestCollision(result, collision);
|
result = workspace.updateLatestCollision(result, collision);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ru.windcorp.progressia.common.state;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class BooleanStateField extends StateField {
|
||||||
|
|
||||||
|
public BooleanStateField(
|
||||||
|
String id,
|
||||||
|
boolean isLocal,
|
||||||
|
int index
|
||||||
|
) {
|
||||||
|
super(id, isLocal, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean get(StatefulObject object) {
|
||||||
|
return object.getStorage().getBoolean(getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNow(StatefulObject object, boolean value) {
|
||||||
|
object.getStorage().setBoolean(getIndex(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(StateChanger changer, boolean value) {
|
||||||
|
changer.setBoolean(this, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(
|
||||||
|
StatefulObject object,
|
||||||
|
DataInput input,
|
||||||
|
IOContext context
|
||||||
|
)
|
||||||
|
throws IOException {
|
||||||
|
object.getStorage().setBoolean(getIndex(), input.readBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(
|
||||||
|
StatefulObject object,
|
||||||
|
DataOutput output,
|
||||||
|
IOContext context
|
||||||
|
)
|
||||||
|
throws IOException {
|
||||||
|
output.writeBoolean(object.getStorage().getBoolean(getIndex()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(StatefulObject from, StatefulObject to) {
|
||||||
|
setNow(to, get(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int computeHashCode(StatefulObject object) {
|
||||||
|
return Boolean.hashCode(get(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areEqual(StatefulObject a, StatefulObject b) {
|
||||||
|
return get(a) == get(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDefault(StateStorage storage) {
|
||||||
|
storage.setBoolean(getIndex(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,10 +22,13 @@ import gnu.trove.map.TIntIntMap;
|
|||||||
import gnu.trove.map.TIntObjectMap;
|
import gnu.trove.map.TIntObjectMap;
|
||||||
import gnu.trove.map.hash.TIntIntHashMap;
|
import gnu.trove.map.hash.TIntIntHashMap;
|
||||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||||
|
import gnu.trove.set.TIntSet;
|
||||||
|
import gnu.trove.set.hash.TIntHashSet;
|
||||||
|
|
||||||
public class HashMapStateStorage extends StateStorage {
|
public class HashMapStateStorage extends StateStorage {
|
||||||
|
|
||||||
private final TIntIntMap ints = new TIntIntHashMap();
|
private final TIntIntMap ints = new TIntIntHashMap();
|
||||||
|
private final TIntSet booleans = new TIntHashSet();
|
||||||
private final TIntObjectMap<Object> objects = new TIntObjectHashMap<>();
|
private final TIntObjectMap<Object> objects = new TIntObjectHashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -38,6 +41,20 @@ public class HashMapStateStorage extends StateStorage {
|
|||||||
ints.put(index, value);
|
ints.put(index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean(int index) {
|
||||||
|
return booleans.contains(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBoolean(int index, boolean value) {
|
||||||
|
if (value) {
|
||||||
|
booleans.add(index);
|
||||||
|
} else {
|
||||||
|
booleans.remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject(int index) {
|
public Object getObject(int index) {
|
||||||
return objects.get(index);
|
return objects.get(index);
|
||||||
|
@ -85,6 +85,21 @@ public class InspectingStatefulObjectLayout
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class Boolean implements StateFieldBuilder.Boolean {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BooleanStateField build() {
|
||||||
|
return registerField(
|
||||||
|
new BooleanStateField(
|
||||||
|
id,
|
||||||
|
isLocal,
|
||||||
|
fieldIndexCounters.getBooleansThenIncrement()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private class Obj<T> implements StateFieldBuilder.Obj<T> {
|
private class Obj<T> implements StateFieldBuilder.Obj<T> {
|
||||||
|
|
||||||
private final ObjectCodec<T> codec;
|
private final ObjectCodec<T> codec;
|
||||||
@ -123,6 +138,11 @@ public class InspectingStatefulObjectLayout
|
|||||||
return new Int();
|
return new Int();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean ofBoolean() {
|
||||||
|
return new Boolean();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
||||||
return new Obj<T>(codec, defaultValue);
|
return new Obj<T>(codec, defaultValue);
|
||||||
|
@ -21,11 +21,13 @@ package ru.windcorp.progressia.common.state;
|
|||||||
public class OptimizedStateStorage extends StateStorage {
|
public class OptimizedStateStorage extends StateStorage {
|
||||||
|
|
||||||
private final int[] ints;
|
private final int[] ints;
|
||||||
|
private final boolean[] booleans;
|
||||||
private final Object[] objects;
|
private final Object[] objects;
|
||||||
|
|
||||||
public OptimizedStateStorage(PrimitiveCounters sizes) {
|
public OptimizedStateStorage(PrimitiveCounters sizes) {
|
||||||
this.ints = new int[sizes.getInts()];
|
this.ints = sizes.getInts() == 0 ? null : new int[sizes.getInts()];
|
||||||
this.objects = new Object[sizes.getObjects()];
|
this.booleans = sizes.getBooleans() == 0 ? null : new boolean[sizes.getBooleans()];
|
||||||
|
this.objects = sizes.getObjects() == 0 ? null : new Object[sizes.getObjects()];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -38,6 +40,16 @@ public class OptimizedStateStorage extends StateStorage {
|
|||||||
ints[index] = value;
|
ints[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean(int index) {
|
||||||
|
return booleans[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBoolean(int index, boolean value) {
|
||||||
|
booleans[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getObject(int index) {
|
public Object getObject(int index) {
|
||||||
return objects[index];
|
return objects[index];
|
||||||
|
@ -75,6 +75,16 @@ public class OptimizedStatefulObjectLayout
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean ofBoolean() {
|
||||||
|
return new Boolean() {
|
||||||
|
@Override
|
||||||
|
public BooleanStateField build() {
|
||||||
|
return (BooleanStateField) result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
||||||
return new Obj<T>() {
|
return new Obj<T>() {
|
||||||
|
@ -21,6 +21,7 @@ package ru.windcorp.progressia.common.state;
|
|||||||
class PrimitiveCounters {
|
class PrimitiveCounters {
|
||||||
|
|
||||||
private int ints = 0;
|
private int ints = 0;
|
||||||
|
private int booleans = 0;
|
||||||
private int objects = 0;
|
private int objects = 0;
|
||||||
|
|
||||||
public PrimitiveCounters() {
|
public PrimitiveCounters() {
|
||||||
@ -28,6 +29,7 @@ class PrimitiveCounters {
|
|||||||
|
|
||||||
public PrimitiveCounters(PrimitiveCounters copyFrom) {
|
public PrimitiveCounters(PrimitiveCounters copyFrom) {
|
||||||
this.ints = copyFrom.ints;
|
this.ints = copyFrom.ints;
|
||||||
|
this.booleans = copyFrom.booleans;
|
||||||
this.objects = copyFrom.objects;
|
this.objects = copyFrom.objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +41,14 @@ class PrimitiveCounters {
|
|||||||
return this.ints++;
|
return this.ints++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getBooleans() {
|
||||||
|
return booleans;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBooleansThenIncrement() {
|
||||||
|
return this.booleans++;
|
||||||
|
}
|
||||||
|
|
||||||
public int getObjects() {
|
public int getObjects() {
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package ru.windcorp.progressia.common.state;
|
|||||||
public interface StateChanger {
|
public interface StateChanger {
|
||||||
|
|
||||||
void setInt(IntStateField field, int value);
|
void setInt(IntStateField field, int value);
|
||||||
|
void setBoolean(BooleanStateField field, boolean value);
|
||||||
<T> void setObject(ObjectStateField<T> field, T value);
|
<T> void setObject(ObjectStateField<T> field, T value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,18 @@ public interface StateFieldBuilder {
|
|||||||
IntStateField build();
|
IntStateField build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface Boolean {
|
||||||
|
BooleanStateField build();
|
||||||
|
}
|
||||||
|
|
||||||
public static interface Obj<T> {
|
public static interface Obj<T> {
|
||||||
ObjectStateField<T> build();
|
ObjectStateField<T> build();
|
||||||
}
|
}
|
||||||
|
|
||||||
Int ofInt();
|
Int ofInt();
|
||||||
|
|
||||||
|
Boolean ofBoolean();
|
||||||
|
|
||||||
<T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue);
|
<T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue);
|
||||||
|
|
||||||
default <T> Obj<T> of(Class<T> clazz, Supplier<T> defaultValue) {
|
default <T> Obj<T> of(Class<T> clazz, Supplier<T> defaultValue) {
|
||||||
|
@ -24,6 +24,10 @@ public abstract class StateStorage {
|
|||||||
|
|
||||||
public abstract void setInt(int index, int value);
|
public abstract void setInt(int index, int value);
|
||||||
|
|
||||||
|
public abstract boolean getBoolean(int index);
|
||||||
|
|
||||||
|
public abstract void setBoolean(int index, boolean value);
|
||||||
|
|
||||||
public abstract Object getObject(int index);
|
public abstract Object getObject(int index);
|
||||||
|
|
||||||
public abstract void setObject(int index, Object object);
|
public abstract void setObject(int index, Object object);
|
||||||
|
@ -235,7 +235,7 @@ public abstract class StatefulObject extends Namespaced implements Encodable {
|
|||||||
|
|
||||||
StatefulObject statefulObj = (StatefulObject) obj;
|
StatefulObject statefulObj = (StatefulObject) obj;
|
||||||
|
|
||||||
if (statefulObj.getId().equals(this.getId()))
|
if (!statefulObj.getId().equals(this.getId()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -42,6 +42,16 @@ public class StatefulObjectRegistry<T extends StatefulObject> {
|
|||||||
*/
|
*/
|
||||||
T build();
|
T build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public static interface IdFactory<T> {
|
||||||
|
/**
|
||||||
|
* Initializes a new, independent instance of the stateful object.
|
||||||
|
*
|
||||||
|
* @return the created object
|
||||||
|
*/
|
||||||
|
T build(String id);
|
||||||
|
}
|
||||||
|
|
||||||
protected static class Type<T> extends Namespaced {
|
protected static class Type<T> extends Namespaced {
|
||||||
|
|
||||||
@ -110,5 +120,9 @@ public class StatefulObjectRegistry<T extends StatefulObject> {
|
|||||||
public void register(String id, Factory<T> factory) {
|
public void register(String id, Factory<T> factory) {
|
||||||
registry.register(new Type<>(id, factory));
|
registry.register(new Type<>(id, factory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void register(String id, IdFactory<T> factory) {
|
||||||
|
register(id, () -> factory.build(id));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -379,5 +379,15 @@ public class EntityData extends StatefulObject implements Collideable, EntityGen
|
|||||||
|
|
||||||
super.read(input, context);
|
super.read(input, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return this == obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Long.hashCode(entityId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.entity;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.IntStateField;
|
||||||
|
import ru.windcorp.progressia.common.state.ObjectStateField;
|
||||||
|
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.InventoryUser;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerEquipment;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerHand;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryClosingEvent;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.event.InventoryOpenedEvent;
|
||||||
|
|
||||||
|
public class EntityDataPlayer extends EntityData implements InventoryUser {
|
||||||
|
|
||||||
|
private final ObjectStateField<SpeciesDatalet> speciesDatalet = field("Core:SpeciesDatalet").setShared()
|
||||||
|
.of(SpeciesDataRegistry.getInstance().getCodec()).build();
|
||||||
|
|
||||||
|
private final IntStateField selectedHand = field("Core:SelectedHand").setShared().ofInt().build();
|
||||||
|
|
||||||
|
private final EventBus eventBus = ReportingEventBus.create("EntityDataPlayer");
|
||||||
|
|
||||||
|
public EntityDataPlayer(String id, SpeciesData species) {
|
||||||
|
super(id);
|
||||||
|
|
||||||
|
setSpecies(species);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSpecies(SpeciesData species) {
|
||||||
|
speciesDatalet.setNow(this, species.createDatalet());
|
||||||
|
setCollisionModel(species.getCollisionModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeciesData getSpecies() {
|
||||||
|
return speciesDatalet.get(this).getSpecies();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemContainerHand getHand(int index) {
|
||||||
|
return speciesDatalet.get(this).getHands()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHandCount() {
|
||||||
|
return speciesDatalet.get(this).getHands().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemContainerEquipment getEquipmentSlot(int index) {
|
||||||
|
return speciesDatalet.get(this).getEquipment()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEquipmentCount() {
|
||||||
|
return speciesDatalet.get(this).getEquipment().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSelectedHandIndex() {
|
||||||
|
return selectedHand.get(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedHandIndexNow(int index) {
|
||||||
|
selectedHand.setNow(this, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemContainerHand getSelectedHand() {
|
||||||
|
return getHand(getSelectedHandIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onInventoryOpened(InventoryOpenedEvent event) {
|
||||||
|
eventBus.post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onInventoryClosed(InventoryClosingEvent event) {
|
||||||
|
eventBus.post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribe(Object listener) {
|
||||||
|
eventBus.register(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(Object listener) {
|
||||||
|
eventBus.unregister(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.entity;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.IOContext;
|
||||||
|
import ru.windcorp.progressia.common.state.codec.ObjectCodec;
|
||||||
|
|
||||||
|
public class SpeciesCodec extends ObjectCodec<SpeciesDatalet> {
|
||||||
|
|
||||||
|
public SpeciesCodec() {
|
||||||
|
super(SpeciesDatalet.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SpeciesDatalet doRead(SpeciesDatalet previous, DataInput input, IOContext context) throws IOException {
|
||||||
|
String id = input.readUTF();
|
||||||
|
|
||||||
|
SpeciesDatalet result = previous;
|
||||||
|
|
||||||
|
if (result == null || !result.getSpecies().getId().equals(id)) {
|
||||||
|
SpeciesData species = SpeciesDataRegistry.getInstance().get(id);
|
||||||
|
if (species == null) {
|
||||||
|
throw new IOException("Unknown species ID " + species);
|
||||||
|
}
|
||||||
|
result = species.createDatalet();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.read(input, context);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWrite(SpeciesDatalet obj, DataOutput output, IOContext context) throws IOException {
|
||||||
|
output.writeUTF(obj.getSpecies().getId());
|
||||||
|
obj.write(output, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpeciesDatalet copy(SpeciesDatalet object, SpeciesDatalet previous) {
|
||||||
|
SpeciesDatalet result = previous;
|
||||||
|
|
||||||
|
if (result == null || result.getSpecies() != object.getSpecies()) {
|
||||||
|
result = object.getSpecies().createDatalet();
|
||||||
|
}
|
||||||
|
|
||||||
|
object.copy(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.entity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.collision.CollisionModel;
|
||||||
|
import ru.windcorp.progressia.common.util.Named;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
|
||||||
|
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||||
|
|
||||||
|
public abstract class SpeciesData extends Namespaced {
|
||||||
|
|
||||||
|
public static class Hand extends Named {
|
||||||
|
|
||||||
|
private int index = -1;
|
||||||
|
|
||||||
|
public Hand(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EquipmentSlot extends Named {
|
||||||
|
|
||||||
|
private int index = -1;
|
||||||
|
|
||||||
|
private Predicate<ItemData> filter;
|
||||||
|
|
||||||
|
public EquipmentSlot(String name, Predicate<ItemData> filter) {
|
||||||
|
super(name);
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Predicate<ItemData> getFilter() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Hand> hands;
|
||||||
|
private List<EquipmentSlot> equipmentSlots;
|
||||||
|
|
||||||
|
public SpeciesData(String id) {
|
||||||
|
super(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void withHands(Hand... hands) {
|
||||||
|
if (this.hands != null) {
|
||||||
|
throw new IllegalStateException("Hands already set");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hands.length == 0) {
|
||||||
|
throw new IllegalArgumentException("At least one hand required");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hands = ImmutableList.copyOf(hands);
|
||||||
|
|
||||||
|
for (int i = 0; i < hands.length; ++i) {
|
||||||
|
hands[i].index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void withEquipmentSlots(EquipmentSlot... equipmentSlots) {
|
||||||
|
if (this.equipmentSlots != null) {
|
||||||
|
throw new IllegalStateException("Equipment slots already set");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.equipmentSlots = ImmutableList.copyOf(equipmentSlots);
|
||||||
|
|
||||||
|
for (int i = 0; i < equipmentSlots.length; ++i) {
|
||||||
|
equipmentSlots[i].index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Hand> getHands() {
|
||||||
|
return hands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EquipmentSlot> getEquipmentSlots() {
|
||||||
|
return equipmentSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract CollisionModel getCollisionModel();
|
||||||
|
|
||||||
|
public SpeciesDatalet createDatalet() {
|
||||||
|
return new SpeciesDatalet(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.entity;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.codec.ObjectCodec;
|
||||||
|
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
|
||||||
|
|
||||||
|
public class SpeciesDataRegistry extends NamespacedInstanceRegistry<SpeciesData> {
|
||||||
|
|
||||||
|
private static final SpeciesDataRegistry INSTANCE = new SpeciesDataRegistry();
|
||||||
|
|
||||||
|
private final ObjectCodec<SpeciesDatalet> codec = new SpeciesCodec();
|
||||||
|
|
||||||
|
public static SpeciesDataRegistry getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectCodec<SpeciesDatalet> getCodec() {
|
||||||
|
return codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.entity;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.Encodable;
|
||||||
|
import ru.windcorp.progressia.common.state.IOContext;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData.EquipmentSlot;
|
||||||
|
import ru.windcorp.progressia.common.world.entity.SpeciesData.Hand;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerEquipment;
|
||||||
|
import ru.windcorp.progressia.common.world.item.inventory.ItemContainerHand;
|
||||||
|
|
||||||
|
public class SpeciesDatalet implements Encodable {
|
||||||
|
|
||||||
|
private final SpeciesData species;
|
||||||
|
|
||||||
|
private final ItemContainerHand[] hands;
|
||||||
|
private final ItemContainerEquipment[] equipment;
|
||||||
|
|
||||||
|
public SpeciesDatalet(SpeciesData species) {
|
||||||
|
this.species = species;
|
||||||
|
|
||||||
|
this.hands = new ItemContainerHand[species.getHands().size()];
|
||||||
|
for (int i = 0; i < hands.length; ++i) {
|
||||||
|
Hand hand = species.getHands().get(i);
|
||||||
|
this.hands[i] = new ItemContainerHand(species.getId() + "Hand" + hand.getName(), hand);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.equipment = new ItemContainerEquipment[species.getEquipmentSlots().size()];
|
||||||
|
for (int i = 0; i < equipment.length; ++i) {
|
||||||
|
EquipmentSlot equipmentSlot = species.getEquipmentSlots().get(i);
|
||||||
|
this.equipment[i] = new ItemContainerEquipment(
|
||||||
|
species.getId() + "EquipmentSlot" + equipmentSlot.getName(),
|
||||||
|
equipmentSlot
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeciesData getSpecies() {
|
||||||
|
return species;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(DataInput input, IOContext context) throws IOException {
|
||||||
|
for (int i = 0; i < hands.length; ++i) {
|
||||||
|
hands[i].read(input, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < equipment.length; ++i) {
|
||||||
|
equipment[i].read(input, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(DataOutput output, IOContext context) throws IOException {
|
||||||
|
for (int i = 0; i < hands.length; ++i) {
|
||||||
|
hands[i].write(output, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < equipment.length; ++i) {
|
||||||
|
equipment[i].write(output, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copy(Encodable destination) {
|
||||||
|
SpeciesDatalet other = (SpeciesDatalet) destination;
|
||||||
|
|
||||||
|
if (other.getSpecies() != getSpecies()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Cannot copy datalet of species " + other.getSpecies() + " into datalet of species " + getSpecies()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < hands.length; ++i) {
|
||||||
|
hands[i].copy(other.hands[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < equipment.length; ++i) {
|
||||||
|
equipment[i].copy(other.equipment[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the hands
|
||||||
|
*/
|
||||||
|
public ItemContainerHand[] getHands() {
|
||||||
|
return hands;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the equipment
|
||||||
|
*/
|
||||||
|
public ItemContainerEquipment[] getEquipment() {
|
||||||
|
return equipment;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.generic;
|
||||||
|
|
||||||
|
public interface ItemGeneric {
|
||||||
|
|
||||||
|
String getId();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Progressia
|
||||||
|
* Copyright (C) 2020-2021 Wind Corporation and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package ru.windcorp.progressia.common.world.item;
|
||||||
|
|
||||||
|
import ru.windcorp.progressia.common.state.StatefulObject;
|
||||||
|
import ru.windcorp.progressia.common.world.generic.ItemGeneric;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item identified by its ID and properties, able to reside in a slot.
|
||||||
|
*/
|
||||||
|
public abstract class ItemData extends StatefulObject implements ItemGeneric {
|
||||||
|
|
||||||
|
public ItemData(String id) {
|
||||||
|
super(ItemDataRegistry.getInstance(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes and returns the mass of a single unit (single item) of this
|
||||||
|
* item.
|
||||||
|
*
|
||||||
|
* @return the mass of this item
|
||||||
|
*/
|
||||||
|
public abstract float getMass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes and returns the volume of a single unit (single item) of this
|
||||||
|
* item stack.
|
||||||
|
*
|
||||||
|
* @return the volume of this item
|
||||||
|
*/
|
||||||
|
public abstract float getVolume();
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user