Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
5472576606 | |||
4a6aa5dbf7 | |||
c3bbc8661d | |||
eadc85bfda | |||
ca8ac6e7b6 | |||
0638794a80 | |||
e6e55a6c40 | |||
57a86b544e | |||
b18eac44b8 | |||
c3c8a6e5e0 | |||
fe01e1b81c | |||
162b2249b1 | |||
dececb4589 | |||
ec17eb7065 | |||
e4d0570200 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -6,4 +6,4 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.bat text eol=crlf
|
||||
|
||||
*.nsi text eol=crlf
|
||||
|
49
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
49
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
name: Bug Report
|
||||
description: Let us know about a problem
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use this template to report identified problems. If the game suddenly crashed, and you need help identifying the cause of a crashreport, please use the Investigate Crashreport template instead.
|
||||
|
||||
**Do not forget to give your issue a descriptive title.**
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
What did you do just before the problem appeared, or where can it be observed?
|
||||
|
||||
If the issue occurs unreliably, please estimate the probability of the crash.
|
||||
placeholder: |
|
||||
1. Look at a cow
|
||||
2. Wait for the cow to look back
|
||||
3. The cow turns away after a minute
|
||||
|
||||
The issue occurs approximately once every 10 attempts.
|
||||
|
||||
Player inventory must be empty. Does not occur in multiplayer. Occurred inside a virtual machine.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behaviour
|
||||
description: |
|
||||
What should happen?
|
||||
placeholder: |
|
||||
The cow should stare back indefinitely, because obviously it should, and because comedy.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Other information
|
||||
description: What else can you tell us about this bug?
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Crashreport
|
||||
description: If you have a relevant crashreport, paste the contents of the crashreport file here
|
||||
render: text
|
||||
validations:
|
||||
required: false
|
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Official Progressia Discord
|
||||
url: https://discord.gg/TWuXbVmX23
|
||||
about: Ask developers or community members for help
|
41
.github/ISSUE_TEMPLATE/crashreport.yml
vendored
Normal file
41
.github/ISSUE_TEMPLATE/crashreport.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
name: Investigate Crashreport
|
||||
description: Submit a crashreport to determine the problem
|
||||
labels: [bug, crashreport]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Use this template to submit crashreports for initial analisys. If you don't have a crashreport, or you have a good understanding of the underlying cause, please use the Bug Report template instead.
|
||||
|
||||
Crashreports can be found in `WORKING-DIRECTORY/crashreports` (take notice of the timestamp). `WORKING-DIRECTORY` is `C:\Users\<windows-user>\AppData\Roaming\Progressia` on Windows when using the installer.
|
||||
|
||||
**Do not forget to give your issue a descriptive title.**
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
What did you do just before the crash? How could someone else reproduce it? What other context might be relevant?
|
||||
|
||||
If the issue occurs unreliably, please estimate the probability of the crash.
|
||||
placeholder: |
|
||||
1. Enter a new world
|
||||
2. Turn around
|
||||
3. Wait 5 minutes
|
||||
4. Game crashes half of the time
|
||||
|
||||
Player inventory must be empty. Does not crash in multiplayer. Occurred inside a virtual machine.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Other information
|
||||
description: What else can you tell us about this crashreport?
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Crashreport
|
||||
description: Paste the contents of the crashreport file here
|
||||
render: text
|
||||
validations:
|
||||
required: true
|
493
build.gradle
493
build.gradle
@ -1,23 +1,29 @@
|
||||
/*
|
||||
* build.gradle for Progressia
|
||||
* Build logic for Progressia
|
||||
* build.gradle
|
||||
*
|
||||
* Please refer to
|
||||
*
|
||||
* docs/building/BuildScriptReference.md
|
||||
*
|
||||
* for user reference.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
// Apply the java-library plugin to add support for Java Library
|
||||
id 'java-library'
|
||||
id 'java'
|
||||
|
||||
/*
|
||||
* Uncomment the following line to enable the Eclipse plugin.
|
||||
* This is only necessary if you don't use Buildship plugin from the IDE
|
||||
*/
|
||||
//id 'eclipse'
|
||||
// GrGit
|
||||
// A JGit wrapper for Groovy used to access git commit info
|
||||
id 'org.ajoberstar.grgit' version '4.1.1'
|
||||
}
|
||||
|
||||
java {
|
||||
/*
|
||||
* We're Java 8 for now.
|
||||
* Why? As of 2020, most users have Oracle Java, which only supports Java 8.
|
||||
|
||||
|
||||
/*
|
||||
* Configure Java version
|
||||
*/
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
@ -34,6 +40,18 @@ compileJava {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Set encoding
|
||||
*/
|
||||
|
||||
compileJava {
|
||||
options.encoding = 'utf8'
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Dependencies
|
||||
*/
|
||||
@ -42,7 +60,7 @@ repositories {
|
||||
mavenCentral()
|
||||
|
||||
/*
|
||||
* Specify Windcorp Maven repository
|
||||
* Windcorp Maven repository
|
||||
* Currently used by:
|
||||
* - ru.windcorp.fork.io.github.java-graphics:glm:1.0.1
|
||||
*/
|
||||
@ -52,7 +70,7 @@ repositories {
|
||||
dependencies {
|
||||
// Google Guava
|
||||
// A generic utilities library
|
||||
implementation 'com.google.guava:guava:30.0-jre'
|
||||
implementation 'com.google.guava:guava:31.0.1-jre'
|
||||
|
||||
// Trove4j
|
||||
// Provides optimized Collections for primitive types
|
||||
@ -65,238 +83,311 @@ dependencies {
|
||||
|
||||
// Log4j
|
||||
// A logging library
|
||||
implementation 'org.apache.logging.log4j:log4j-api:2.17.0'
|
||||
implementation 'org.apache.logging.log4j:log4j-core:2.17.0'
|
||||
implementation 'org.apache.logging.log4j:log4j-api:2.17.1'
|
||||
implementation 'org.apache.logging.log4j:log4j-core:2.17.1'
|
||||
|
||||
// JUnit
|
||||
// A unit-testing library
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
||||
// See LWJGL dependencies below
|
||||
// Also see LWJGL dependencies in build_logic/lwjgl.gradle
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Progressia uses the following LWJGL libraries:
|
||||
* - Core libraries
|
||||
* - OpenGL
|
||||
* - OpenAL
|
||||
* - GLFW
|
||||
* - STB
|
||||
* Version resolution
|
||||
*/
|
||||
|
||||
/*
|
||||
* LWJGL
|
||||
* (auto-generated script)
|
||||
* ((here be dragons))
|
||||
*/
|
||||
import org.ajoberstar.grgit.*
|
||||
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
// Pattern: vMAJOR.MINOR.PATCH[-SUFFIX]
|
||||
project.ext.tagFormat = /^v(\d+)\.(\d+)\.(\d+)(-[\w\-]*)?$/
|
||||
|
||||
project.ext.lwjglVersion = "3.2.3"
|
||||
String version_parseVersion(String tag, boolean increment) {
|
||||
try {
|
||||
|
||||
switch (OperatingSystem.current()) {
|
||||
case OperatingSystem.LINUX:
|
||||
def osArch = System.getProperty("os.arch")
|
||||
project.ext.lwjglNatives = osArch.startsWith("arm") || osArch.startsWith("aarch64")
|
||||
? "natives-linux-${osArch.contains("64") || osArch.startsWith("armv8") ? "arm64" : "arm32"}"
|
||||
: "natives-linux"
|
||||
break
|
||||
case OperatingSystem.MAC_OS:
|
||||
project.ext.lwjglNatives = "natives-macos"
|
||||
break
|
||||
case OperatingSystem.WINDOWS:
|
||||
project.ext.lwjglNatives = System.getProperty("os.arch").contains("64") ? "natives-windows" : "natives-windows-x86"
|
||||
break
|
||||
}
|
||||
def data = (tag =~ tagFormat)[0]
|
||||
|
||||
dependencies {
|
||||
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
|
||||
def major = data[1]
|
||||
def minor = data[2]
|
||||
def patch = data[3] as int
|
||||
def suffix = data[4] ?: ''
|
||||
|
||||
implementation "org.lwjgl:lwjgl"
|
||||
implementation "org.lwjgl:lwjgl-glfw"
|
||||
implementation "org.lwjgl:lwjgl-openal"
|
||||
implementation "org.lwjgl:lwjgl-opengl"
|
||||
implementation "org.lwjgl:lwjgl-stb"
|
||||
if (increment) {
|
||||
def oldVersion = "$major.$minor.$patch$suffix"
|
||||
patch++
|
||||
def newVersion = "$major.$minor.$patch$suffix"
|
||||
|
||||
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
||||
}
|
||||
|
||||
// LWJGL END
|
||||
|
||||
/*
|
||||
* Tasks
|
||||
*/
|
||||
|
||||
/*
|
||||
* Additional native libraries specification
|
||||
*/
|
||||
|
||||
project.ext.platforms = new HashSet<>()
|
||||
|
||||
task addNativeDependencies {
|
||||
doFirst {
|
||||
def archs = project.ext.platforms
|
||||
|
||||
switch (archs.size()) {
|
||||
case 0:
|
||||
println "Adding LWJGL native dependencies for local platform only:\n\t$lwjglNatives"
|
||||
archs.add project.ext.lwjglNatives
|
||||
break
|
||||
case 1:
|
||||
println "Adding LWJGL native dependencies for platform\n\t" + archs.get(0)
|
||||
break
|
||||
default:
|
||||
println "Adding LWJGL native dependencies for platforms:\n\t" + archs.join("\n\t")
|
||||
}
|
||||
|
||||
if (project.ext.lwjglNatives.isEmpty()) println "WTF"
|
||||
|
||||
dependencies {
|
||||
archs.each { arch ->
|
||||
runtimeOnly "org.lwjgl:lwjgl::$arch"
|
||||
runtimeOnly "org.lwjgl:lwjgl-glfw::$arch"
|
||||
runtimeOnly "org.lwjgl:lwjgl-openal::$arch"
|
||||
runtimeOnly "org.lwjgl:lwjgl-opengl::$arch"
|
||||
runtimeOnly "org.lwjgl:lwjgl-stb::$arch"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileJava.mustRunAfter addNativeDependencies // Make sure runtimeOnly has not been resolved
|
||||
|
||||
task requestLinuxDependencies {
|
||||
description 'Adds linux, linux-arm64 and linux-arm32 native libraries to built artifacts.'
|
||||
doFirst {
|
||||
project.ext.platforms.addAll([
|
||||
'natives-linux',
|
||||
'natives-linux-arm64',
|
||||
'natives-linux-arm32'
|
||||
])
|
||||
}
|
||||
}
|
||||
task requestWindowsDependencies {
|
||||
description 'Adds windows and windows-x86 native libraries to built artifacts.'
|
||||
doFirst {
|
||||
project.ext.platforms.addAll([
|
||||
'natives-windows',
|
||||
'natives-windows-x86'
|
||||
])
|
||||
}
|
||||
}
|
||||
task requestMacOSDependencies {
|
||||
description 'Adds macos native libraries to built artifacts.'
|
||||
doFirst {
|
||||
project.ext.platforms.addAll(['natives-macos'])
|
||||
}
|
||||
}
|
||||
|
||||
def dependencySpecificationTasks = tasks.findAll { task -> task.name.startsWith('request') && task.name.endsWith('Dependencies') }
|
||||
|
||||
task requestCrossPlatformDependencies {
|
||||
description 'Adds native libraries for all available platforms to built artifacts.'
|
||||
dependsOn dependencySpecificationTasks
|
||||
}
|
||||
|
||||
addNativeDependencies.mustRunAfter dependencySpecificationTasks
|
||||
|
||||
/*
|
||||
* Determines if the provided dependency should be packaged
|
||||
*/
|
||||
def isDependencyRequested(String dep) {
|
||||
if (dep.endsWith(".jar")) {
|
||||
dep = dep.substring(0, dep.length() - ".jar".length())
|
||||
}
|
||||
|
||||
return !dep.contains("natives-") ||
|
||||
project.ext.platforms.contains(dep.substring(dep.indexOf("natives-"), dep.length()))
|
||||
}
|
||||
|
||||
/*
|
||||
* Manifest specification
|
||||
*/
|
||||
|
||||
task specifyLocalManifest {
|
||||
dependsOn addNativeDependencies // Make sure all native dependencies are specified
|
||||
|
||||
doFirst {
|
||||
def classPath = []
|
||||
|
||||
configurations.runtimeClasspath.each {
|
||||
if (isDependencyRequested(it.getName())) {
|
||||
classPath.add("lib/" + it.getName())
|
||||
logger.info "Version parsed from Git: $oldVersion, incremented to $newVersion"
|
||||
return newVersion
|
||||
} else {
|
||||
println "\tRemoving from JAR classpath (not requested): " + it.getName()
|
||||
}
|
||||
def newVersion = "$major.$minor.$patch$suffix"
|
||||
logger.info "Version parsed from Git: $newVersion"
|
||||
return newVersion
|
||||
}
|
||||
|
||||
if (classPath.size() == configurations.runtimeClasspath.size()) {
|
||||
println "Nothing removed from JAR classpath"
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes(
|
||||
"Main-Class": "ru.windcorp.progressia.client.ProgressiaClientMain",
|
||||
"Class-Path": configurations.runtimeClasspath.collect { "lib/" + it.getName() } .findAll { isDependencyRequested(it) } .join(' ')
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (any) {
|
||||
logger.warn "Could not parse version from tag \"$tag\""
|
||||
return tag
|
||||
}
|
||||
}
|
||||
|
||||
jar.dependsOn specifyLocalManifest
|
||||
Tag version_findRelevantTag(Grgit git) {
|
||||
def tags = git.tag.list()
|
||||
|
||||
def commits = [ git.head() ]
|
||||
def visited = new HashSet<>()
|
||||
|
||||
while (true) {
|
||||
if (commits.isEmpty()) return null
|
||||
|
||||
def nextCommits = new HashSet<>()
|
||||
|
||||
def formatSpecificationPrinted = false
|
||||
for (def commit : commits) {
|
||||
def tag = tags.findAll { it.commit == commit } ?.max { it.dateTime }
|
||||
|
||||
if (tag != null) {
|
||||
if (tag.name ==~ tagFormat) {
|
||||
return tag
|
||||
} else {
|
||||
if (!formatSpecificationPrinted) {
|
||||
formatSpecificationPrinted = true
|
||||
logger.info 'Expecting tag format: vMAJOR.MINOR.PATCH[-SUFFIX]'
|
||||
}
|
||||
logger.info 'Ignoring tag due to invalid format: {}', tag.name
|
||||
}
|
||||
}
|
||||
|
||||
nextCommits.addAll commit.parentIds.collect(git.resolve.&toCommit)
|
||||
}
|
||||
|
||||
visited.addAll commits
|
||||
nextCommits.removeAll visited
|
||||
commits = nextCommits
|
||||
}
|
||||
}
|
||||
|
||||
task resolveVersion {
|
||||
description 'Resolves version information from Git repository or project properties.'
|
||||
|
||||
doFirst {
|
||||
|
||||
project.ext.commit = System.env.GIT_COMMIT
|
||||
project.ext.branch = System.env.GIT_BRANCH
|
||||
|
||||
try {
|
||||
def git = Grgit.open(dir: project.projectDir)
|
||||
|
||||
project.ext.commit = commit ?: git.head().id
|
||||
project.ext.branch = branch ?: git.branch.current().name
|
||||
|
||||
if (project.version != 'unspecified') {
|
||||
// Leave version as-is
|
||||
} else {
|
||||
|
||||
// Resolve version from Git
|
||||
def tag = version_findRelevantTag(git)
|
||||
if (tag == null) {
|
||||
|
||||
String suffix
|
||||
if (project.hasProperty('buildId')) {
|
||||
suffix = project.buildId;
|
||||
} else {
|
||||
suffix = java.time.ZonedDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern('yyyy_MM_dd'))
|
||||
}
|
||||
project.version = "999.0.0-$suffix"
|
||||
|
||||
logger.warn 'Git repository does not contain an applicable tag, using dummy version {}\nSpecify version with -Pversion=1.2.3 or create a Git tag named v1.2.3', project.version
|
||||
|
||||
} else {
|
||||
|
||||
project.version = version_parseVersion(tag.name, tag.commit != git.head())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} catch (org.eclipse.jgit.errors.RepositoryNotFoundException e) {
|
||||
if (project.version == 'unspecified') project.version = 'dev'
|
||||
project.ext.commit = commit ?: '-'
|
||||
project.ext.branch = branch ?: '-'
|
||||
|
||||
logger.warn 'No Git repository found in project root, using dummy version {}\nSpecify version with -Pversion=1.2.3 or create a Git tag named v1.2.3', project.version
|
||||
}
|
||||
|
||||
if (branch.contains '/') {
|
||||
// Strip remote - no one wants that
|
||||
project.ext.branch = branch.takeAfter '/'
|
||||
}
|
||||
|
||||
if (!project.hasProperty('buildId')) {
|
||||
project.ext.buildId = '-'
|
||||
}
|
||||
}
|
||||
|
||||
doLast {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Library export
|
||||
* Apply LWJGL logic
|
||||
*/
|
||||
apply from: 'build_logic/lwjgl.gradle'
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Copy libraries into build/libs/lib directory, next to Progressia.jar
|
||||
*/
|
||||
|
||||
task exportLibs(type: Sync) {
|
||||
mustRunAfter addNativeDependencies
|
||||
description 'Copies runtime libraries into a subdirectory next to the output JAR.'
|
||||
|
||||
into libsDirectory.get().getAsFile().getPath() + "/lib"
|
||||
exclude { !isDependencyRequested(it.getName()) }
|
||||
from configurations.runtimeClasspath
|
||||
jar.dependsOn exportLibs
|
||||
dependsOn lwjgl_addNativesToRuntimeOnly
|
||||
|
||||
// from defined in configureManifest
|
||||
into 'build/libs/lib'
|
||||
}
|
||||
|
||||
jar.dependsOn(exportLibs)
|
||||
|
||||
|
||||
/*
|
||||
* Packaging
|
||||
* Configure JAR manifest
|
||||
*/
|
||||
|
||||
task packageDebian(type: Exec) {
|
||||
description 'Builds the project and creates a Debain package.'
|
||||
group 'Progressia'
|
||||
task configureManifest {
|
||||
description 'Populates JAR manifest with Main-Class, Class-Path and version metadata.'
|
||||
|
||||
dependsOn build
|
||||
dependsOn requestLinuxDependencies
|
||||
jar.dependsOn configureManifest
|
||||
dependsOn resolveVersion
|
||||
dependsOn lwjgl_addNativesToRuntimeOnly
|
||||
|
||||
commandLine './buildPackages.sh', 'debian'
|
||||
doFirst {
|
||||
def classPath = project.lwjgl.replaceNativesIn(configurations.runtimeClasspath)
|
||||
|
||||
doLast {
|
||||
println "Debian package available in build_packages/"
|
||||
exportLibs.from classPath
|
||||
|
||||
jar.manifest.attributes(
|
||||
'Main-Class': 'ru.windcorp.progressia.client.ProgressiaClientMain',
|
||||
'Class-Path': classPath.collect { "lib/${java.net.URLEncoder.encode it.name}" } .join(' '),
|
||||
|
||||
'Specification-Title': 'Progressia',
|
||||
|
||||
'Implementation-Title': 'Progressia',
|
||||
'Implementation-Version': project.version,
|
||||
'Implementation-Version-Git-Commit': project.commit,
|
||||
'Implementation-Version-Git-Branch': project.branch,
|
||||
'Implementation-Version-BuildId': project.buildId,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
task packageWindows(type: Exec) {
|
||||
description 'Builds the project and creates a Windows installer.'
|
||||
group 'Progressia'
|
||||
|
||||
|
||||
/*
|
||||
* Packaging working directory configuration
|
||||
*/
|
||||
|
||||
import java.nio.file.*
|
||||
import java.nio.file.attribute.*
|
||||
|
||||
task deletePackagingDirs(type: Delete) {
|
||||
description 'Deletes build/tmp/packaging directory.'
|
||||
followSymlinks = false
|
||||
delete 'build/tmp/packaging'
|
||||
}
|
||||
|
||||
task linkBuildOutputForPackaging {
|
||||
description 'Symlinks the contents of build/libs into packaging working directory.'
|
||||
|
||||
dependsOn build
|
||||
dependsOn requestWindowsDependencies
|
||||
mustRunAfter deletePackagingDirs
|
||||
|
||||
commandLine './buildPackages.sh', 'windows'
|
||||
onlyIf { preparePackaging.ext.mode == 'symlink' }
|
||||
|
||||
ext.from = 'build/libs'
|
||||
ext.into = "build/tmp/packaging/workingDir/${ -> preparePackaging.ext.buildDest}"
|
||||
|
||||
inputs.dir from
|
||||
outputs.dir into
|
||||
|
||||
doLast {
|
||||
println "Windows installer available in build_packages/"
|
||||
def fromPath = Paths.get from
|
||||
def intoPath = Paths.get into
|
||||
|
||||
Files.createDirectories intoPath
|
||||
|
||||
Files.list(fromPath).each {
|
||||
def fileName = it.fileName.toString()
|
||||
|
||||
// Exclude all JARs except the current one
|
||||
if (fileName ==~ "${project.name}.*\\.jar" && fileName != tasks.jar.archiveFileName.get())
|
||||
return
|
||||
|
||||
Files.createSymbolicLink intoPath.resolve(it.fileName), intoPath.relativize(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task copyBuildOutputForPackaging(type: Copy) {
|
||||
description 'Copies the contents of build/libs into packaging working directory.'
|
||||
|
||||
dependsOn build
|
||||
mustRunAfter deletePackagingDirs
|
||||
|
||||
onlyIf { preparePackaging.ext.mode == 'copy' }
|
||||
|
||||
from 'build/libs'
|
||||
filesMatching("${project.name}*.jar") {
|
||||
include tasks.jar.archiveFileName.get()
|
||||
}
|
||||
into "build/tmp/packaging/workingDir/${ -> preparePackaging.ext.buildDest}"
|
||||
}
|
||||
|
||||
task preparePackaging {
|
||||
preparePackaging.ext.buildDest = ''
|
||||
preparePackaging.ext.mode = 'symlink'
|
||||
|
||||
dependsOn deletePackagingDirs
|
||||
dependsOn linkBuildOutputForPackaging
|
||||
dependsOn copyBuildOutputForPackaging
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Apply all packaging scripts
|
||||
*/
|
||||
|
||||
new File(projectDir, 'build_logic/packaging').list().each {
|
||||
apply from: "build_logic/packaging/$it/script.gradle"
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Ensure no more than one packaging task is scheduled
|
||||
*/
|
||||
|
||||
gradle.taskGraph.whenReady { graph ->
|
||||
if (graph.allTasks.count { it.name ==~ /package[^_]*/ } > 1) {
|
||||
def offenders = graph.allTasks.findAll { it.name ==~ /package[^_]*/ }
|
||||
throw new GradleException("Cannot execute multiple package tasks within a single build\n" +
|
||||
"\tOffending tasks: $offenders")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Convenience build tasks
|
||||
*/
|
||||
|
||||
task buildCrossPlatform {
|
||||
description 'Builds the project including native libraries for all available platforms.'
|
||||
group 'Progressia'
|
||||
@ -305,17 +396,17 @@ task buildCrossPlatform {
|
||||
dependsOn build
|
||||
|
||||
doLast {
|
||||
println "Native libraries for all platforms have been added"
|
||||
logger.info 'Native libraries for all platforms have been added'
|
||||
}
|
||||
}
|
||||
|
||||
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 (${lwjgl.localArch})."
|
||||
group 'Progressia'
|
||||
|
||||
dependsOn build
|
||||
|
||||
doLast {
|
||||
println "Native libraries only for platform $lwjglNatives have been added"
|
||||
logger.info "Native libraries only for platform ${lwjgl.localArch} have been added"
|
||||
}
|
||||
}
|
||||
|
191
buildPackages.sh
191
buildPackages.sh
@ -1,191 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
|
||||
echoerr() { echo "$@" 1>&2; }
|
||||
|
||||
buildDebianPackage() {
|
||||
|
||||
# Commands that must be available to execute this action
|
||||
requiredCommands='dpkg-deb fakeroot'
|
||||
|
||||
# Package name. Sync with control file manually!
|
||||
name='progressia-techdemo'
|
||||
# Version that the package will receive. Sync with control file manually!
|
||||
version='1.0_all'
|
||||
|
||||
# This directory will be copied into $tmpDir
|
||||
templateDirectory="build_packages/DEB/template"
|
||||
|
||||
# Files that must be present
|
||||
requiredFiles="$templateDirectory/DEBIAN/control"
|
||||
|
||||
nameAndVersion="$name-$version"
|
||||
tmpDir="build_packages/DEB/$nameAndVersion"
|
||||
outputFile="build_packages/DEB/$nameAndVersion.deb"
|
||||
|
||||
echo "Checking environment to build Debian package"
|
||||
|
||||
for item in $requiredCommands; do
|
||||
if command -v "$item" &> /dev/null; then
|
||||
echo "- $item found"
|
||||
else
|
||||
echoerr "Command $item not found, cannot package"
|
||||
exit 100
|
||||
fi
|
||||
done
|
||||
|
||||
for file in $requiredFiles; do
|
||||
if ! [ -r "$file" ]; then
|
||||
echoerr "$file is missing or not readable, cannot package"
|
||||
exit 101
|
||||
else
|
||||
echo "- $file is present and readable"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Environment OK; packaging Debian package"
|
||||
exitCode=0
|
||||
|
||||
{
|
||||
shareDir="$tmpDir/usr/share/progressia"
|
||||
|
||||
mkdir -p "$tmpDir" &&
|
||||
mkdir -p "$shareDir" &&
|
||||
cp -r "$templateDirectory"/* "$tmpDir" &&
|
||||
cp -r 'build/libs/lib' "$shareDir/lib" &&
|
||||
cp 'build/libs/Progressia.jar' "$shareDir/Progressia.jar" &&
|
||||
echo "------ DPKG-DEB ------" &&
|
||||
fakeroot dpkg-deb --build "$tmpDir" &&
|
||||
echo "---- DPKG-DEB END ----" &&
|
||||
mv "$outputFile" build_packages
|
||||
} || {
|
||||
echoerr "Could not create Debian package"
|
||||
exitCode=1
|
||||
}
|
||||
|
||||
{
|
||||
if [ -d "$tmpDir" ]; then
|
||||
rm -r "$tmpDir"
|
||||
fi
|
||||
echo "Cleaned up"
|
||||
} || {
|
||||
echoerr "Could not clean up after packaging Debian package"
|
||||
exitCode=2
|
||||
}
|
||||
|
||||
exit "$exitCode"
|
||||
}
|
||||
|
||||
buildWindowsInstaller() {
|
||||
|
||||
# Commands that must be available to execute this action
|
||||
requiredCommands='makensis'
|
||||
|
||||
# NSIS configuration file that must be present
|
||||
configurationFile='build_packages/NSIS/ProgressiaInstaller.nsi'
|
||||
|
||||
# File that will be output
|
||||
outputFile='build_packages/NSIS/ProgressiaInstaller.exe'
|
||||
|
||||
echo "Checking environment to build Windows installer"
|
||||
|
||||
for item in $requiredCommands; do
|
||||
if command -v "$item" &> /dev/null; then
|
||||
echo "- $item found"
|
||||
else
|
||||
echoerr "Command $item not found, cannot build"
|
||||
exit 100
|
||||
fi
|
||||
done
|
||||
|
||||
if ! [ -r "$configurationFile" ]; then
|
||||
echoerr "$configurationFile is missing or not readable, cannot build"
|
||||
exit 101
|
||||
else
|
||||
echo "- $configurationFile is present and readable"
|
||||
fi
|
||||
|
||||
echo "Environment OK; building Windows installer"
|
||||
exitCode=0
|
||||
|
||||
{
|
||||
cp -r 'build/libs/lib' 'build_packages/NSIS/lib' &&
|
||||
cp 'build/libs/Progressia.jar' 'build_packages/NSIS/Progressia.jar' &&
|
||||
cp 'LICENSE' 'build_packages/NSIS/LICENSE.txt' &&
|
||||
echo "------ NSIS ------" &&
|
||||
makensis "$configurationFile" &&
|
||||
echo "---- NSIS END ----" &&
|
||||
mv "$outputFile" build_packages
|
||||
} || {
|
||||
echoerr "Could not build Windows installer"
|
||||
exitCode=1
|
||||
}
|
||||
|
||||
{
|
||||
if [ -d 'build_packages/NSIS/lib' ]; then
|
||||
rm -r 'build_packages/NSIS/lib'
|
||||
fi
|
||||
if [ -e 'build_packages/NSIS/Progressia.jar' ]; then
|
||||
rm 'build_packages/NSIS/Progressia.jar'
|
||||
fi
|
||||
if [ -e 'build_packages/NSIS/LICENSE.txt' ]; then
|
||||
rm 'build_packages/NSIS/LICENSE.txt'
|
||||
fi
|
||||
echo "Cleaned up"
|
||||
} || {
|
||||
echoerr "Could not clean up after building Windows installer"
|
||||
exitCode=2
|
||||
}
|
||||
|
||||
exit "$exitCode"
|
||||
}
|
||||
|
||||
printUsage() {
|
||||
echoerr "Usage: $0 TARGET"
|
||||
echoerr " where TARGET is 'debian' or 'windows'"
|
||||
}
|
||||
|
||||
if [ -n "$2" ]; then
|
||||
echoerr "Too many arguments."
|
||||
printUsage
|
||||
exit 202
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
"debian")
|
||||
buildDebianPackage
|
||||
;;
|
||||
"windows")
|
||||
buildWindowsInstaller
|
||||
;;
|
||||
"")
|
||||
echoerr "No action specified"
|
||||
printUsage
|
||||
exit 200
|
||||
;;
|
||||
"--help" | "-help" | "help" | "?")
|
||||
printUsage
|
||||
;;
|
||||
*)
|
||||
echoerr "Unknown action '$1'"
|
||||
printUsage
|
||||
exit 201
|
||||
;;
|
||||
esac
|
149
build_logic/lwjgl.gradle
Normal file
149
build_logic/lwjgl.gradle
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Build logic for Progressia
|
||||
* LWJGL dependency logic
|
||||
*/
|
||||
|
||||
project.ext.lwjgl = new HashMap<>()
|
||||
|
||||
// Version of LWJGL
|
||||
lwjgl.version = '3.3.0'
|
||||
|
||||
/*
|
||||
* Target platforms for current operation.
|
||||
* This is filled in by the request* tasks. This is referenced by the addLwjglNatives task.
|
||||
* When empty, current platform is assumed.
|
||||
*/
|
||||
lwjgl.targets = new HashSet<String>()
|
||||
|
||||
// LWJGL components. To include org.lwjgl:lwjgl-foobar, add 'foobar' to this list.
|
||||
lwjgl.libraries = [
|
||||
'opengl',
|
||||
'glfw',
|
||||
'openal',
|
||||
'stb'
|
||||
]
|
||||
|
||||
// Determine the architecture of the build environment
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
switch (OperatingSystem.current()) {
|
||||
case OperatingSystem.LINUX:
|
||||
def osArch = System.getProperty('os.arch')
|
||||
lwjgl.localArch = osArch.startsWith('arm') || osArch.startsWith('aarch64')
|
||||
? "linux-${osArch.contains('64') || osArch.startsWith('armv8') ? 'arm64' : 'arm32'}"
|
||||
: 'linux'
|
||||
break
|
||||
case OperatingSystem.MAC_OS:
|
||||
lwjgl.localArch = System.getProperty('os.arch').startsWith('aarch64') ? 'macos-arm64' : 'macos'
|
||||
break
|
||||
case OperatingSystem.WINDOWS:
|
||||
def osArch = System.getProperty('os.arch')
|
||||
lwjgl.localArch = osArch.contains('64')
|
||||
? "windows${osArch.startsWith('aarch64') ? '-arm64' : ''}"
|
||||
: 'windows-x86'
|
||||
break
|
||||
default:
|
||||
logger.info "Unknown or unsupported OS type according to Gradle's org.gradle.internal.os.OperatingSystem: ${OperatingSystem.current()}"
|
||||
break
|
||||
}
|
||||
|
||||
configurations {
|
||||
create 'lwjglNatives'
|
||||
}
|
||||
|
||||
// Declare pure-Java dependencies
|
||||
dependencies {
|
||||
// BOM
|
||||
|
||||
def bom = platform("org.lwjgl:lwjgl-bom:${lwjgl.version}")
|
||||
implementation bom
|
||||
lwjglNatives bom
|
||||
|
||||
// Core
|
||||
implementation 'org.lwjgl:lwjgl'
|
||||
// Local natives for core
|
||||
runtimeOnly "org.lwjgl:lwjgl::natives-${lwjgl.localArch}"
|
||||
|
||||
// Components
|
||||
lwjgl.libraries.each { lib ->
|
||||
implementation "org.lwjgl:lwjgl-$lib"
|
||||
// Local natives for component
|
||||
runtimeOnly "org.lwjgl:lwjgl-$lib::natives-${lwjgl.localArch}"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds LWJGL native libraries to lwjglNatives configuration
|
||||
*/
|
||||
task lwjgl_addNativesToRuntimeOnly {
|
||||
doFirst {
|
||||
if (project.hasProperty('forceTargets')) {
|
||||
try {
|
||||
def oldTargets = lwjgl.targets.join(',')
|
||||
|
||||
lwjgl.targets.clear()
|
||||
lwjgl.targets.addAll project.forceTargets.split(',')*.trim().collect { it == 'local' ? lwjgl.localArch : it }
|
||||
|
||||
logger.info 'Overriding selected platforms {} with {}', oldTargets, lwjgl.targets.join(',')
|
||||
} catch (Exception e) {
|
||||
throw new GradleException("Could not parse forceTargets \"${project.forceTargets}\", expecting platform-1,platform-2,local", e)
|
||||
}
|
||||
}
|
||||
|
||||
if (lwjgl.targets.isEmpty()) {
|
||||
logger.info 'Adding LWJGL native dependencies for local platform only: {}', lwjgl.localArch
|
||||
lwjgl.targets.add lwjgl.localArch
|
||||
} else {
|
||||
logger.info 'Adding LWJGL native dependencies for platforms: {}', lwjgl.targets.sort().join(', ')
|
||||
}
|
||||
|
||||
if (lwjgl.targets.contains(null)) {
|
||||
if (lwjgl.localArch != null) {
|
||||
throw new GradleException("Requested local LWJGL natives; could not determine local architecture for OS ${OperatingSystem.current()} with os.arch ${System.getProperty('os.arch')}")
|
||||
} else {
|
||||
throw new GradleException("LWJGL targets resolved to ${lwjgl.targets}")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
lwjgl.targets.each { target ->
|
||||
lwjglNatives "org.lwjgl:lwjgl::natives-$target"
|
||||
lwjgl.libraries.each { lib ->
|
||||
lwjglNatives "org.lwjgl:lwjgl-$lib::natives-$target"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces LWJGL natives in the given configuration with the requested ones
|
||||
lwjgl.replaceNativesIn = { config ->
|
||||
new ArrayList<File>().tap {
|
||||
addAll config
|
||||
removeIf { it.name ==~ /.*lwjgl.*natives.*/ }
|
||||
addAll project.configurations.lwjglNatives
|
||||
}
|
||||
}
|
||||
|
||||
task requestCrossPlatformDependencies {
|
||||
description 'Adds LWJGL natives for all available platforms.'
|
||||
|
||||
lwjgl_addNativesToRuntimeOnly.mustRunAfter requestCrossPlatformDependencies
|
||||
}
|
||||
|
||||
def requestTask(String name, String... targets) {
|
||||
def theTask = task "request${name}Dependencies"
|
||||
|
||||
theTask.doFirst {
|
||||
lwjgl.targets.addAll targets
|
||||
}
|
||||
|
||||
theTask.description "Adds LWJGL natives for $name (${targets.join(', ')})."
|
||||
|
||||
requestCrossPlatformDependencies.dependsOn theTask
|
||||
lwjgl_addNativesToRuntimeOnly.mustRunAfter theTask
|
||||
}
|
||||
|
||||
requestTask 'Linux', 'linux', 'linux-arm32', 'linux-arm64'
|
||||
requestTask 'Windows', 'windows', 'windows-arm64', 'windows-x86'
|
||||
requestTask 'MacOS', 'macos', 'macos-arm64'
|
42
build_logic/packaging/deb/script.gradle
Normal file
42
build_logic/packaging/deb/script.gradle
Normal file
@ -0,0 +1,42 @@
|
||||
task packageDeb_processResources(type: Copy) {
|
||||
dependsOn resolveVersion
|
||||
dependsOn preparePackaging
|
||||
|
||||
from 'src/packaging/deb'
|
||||
|
||||
filesMatching('DEBIAN/control') {
|
||||
expand(version: { -> project.version})
|
||||
}
|
||||
|
||||
into 'build/tmp/packaging/workingDir'
|
||||
}
|
||||
|
||||
task packageDeb_configure() {
|
||||
preparePackaging.mustRunAfter packageDeb_configure
|
||||
|
||||
doLast {
|
||||
tasks.preparePackaging.ext.buildDest = 'usr/share/progressia'
|
||||
tasks.preparePackaging.ext.mode = 'copy'
|
||||
}
|
||||
}
|
||||
|
||||
task packageDeb(type: Exec) {
|
||||
description 'Builds the project and creates a Debian package.'
|
||||
group 'Progressia'
|
||||
|
||||
dependsOn packageDeb_configure
|
||||
dependsOn requestLinuxDependencies
|
||||
dependsOn build
|
||||
dependsOn preparePackaging
|
||||
|
||||
dependsOn packageDeb_processResources
|
||||
|
||||
doFirst {
|
||||
mkdir 'build/packages'
|
||||
}
|
||||
|
||||
executable 'dpkg-deb'
|
||||
args '--root-owner-group'
|
||||
args '--build', 'build/tmp/packaging/workingDir'
|
||||
args 'build/packages'
|
||||
}
|
54
build_logic/packaging/nsis/script.gradle
Normal file
54
build_logic/packaging/nsis/script.gradle
Normal file
@ -0,0 +1,54 @@
|
||||
task packageNsis_processResources(type: Copy) {
|
||||
dependsOn preparePackaging
|
||||
|
||||
from ('src/packaging/nsis') {
|
||||
exclude 'left_side.png'
|
||||
}
|
||||
from('LICENSE') {
|
||||
rename 'LICENSE', 'LICENSE.txt'
|
||||
}
|
||||
into 'build/tmp/packaging/workingDir'
|
||||
}
|
||||
|
||||
task packageNsis_generateIcon(type: Exec) {
|
||||
mustRunAfter preparePackaging
|
||||
|
||||
executable 'convert'
|
||||
args files('src/main/resources/assets/icons/*.original.png').files*.path
|
||||
args 'build/tmp/packaging/workingDir/logo.ico'
|
||||
}
|
||||
|
||||
task packageNsis_generateLeftSide(type: Exec) {
|
||||
mustRunAfter preparePackaging
|
||||
|
||||
executable 'convert'
|
||||
args 'src/packaging/nsis/left_side.png'
|
||||
args '-alpha', 'off'
|
||||
args 'BMP3:build/tmp/packaging/workingDir/left_side.bmp'
|
||||
}
|
||||
|
||||
task packageNsis(type: Exec) {
|
||||
description 'Builds the project and creates a Windows NSIS installer.'
|
||||
group 'Progressia'
|
||||
|
||||
dependsOn requestWindowsDependencies
|
||||
dependsOn build
|
||||
dependsOn resolveVersion
|
||||
dependsOn preparePackaging
|
||||
|
||||
dependsOn packageNsis_processResources
|
||||
dependsOn packageNsis_generateIcon
|
||||
dependsOn packageNsis_generateLeftSide
|
||||
|
||||
doFirst {
|
||||
mkdir 'build/packages'
|
||||
}
|
||||
|
||||
executable 'makensis'
|
||||
args '-NOCONFIG'
|
||||
args "-DPROJECT_NAME=${project.name}"
|
||||
args "-DPROJECT_VERSION=${ -> project.version}"
|
||||
args "-DMAIN_JAR_FILE=${ -> project.tasks.jar.archiveFileName.get()}"
|
||||
args "-DOUTPUT_DIR=${project.buildDir.absolutePath}/packages"
|
||||
args 'build/tmp/packaging/workingDir/config.nsi'
|
||||
}
|
45
build_logic/packaging/zip/script.gradle
Normal file
45
build_logic/packaging/zip/script.gradle
Normal file
@ -0,0 +1,45 @@
|
||||
task packageZip_processResources(type: Copy) {
|
||||
dependsOn preparePackaging
|
||||
|
||||
from ('src/packaging/zip') {
|
||||
filesMatching('start.*') {
|
||||
filter(
|
||||
org.apache.tools.ant.filters.ReplaceTokens,
|
||||
tokens: [mainJarFile: project.tasks.jar.archiveFileName.get()]
|
||||
)
|
||||
}
|
||||
}
|
||||
from ('src/main/resource/assets/icons/logo256.original.png') {
|
||||
rename 'logo256.original.png', 'logo.png'
|
||||
}
|
||||
from('LICENSE') {
|
||||
rename 'LICENSE', 'LICENSE.txt'
|
||||
}
|
||||
into 'build/tmp/packaging/workingDir'
|
||||
}
|
||||
|
||||
task packageZip(type: Zip) {
|
||||
description 'Builds the project and creates a cross-platform ZIP package.'
|
||||
group 'Progressia'
|
||||
|
||||
dependsOn resolveVersion
|
||||
dependsOn requestCrossPlatformDependencies
|
||||
dependsOn build
|
||||
dependsOn preparePackaging
|
||||
|
||||
dependsOn packageZip_processResources
|
||||
|
||||
archiveBaseName = project.name
|
||||
archiveAppendix = 'universal'
|
||||
|
||||
doFirst {
|
||||
archiveVersion = project.version
|
||||
}
|
||||
|
||||
doFirst {
|
||||
mkdir 'build/packages'
|
||||
}
|
||||
|
||||
from 'build/tmp/packaging/workingDir'
|
||||
destinationDirectory = file('build/packages')
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 151 KiB |
Binary file not shown.
Before Width: | Height: | Size: 187 KiB |
@ -1,8 +1,10 @@
|
||||
# Build Guide
|
||||
|
||||
This document is a guide to building Progressia from source.
|
||||
This document is a guide to building Progressia from source. For quick reference, see
|
||||
[Build Script Reference](BuildScriptReference.md).
|
||||
|
||||
Compilation should be possible on all platforms that support JDK 8 or later, however, packaging scripts require Bash.
|
||||
Compilation should be possible on all platforms that support JDK 8 or later, however, packaging scripts require
|
||||
additional programs in `PATH`.
|
||||
|
||||
This guide assumes you are familiar with using a terminal or Windows Command Prompt or PowerShell.
|
||||
|
||||
@ -141,8 +143,8 @@ build.
|
||||
Some users might find the need to build for a specific set of platforms. Inclusion of GNU/Linux, Windows or MacOS
|
||||
dependencies individually can be controlled with the following arguments to the `./gradlew build` command:
|
||||
- `requestLinuxDependencies` requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included;
|
||||
- `requestWindowsDependencies` requests that `natives-windows` and `natives-windows-x86` binaries are included;
|
||||
- `requestMacOSDependencies` requests that `natives-macos` binaries are included.
|
||||
- `requestWindowsDependencies` requests that `natives-windows`, `natives-windows-arm64` and `natives-windows-x86` binaries are included;
|
||||
- `requestMacOSDependencies` requests that `natives-macos`, `natives-macos-arm64` binaries are included.
|
||||
These requests can be applied in any combination. For example, the following command produces a build containing only
|
||||
GNU/Linux and Windows natives:
|
||||
|
||||
@ -150,54 +152,46 @@ GNU/Linux and Windows natives:
|
||||
./gradlew build requestLinuxDependencies requestWindowsDependencies
|
||||
```
|
||||
|
||||
For finer control please edit `build.gradle` manually by adding the desired natives to the `project.ext.platforms` set like so:
|
||||
|
||||
```
|
||||
project.ext.platforms = new HashSet<>()
|
||||
project.ext.platforms.add 'natives-windows-x86'
|
||||
```
|
||||
|
||||
## Packaging
|
||||
|
||||
A Debian package and a Windows installer can be created automatically on systems that support Bash. These tasks are delegated
|
||||
by Gradle to `buildPackages.sh` in repository root. This script checks the environment and assembles the requested output; the
|
||||
resulting files are moved into `build_packages`.
|
||||
A universal ZIP distribution, a Debian package and a Windows NSIS installer may be created automatically by the build
|
||||
script.
|
||||
|
||||
### Creating a universal ZIP package
|
||||
|
||||
A universal cross-platform ZIP archive can be created with the following Gradle task:
|
||||
|
||||
```
|
||||
./gradlew packageZip
|
||||
```
|
||||
|
||||
Gradle will then build all artifacts necessary to run the game on all available platforms and package game files,
|
||||
libraries, launch scripts, etc. into a compressed ZIP archive.
|
||||
|
||||
The resulting file can be found in `build/packages/`
|
||||
|
||||
### Creating a Debian package
|
||||
|
||||
A Debian package can be created with the following Gradle task:
|
||||
|
||||
```
|
||||
./gradlew packageDebian
|
||||
./gradlew packageDeb
|
||||
```
|
||||
|
||||
Gradle will then build all artifacts necessary to run the game on GNU/Linux (all three architectures) and invoke
|
||||
`./buildPackages.sh debian`. Commands `dpkg-deb` and `fakeroot` must be available in system path in order to build the package.
|
||||
`dpkg-deb`. Commands `dpkg-deb` must be available in system path in order to build the package.
|
||||
|
||||
### Creating a Windows installer
|
||||
|
||||
A Windows installer can be created with the following Gradle task:
|
||||
A Windows NSIS installer can be created with the following Gradle task:
|
||||
|
||||
```
|
||||
./gradlew packageWindows
|
||||
./gradlew packageNsis
|
||||
```
|
||||
|
||||
Gradle will then build all artifacts necessary to run the game on Windows (both x64 and x86 architectures) and invoke
|
||||
`./buildPackages.sh windows`.
|
||||
`makensis`.
|
||||
|
||||
Windows installers are implemented with [NSIS](https://nsis.sourceforge.io/). Command `makensis` must be available in system
|
||||
path in order to build the installer.
|
||||
|
||||
## Gradle tasks summary
|
||||
|
||||
- `buildLocal` – creates a build optimized for current platform. Use this to quickly build the game during development.
|
||||
- `buildCrossPlatform` – creates a build that supports all known architectures. Use this to build a universal version of the game.
|
||||
- `build` – currently a synonym of `buildLocal`; creates a default build.
|
||||
- `packageDebian` – creates a Debian package. Do not invoke together with `packageWindows`.
|
||||
- `packageWindows` – creates a Windows installer. Do not invoke together with `packageDebian`.
|
||||
- `requestLinuxDependencies` – requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included when building.
|
||||
- `requestWindowsDependencies` – requests that `natives-windows` and `natives-windows-x86` binaries are included when building.
|
||||
- `requestMacOSDependencies` – requests that `natives-macos` binaries are included when building.
|
||||
- `requestCrossPlatformDependencies` – requests that all binaries are included when building.
|
||||
|
||||
All other basic and Java-related Gradle tasks are available as well.
|
||||
Windows installers are implemented with [NSIS](https://nsis.sourceforge.io/). [ImageMagick](https://imagemagick.org),
|
||||
a command-line image editing tool, is used to generate some assets for the installer. Commands `makensis` and
|
||||
`convert` (from ImageMagick) must be available in system path in order to build the installer.
|
||||
|
112
docs/building/BuildScriptReference.md
Normal file
112
docs/building/BuildScriptReference.md
Normal file
@ -0,0 +1,112 @@
|
||||
# Build Script Reference
|
||||
|
||||
This document is a user's reference for the build script of Progressia. For a beginner-friendly guide, see
|
||||
[Build Guide](BuildGuide.md).
|
||||
|
||||
## Gradle tasks summary
|
||||
|
||||
- `buildLocal` – creates a build optimized for current platform. Use this to quickly build the game during development.
|
||||
- `buildCrossPlatform` – creates a build that supports all known architectures. Use this to build a universal version of the game.
|
||||
- `build` – currently a synonym of `buildLocal`; creates a default build.
|
||||
- `packageZip` – creates a universal ZIP. Incompatible with other `package` tasks.
|
||||
- `packageDeb` – creates a Debian package. Incompatible with other `package` tasks.
|
||||
- `packageNsis` – creates a Windows NSIS installer. Incompatible with other `package` tasks.
|
||||
- `requestLinuxDependencies` – requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included when building.
|
||||
- `requestWindowsDependencies` – requests that `natives-windows`, `natives-windows-arm64` and `natives-windows-x86` binaries are included when building.
|
||||
- `requestMacOSDependencies` – requests that `natives-macos` and `natives-macos-arm64` binaries are included when building.
|
||||
- `requestCrossPlatformDependencies` – requests that all binaries are included when building.
|
||||
|
||||
To execute a task, run `./gradlew <task-name>`.
|
||||
|
||||
`build`-type tasks output the executable JAR and all libraries required at runtime into `build/libs`. `package`-type
|
||||
tasks output packages into `build/packages`.
|
||||
|
||||
## Packaging tasks
|
||||
|
||||
Some packaging tasks require additional software in `PATH`.
|
||||
|
||||
| Task | Commands required in `PATH` |
|
||||
|---------------|------------------------------------------|
|
||||
| `packageDeb` | `dpkg-deb` |
|
||||
| `packageZip` | _none_ |
|
||||
| `packageNsis` | `makensis`, `convert` (from ImageMagick) |
|
||||
|
||||
## Version and metadata
|
||||
|
||||
### Version scheme
|
||||
|
||||
Progressia builds are identified by four parameters: version, Git commit, Git branch and build ID.
|
||||
|
||||
Versions roughly follow [semantic versioning](https://semver.org/spec/v2.0.0.html), with each version fitting the
|
||||
`MAJOR.MINOR.PATCH[-SUFFIX]` pattern. Depending on the build environment (see below), version is either "real" with
|
||||
no metadata (e.g. `0.43.2` or `1.2.1-beta`) or a dummy fallback with build metadata (e.g. `999.0.0-2021_07_23` or
|
||||
`999.0.0-WJ3`).
|
||||
|
||||
### Version detection
|
||||
|
||||
Build script considers three scenarios when determining the version:
|
||||
|
||||
1. `version` project property is set explicitly. This may be done in a variety of ways, for example with command line
|
||||
argument `-Pversion=1.2.3`
|
||||
(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties))
|
||||
2. Local Git repository is found, and HEAD is tagged appropriately: version is the tag name with leading `v`
|
||||
stripped. Example: `v1.2.3` is version `1.2.3`
|
||||
3. Local Git repository is found, and some ancestor of HEAD is tagged appropriately: version is the tag name with
|
||||
leading `v` stripped and PATCH incremented by one. Example: `v1.2.3` is version `1.2.4`
|
||||
|
||||
Tags not named like `vMAJOR.MINOR.PATCH[-SUFFIX]` are ignored for cases 2 and 3.
|
||||
|
||||
In all other cases, a fallback dummy value is used for version, appended with build ID or current date.
|
||||
|
||||
### Git metadata
|
||||
|
||||
Git commit is determined from `GIT_COMMIT` environment variable if it exists, or the state of the local Git
|
||||
repository, if any, or `-`.
|
||||
|
||||
Git branch is determined from `GIT_BRANCH` environment variable if it exists, or the state of the local Git
|
||||
repository, if any, or `-`.
|
||||
|
||||
The names of the environment variables are picked to assist Jenkins builds.
|
||||
|
||||
### Build ID
|
||||
|
||||
Build ID uniquely identifies artifacts produced by automated build systems. Build ID must be provided explicitly; it
|
||||
is `-` unless specified otherwise.
|
||||
|
||||
The proposed scheme for naming build IDs is `<builder><build-system><build attempt no.>`. For example, builds
|
||||
executed by WindCorp Jenkins suite have build IDs like `WJ3` or `WJ142`.
|
||||
|
||||
Build ID may be set with `buildId` project property. This may be done in a variety of ways, for example with command
|
||||
line argument `-PbuildId=WJ3`
|
||||
(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)).
|
||||
|
||||
## Native libraries
|
||||
|
||||
LWJGL uses native libraries. Build script declares platform-specific dependencies based on the set of target
|
||||
platforms, `project.ext.lwjgl.targets` (aka `lwjgl.targets`). These dependencies are added to `runtimeOnly`
|
||||
configuration.
|
||||
|
||||
When this set is empty, the script selects natives for current platform. Otherwise, all platforms in the set are
|
||||
included.
|
||||
|
||||
`lwjgl.targets` is populated automatically by packaging tasks and by `buildCrossPlatform`. To add extra targets,
|
||||
``requestXxxDependencies` tasks may be used.
|
||||
|
||||
Target selection mechanism may be overridden with `forceTargets` project property. This may be done in a variety of
|
||||
ways, for example with command line argument `-PforceTargets=windows-x86,local`
|
||||
(see [Gradle docs](https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties)). The
|
||||
value is a comma-separated list of target architectures. `local` target will be replaced with the automatically
|
||||
detected current architecture.
|
||||
|
||||
### Available targets
|
||||
|
||||
| Name | Task |
|
||||
|-----------------|------------------------------|
|
||||
| `linux` | `requestLinuxDependencies` |
|
||||
| `linux-arm32` | `requestLinuxDependencies` |
|
||||
| `linux-arm64` | `requestLinuxDependencies` |
|
||||
| `windows` | `requestWindowsDependencies` |
|
||||
| `windows-arm64` | `requestWindowsDependencies` |
|
||||
| `windows-x86` | `requestWindowsDependencies` |
|
||||
| `macos` | `requestMacOSDependencies` |
|
||||
| `macos-arm64` | `requestMacOSDependencies` |
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
269
gradlew
vendored
269
gradlew
vendored
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -17,78 +17,113 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
@ -105,79 +140,95 @@ location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
25
gradlew.bat
vendored
25
gradlew.bat
vendored
@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@ -51,7 +54,7 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
@ -61,28 +64,14 @@ echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
45
src/main/java/ru/windcorp/jputil/ConstantsMapException.java
Normal file
45
src/main/java/ru/windcorp/jputil/ConstantsMapException.java
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* JPUtil
|
||||
* Copyright (C) 2019-2021 OLEGSHA/Javapony 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.jputil;
|
||||
|
||||
public class ConstantsMapException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -4298704891780063127L;
|
||||
|
||||
public ConstantsMapException() {
|
||||
|
||||
}
|
||||
|
||||
public ConstantsMapException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
public ConstantsMapException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ConstantsMapException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ConstantsMapException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
307
src/main/java/ru/windcorp/jputil/IntConstantsMap.java
Normal file
307
src/main/java/ru/windcorp/jputil/IntConstantsMap.java
Normal file
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* JPUtil
|
||||
* Copyright (C) 2019-2022 OLEGSHA/Javapony 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.jputil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntPredicate;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class IntConstantsMap {
|
||||
|
||||
private final Map<Integer, String> namesByValue;
|
||||
private final Map<String, Integer> valuesByName;
|
||||
|
||||
protected IntConstantsMap(Map<Integer, String> namesByValue, Map<String, Integer> valuesByName) {
|
||||
this.namesByValue = namesByValue;
|
||||
this.valuesByName = valuesByName;
|
||||
}
|
||||
|
||||
public int getValue(String name) {
|
||||
Integer value = valuesByName.get(name);
|
||||
if (value == null) {
|
||||
throw new NoSuchElementException("No constant with name " + name);
|
||||
}
|
||||
return value.intValue();
|
||||
}
|
||||
|
||||
public boolean hasConstant(String name) {
|
||||
return valuesByName.containsKey(name);
|
||||
}
|
||||
|
||||
public String getName(int value) {
|
||||
String name = namesByValue.get(value);
|
||||
if (name == null) {
|
||||
throw new NoSuchElementException("No constant with value " + value);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean hasConstant(int value) {
|
||||
return namesByValue.containsKey(value);
|
||||
}
|
||||
|
||||
public Map<String, Integer> getAll() {
|
||||
return valuesByName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return valuesByName.toString();
|
||||
}
|
||||
|
||||
public static Builder from(Class<?> clazz) {
|
||||
return new Builder(clazz);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
@FunctionalInterface
|
||||
public static interface Filter {
|
||||
boolean test(String name, int value);
|
||||
}
|
||||
|
||||
public class ConstantSpec {
|
||||
public String name;
|
||||
public int value;
|
||||
|
||||
public void drop() {
|
||||
if (!extra.contains(name)) {
|
||||
name = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final List<Consumer<ConstantSpec>> transforms = new ArrayList<>();
|
||||
private final Set<String> extra = new HashSet<>();
|
||||
|
||||
private final Class<?> source;
|
||||
|
||||
public Builder(Class<?> source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public Builder apply(Consumer<ConstantSpec> transform) {
|
||||
transforms.add(transform);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder only(Filter filter) {
|
||||
return apply(s -> {
|
||||
if (!filter.test(s.name, s.value)) {
|
||||
s.drop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Builder only(Predicate<String> nameFilter) {
|
||||
return apply(s -> {
|
||||
if (!nameFilter.test(s.name)) {
|
||||
s.drop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Builder onlyValued(IntPredicate valueFilter) {
|
||||
return apply(s -> {
|
||||
if (!valueFilter.test(s.value)) {
|
||||
s.drop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Builder regex(String regex) {
|
||||
return only(Pattern.compile(regex).asPredicate());
|
||||
}
|
||||
|
||||
public Builder prefix(String prefix) {
|
||||
return only(n -> n.startsWith(prefix) && n.length() > prefix.length());
|
||||
}
|
||||
|
||||
public Builder exclude(Filter filter) {
|
||||
return only((n, v) -> !filter.test(n, v));
|
||||
}
|
||||
|
||||
public Builder exclude(Predicate<String> nameFilter) {
|
||||
return only(nameFilter.negate());
|
||||
}
|
||||
|
||||
public Builder exclude(String... names) {
|
||||
Set<String> excluded = new HashSet<>();
|
||||
for (String name : names) {
|
||||
excluded.add(name);
|
||||
}
|
||||
return exclude(excluded::contains);
|
||||
}
|
||||
|
||||
public Builder excludeRegex(String... nameRegexes) {
|
||||
List<Predicate<String>> tests = new ArrayList<>();
|
||||
for (String regex : nameRegexes) {
|
||||
tests.add(Pattern.compile(regex).asPredicate());
|
||||
}
|
||||
return only((n, v) -> {
|
||||
for (Predicate<String> test : tests) {
|
||||
if (test.test(n)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public Builder extra(String... names) {
|
||||
for (String name : names) {
|
||||
extra.add(name);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder rename(Function<String, String> renamer) {
|
||||
apply(s -> {
|
||||
s.name = renamer.apply(s.name);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder stripPrefix(String prefix) {
|
||||
return apply(s -> {
|
||||
if (s.name.startsWith(prefix)) {
|
||||
s.name = s.name.substring(prefix.length());
|
||||
} else if (extra.contains(s.name)) {
|
||||
return;
|
||||
} else {
|
||||
s.drop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public IntConstantsMap scan() {
|
||||
return build(true);
|
||||
}
|
||||
|
||||
public IntConstantsMap scanAll() {
|
||||
return build(false);
|
||||
}
|
||||
|
||||
private IntConstantsMap build(boolean onlyPublic) {
|
||||
Map<Integer, String> namesByValue = new HashMap<>();
|
||||
Map<String, Integer> valuesByName = new HashMap<>();
|
||||
|
||||
BiConsumer<String, Integer> putter = (name, value) -> {
|
||||
if (namesByValue.containsKey(value)) {
|
||||
throw newDuplicateException("value", value, name, namesByValue.get(value));
|
||||
}
|
||||
if (valuesByName.containsKey(name)) {
|
||||
throw newDuplicateException("name", name, value, valuesByName.get(name));
|
||||
}
|
||||
namesByValue.put(value, name);
|
||||
valuesByName.put(name, value);
|
||||
};
|
||||
|
||||
try {
|
||||
for (Field field : source.getDeclaredFields()) {
|
||||
processField(field, putter, onlyPublic);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConstantsMapException(e);
|
||||
}
|
||||
|
||||
return new IntConstantsMap(
|
||||
Collections.unmodifiableMap(namesByValue),
|
||||
Collections.unmodifiableMap(valuesByName)
|
||||
);
|
||||
}
|
||||
|
||||
private void processField(Field field, BiConsumer<String, Integer> putter, boolean onlyPublic)
|
||||
throws IllegalAccessException {
|
||||
if (!Modifier.isStatic(field.getModifiers())) {
|
||||
return;
|
||||
}
|
||||
if (!Modifier.isFinal(field.getModifiers())) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean clearAccessible = false;
|
||||
if (!Modifier.isPublic(field.getModifiers())) {
|
||||
if (onlyPublic) {
|
||||
return;
|
||||
} else if (!isAccessibleFlagSet(field)) {
|
||||
field.setAccessible(true);
|
||||
clearAccessible = true;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
ConstantSpec spec = new ConstantSpec();
|
||||
spec.name = field.getName();
|
||||
spec.value = field.getInt(null);
|
||||
|
||||
for (Consumer<ConstantSpec> t : transforms) {
|
||||
t.accept(spec);
|
||||
if (spec.name == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
putter.accept(spec.name, spec.value);
|
||||
|
||||
} finally {
|
||||
if (clearAccessible) {
|
||||
field.setAccessible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Yes, this method exists only so that neither Java 8 nor Java 9 complain about deprecation.
|
||||
*/
|
||||
@Deprecated
|
||||
private boolean isAccessibleFlagSet(Field f) {
|
||||
return f.isAccessible();
|
||||
}
|
||||
|
||||
private ConstantsMapException newDuplicateException(String what, Object common, Object current, Object old) {
|
||||
return new ConstantsMapException(
|
||||
String.format(
|
||||
"Duplicate %1$s: %2$s -> %3$s and %2$s -> %4$s",
|
||||
what,
|
||||
common,
|
||||
current,
|
||||
old
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -18,6 +18,177 @@
|
||||
|
||||
package ru.windcorp.progressia;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
|
||||
/**
|
||||
* A class providing access to build metadata.
|
||||
*/
|
||||
public class Progressia {
|
||||
|
||||
private static final String NAME = "Progressia";
|
||||
private static String version;
|
||||
private static String gitCommit;
|
||||
private static String gitBranch;
|
||||
private static String buildId;
|
||||
|
||||
static {
|
||||
try {
|
||||
Manifest manifest = findManifest();
|
||||
|
||||
if (manifest == null) {
|
||||
setDevelopmentMetadata();
|
||||
LogManager.getLogger().info(
|
||||
"Manifest with Specification-Title not found. "
|
||||
+ "Either you are in a development environment or something has gone horribly wrong with classloaders."
|
||||
);
|
||||
} else {
|
||||
fillMetadata(manifest);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
CrashReports.crash(t, "Something went wrong while loading metadata");
|
||||
}
|
||||
}
|
||||
|
||||
private static Manifest findManifest() {
|
||||
try {
|
||||
Enumeration<URL> resources = Progressia.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
|
||||
Collection<IOException> exceptions = new ArrayList<>();
|
||||
|
||||
while (resources.hasMoreElements()) {
|
||||
URL url = resources.nextElement();
|
||||
|
||||
try {
|
||||
|
||||
Manifest manifest = new Manifest(url.openStream());
|
||||
Attributes mainAttributes = manifest.getMainAttributes();
|
||||
if (NAME.equals(mainAttributes.getValue("Specification-Title"))) {
|
||||
return manifest;
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
exceptions.add(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (exceptions.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
IOException scapegoat = null;
|
||||
for (IOException e : exceptions) {
|
||||
if (scapegoat == null) {
|
||||
scapegoat = e;
|
||||
} else {
|
||||
scapegoat.addSuppressed(e);
|
||||
}
|
||||
}
|
||||
|
||||
throw CrashReports.report(scapegoat, "Could not read manifest");
|
||||
} catch (IOException e) {
|
||||
throw CrashReports.report(e, "Could not read manifest");
|
||||
}
|
||||
}
|
||||
|
||||
private static void setDevelopmentMetadata() {
|
||||
version = "dev";
|
||||
gitCommit = "-";
|
||||
gitBranch = "-";
|
||||
buildId = "-";
|
||||
}
|
||||
|
||||
private static void fillMetadata(Manifest manifest) {
|
||||
version = getAttributeOrCrash(manifest, "Implementation-Version");
|
||||
gitCommit = getAttributeOrCrash(manifest, "Implementation-Version-Git-Commit");
|
||||
gitBranch = getAttributeOrCrash(manifest, "Implementation-Version-Git-Branch");
|
||||
buildId = getAttributeOrCrash(manifest, "Implementation-Version-BuildId");
|
||||
}
|
||||
|
||||
private static String getAttributeOrCrash(Manifest manifest, String key) {
|
||||
String result = manifest.getMainAttributes().getValue(key);
|
||||
if (result == null) {
|
||||
throw CrashReports.report(null, "Manifest exists but attribute " + key + " not found");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the game as a String. Version data is retrieved
|
||||
* from a {@code META-INF/MANIFEST.MF} file located in the main JAR. Version
|
||||
* format depends on way the game was built:
|
||||
* <ul>
|
||||
* <li><code>dev</code> if no matching manifest was found, e.g. when launching from an IDE</li>
|
||||
* <li>The value of <code>Implementation-Version</code> specified in the manifest:
|
||||
* <ul>
|
||||
* <li>[Stage-]Major.Minor.Patch, e.g. <code>alpha-0.3.2</code> or <code>1.4.2</code>, for released versions</li>
|
||||
* <li>BuildId, e.g. <code>WJ7</code>, for snapshots built by automation systems</li>
|
||||
* <li>YYYY-MM-DD, e.g. <code>2021-12-32</code>, for snapshots built manually</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
public static String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public static String getFullerVersion() {
|
||||
if (isDefaultGitBranch() || "-".equals(gitBranch)) {
|
||||
return version;
|
||||
} else {
|
||||
return String.format("%s/%s", version, gitBranch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the buildId or <code>"-"</code>
|
||||
*/
|
||||
public static String getBuildId() {
|
||||
return buildId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Git commit or <code>"-"</code>
|
||||
*/
|
||||
public static String getGitCommit() {
|
||||
return gitCommit;
|
||||
}
|
||||
|
||||
public static String getGitCommitShort() {
|
||||
if (gitCommit == null || "-".equals(gitCommit)) {
|
||||
return gitCommit;
|
||||
}
|
||||
|
||||
return gitCommit.substring(0, Math.min(7, gitCommit.length()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Git branch or <code>"-"</code>
|
||||
*/
|
||||
public static String getGitBranch() {
|
||||
return gitBranch;
|
||||
}
|
||||
|
||||
public static boolean isDefaultGitBranch() {
|
||||
return "master".equals(gitBranch) || "main".equals(gitBranch);
|
||||
}
|
||||
|
||||
public static String getFullVersion() {
|
||||
return String.format("%s/%s/%s/%s", version, gitBranch, getGitCommitShort(), buildId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
package ru.windcorp.progressia;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.GUI;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer;
|
||||
@ -33,6 +35,8 @@ public class ProgressiaLauncher {
|
||||
arguments = args.clone();
|
||||
setupCrashReports();
|
||||
|
||||
LogManager.getRootLogger().info("Launching " + Progressia.getName() + " version " + Progressia.getFullVersion());
|
||||
|
||||
proxy.initialize();
|
||||
ProgressiaLauncher.proxy = proxy;
|
||||
GUI.addTopLayer(new LayerTitle("Title"));
|
||||
@ -44,6 +48,7 @@ public class ProgressiaLauncher {
|
||||
|
||||
private static void setupCrashReports() {
|
||||
// Context providers
|
||||
CrashReports.registerProvider(new VersionProvider());
|
||||
CrashReports.registerProvider(new OSContextProvider());
|
||||
CrashReports.registerProvider(new RAMContextProvider());
|
||||
CrashReports.registerProvider(new JavaVersionContextProvider());
|
||||
|
@ -18,43 +18,22 @@
|
||||
|
||||
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.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.EntityAnchor;
|
||||
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
|
||||
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.common.util.crash.ReportingEventBus;
|
||||
import ru.windcorp.progressia.common.world.DefaultWorldData;
|
||||
import ru.windcorp.progressia.test.LayerAbout;
|
||||
import ru.windcorp.progressia.test.LayerDebug;
|
||||
import ru.windcorp.progressia.test.LayerTestUI;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class Client {
|
||||
|
||||
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 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;
|
||||
|
||||
public Client(DefaultWorldData world, ServerCommsChannel comms) {
|
||||
@ -62,22 +41,6 @@ public class Client {
|
||||
this.comms = comms;
|
||||
|
||||
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() {
|
||||
@ -100,44 +63,17 @@ public class Client {
|
||||
return comms;
|
||||
}
|
||||
|
||||
public HUDManager getHUD() {
|
||||
return hudManager;
|
||||
}
|
||||
|
||||
public void toggleDebugLayer() {
|
||||
if (GUI.getLayers().contains(layerDebug)) {
|
||||
GUI.removeLayer(layerDebug);
|
||||
} else {
|
||||
GUI.addTopLayer(layerDebug);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onLocalPlayerEntityChanged(NewLocalEntityEvent e) {
|
||||
if (e.getNewEntity() == null) {
|
||||
public void onLocalPlayerEntityChanged(EntityData entity, EntityData lastKnownEntity) {
|
||||
if (entity == null) {
|
||||
getCamera().setAnchor(null);
|
||||
return;
|
||||
}
|
||||
|
||||
getCamera().setAnchor(
|
||||
new EntityAnchor(
|
||||
getWorld().getEntityRenderable(e.getNewEntity())
|
||||
getWorld().getEntityRenderable(entity)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,9 +25,9 @@ import ru.windcorp.progressia.client.graphics.backend.RenderTaskQueue;
|
||||
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
|
||||
import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader;
|
||||
import ru.windcorp.progressia.client.graphics.font.Typefaces;
|
||||
import ru.windcorp.progressia.client.graphics.gui.ColorScheme;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Atlases;
|
||||
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.common.resource.ResourceManager;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
@ -48,11 +48,11 @@ public class ClientProxy implements Proxy {
|
||||
() -> Typefaces
|
||||
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
|
||||
);
|
||||
RenderTaskQueue.waitAndInvoke(HUDTextures::loadItemAmountTypeface);
|
||||
} catch (InterruptedException e) {
|
||||
throw CrashReports.report(e, "ClientProxy failed");
|
||||
}
|
||||
|
||||
ColorScheme.load(ResourceManager.getResource("assets/default.colorScheme"));
|
||||
Localizer.getInstance().setLanguage("en-US");
|
||||
|
||||
TestContent.registerContent();
|
||||
|
@ -20,10 +20,14 @@ package ru.windcorp.progressia.client;
|
||||
|
||||
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
|
||||
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.client.localization.MutableStringLocalized;
|
||||
import ru.windcorp.progressia.server.ServerState;
|
||||
import ru.windcorp.progressia.test.LayerAbout;
|
||||
import ru.windcorp.progressia.test.LayerTestText;
|
||||
import ru.windcorp.progressia.test.LayerTestUI;
|
||||
import ru.windcorp.progressia.test.TestContent;
|
||||
|
||||
public class ClientState {
|
||||
@ -66,14 +70,24 @@ public class ClientState {
|
||||
|
||||
if (client != null && client.getLocalPlayer().hasEntity()) {
|
||||
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() {
|
||||
getInstance().getComms().disconnect();
|
||||
getInstance().remove();
|
||||
|
||||
for (Layer layer : GUI.getLayers()) {
|
||||
GUI.removeLayer(layer);
|
||||
}
|
||||
}
|
||||
|
||||
private ClientState() {
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -34,13 +34,7 @@ public class Colors {
|
||||
DEBUG_BLUE = toVector(0xFF0000FF),
|
||||
DEBUG_CYAN = toVector(0xFF00FFFF),
|
||||
DEBUG_MAGENTA = toVector(0xFFFF00FF),
|
||||
DEBUG_YELLOW = toVector(0xFFFFFF00),
|
||||
|
||||
LIGHT_GRAY = toVector(0xFFCBCBD0),
|
||||
BLUE = toVector(0xFF37A2E6),
|
||||
HOVER_BLUE = toVector(0xFFC3E4F7),
|
||||
DISABLED_GRAY = toVector(0xFFE5E5E5),
|
||||
DISABLED_BLUE = toVector(0xFFB2D8ED);
|
||||
DEBUG_YELLOW = toVector(0xFFFFFF00);
|
||||
|
||||
public static Vec4 toVector(int argb) {
|
||||
return toVector(argb, new Vec4());
|
||||
@ -56,25 +50,6 @@ public class Colors {
|
||||
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) {
|
||||
output.w = ((argb & 0xFF000000) >>> 24) / (float) 0xFF; // Alpha
|
||||
output.x = ((argb & 0x00FF0000) >>> 16) / (float) 0xFF; // Red
|
||||
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
|
||||
}
|
@ -66,12 +66,6 @@ public class GUI {
|
||||
});
|
||||
}
|
||||
|
||||
public static void updateLayer(Layer layer) {
|
||||
modify(layers -> {
|
||||
// Do nothing
|
||||
});
|
||||
}
|
||||
|
||||
private static void modify(LayerStackModification mod) {
|
||||
MODIFICATION_QUEUE.add(mod);
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2022 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.backend;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
|
||||
import ru.windcorp.jputil.ConstantsMapException;
|
||||
import ru.windcorp.jputil.IntConstantsMap;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
|
||||
public class GLFWErrorHandler {
|
||||
|
||||
private static final IntConstantsMap ERROR_CODES;
|
||||
|
||||
static {
|
||||
try {
|
||||
ERROR_CODES = IntConstantsMap.from(GLFW.class)
|
||||
.stripPrefix("GLFW_")
|
||||
.onlyValued(i -> i >= 0x10000 && i <= 0x1FFFF)
|
||||
.extra("GLFW_NO_ERROR")
|
||||
.scan();
|
||||
} catch (ConstantsMapException e) {
|
||||
throw CrashReports.report(e, "Could not analyze GLFW error codes");
|
||||
}
|
||||
}
|
||||
|
||||
public void onError(int errorCode, long descriptionPointer) {
|
||||
String description = GLFWErrorCallback.getDescription(descriptionPointer);
|
||||
|
||||
String errorCodeName;
|
||||
if (ERROR_CODES.hasConstant(errorCode)) {
|
||||
errorCodeName = ERROR_CODES.getName(errorCode);
|
||||
} else {
|
||||
errorCodeName = "<unknown " + Integer.toHexString(errorCode) + ">";
|
||||
}
|
||||
|
||||
throw CrashReports.report(null, "GLFW error detected: " + errorCodeName + " %s", description);
|
||||
}
|
||||
|
||||
}
|
@ -22,13 +22,24 @@ import static org.lwjgl.opengl.GL11.*;
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
import static org.lwjgl.system.MemoryUtil.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.lwjgl.glfw.GLFWErrorCallback;
|
||||
import org.lwjgl.glfw.GLFWImage;
|
||||
import org.lwjgl.opengl.GL;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ru.windcorp.progressia.Progressia;
|
||||
import ru.windcorp.progressia.client.graphics.GUI;
|
||||
import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent;
|
||||
import ru.windcorp.progressia.client.graphics.input.InputEvent;
|
||||
import ru.windcorp.progressia.client.graphics.texture.TextureDataEditor;
|
||||
import ru.windcorp.progressia.client.graphics.texture.TextureLoader;
|
||||
import ru.windcorp.progressia.client.graphics.texture.TextureSettings;
|
||||
import ru.windcorp.progressia.common.resource.Resource;
|
||||
import ru.windcorp.progressia.common.resource.ResourceManager;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
|
||||
class LWJGLInitializer {
|
||||
|
||||
@ -45,6 +56,7 @@ class LWJGLInitializer {
|
||||
setupWindowCallbacks();
|
||||
|
||||
glfwShowWindow(GraphicsBackend.getWindowHandle());
|
||||
GraphicsBackend.onFrameResized(GraphicsBackend.getWindowHandle(), 800, 600);
|
||||
}
|
||||
|
||||
private static void checkEnvironment() {
|
||||
@ -52,8 +64,12 @@ class LWJGLInitializer {
|
||||
}
|
||||
|
||||
private static void initializeGLFW() {
|
||||
// TODO Do GLFW error handling: check glfwInit, setup error callback
|
||||
glfwInit();
|
||||
GLFWErrorCallback.create(new GLFWErrorHandler()::onError).set();
|
||||
|
||||
if (!glfwInit()) {
|
||||
throw CrashReports.report(null, "GLFW could not be initialized: glfwInit() has failed");
|
||||
}
|
||||
|
||||
GraphicsBackend.setGLFWInitialized(true);
|
||||
}
|
||||
|
||||
@ -61,11 +77,13 @@ class LWJGLInitializer {
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
|
||||
|
||||
long handle = glfwCreateWindow(900, 900, "ProgressiaTest", NULL, NULL);
|
||||
String windowTitle = Progressia.getName() + " " + Progressia.getFullerVersion();
|
||||
long handle = glfwCreateWindow(800, 600, windowTitle, NULL, NULL);
|
||||
|
||||
// TODO Check that handle != NULL
|
||||
if (handle == 0) {
|
||||
throw CrashReports.report(null, "Could not create game window");
|
||||
}
|
||||
|
||||
GraphicsBackend.setWindowHandle(handle);
|
||||
|
||||
@ -79,8 +97,30 @@ class LWJGLInitializer {
|
||||
}
|
||||
|
||||
private static void createWindowIcons() {
|
||||
// TODO Auto-generated method stub
|
||||
if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
|
||||
// Wayland does not support changing window icons
|
||||
return;
|
||||
}
|
||||
|
||||
final String prefix = "assets/icons/";
|
||||
|
||||
String[] sizes = ResourceManager.getResource(prefix + "logoSizes.txt").readAsString().split(" ");
|
||||
|
||||
try (GLFWImage.Buffer buffer = GLFWImage.malloc(sizes.length)) {
|
||||
for (int i = 0; i < sizes.length; ++i) {
|
||||
Resource resource = ResourceManager.getResource(prefix + "logo" + sizes[i].trim() + ".png");
|
||||
TextureDataEditor icon = TextureLoader.loadPixels(resource, new TextureSettings(false, true));
|
||||
|
||||
buffer.position(i)
|
||||
.width(icon.getContentWidth())
|
||||
.height(icon.getContentHeight())
|
||||
.pixels(icon.getData().getData());
|
||||
}
|
||||
|
||||
glfwSetWindowIcon(GraphicsBackend.getWindowHandle(), buffer);
|
||||
} catch (IOException e) {
|
||||
throw CrashReports.report(e, "Could not load window icons");
|
||||
}
|
||||
}
|
||||
|
||||
private static void initializeOpenGL() {
|
||||
|
@ -191,8 +191,7 @@ public class RenderTarget {
|
||||
assembleCurrentClipFromFaces();
|
||||
|
||||
float depth = this.depth--;
|
||||
final float kostyl = 1e-2f;
|
||||
Mat4 transform = new Mat4().translate(0, 0, depth).scale(1, 1, kostyl).mul(getTransform());
|
||||
Mat4 transform = new Mat4().translate(0, 0, depth).mul(getTransform());
|
||||
assembled.add(new Clip(maskStack, transform, renderable));
|
||||
}
|
||||
|
||||
|
@ -33,22 +33,19 @@ public class Font {
|
||||
private final float align;
|
||||
private final Vec4 color;
|
||||
|
||||
private final int scale;
|
||||
|
||||
public Font(Typeface typeface, int style, float align, Vec4 color, int scale) {
|
||||
public Font(Typeface typeface, int style, float align, Vec4 color) {
|
||||
this.typeface = typeface;
|
||||
this.style = style;
|
||||
this.align = align;
|
||||
this.color = color;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public Font(Typeface typeface, int style, float align, int color, int scale) {
|
||||
this(typeface, style, align, Colors.toVector(color), scale);
|
||||
public Font(Typeface typeface, int style, float align, int color) {
|
||||
this(typeface, style, align, Colors.toVector(color));
|
||||
}
|
||||
|
||||
public Font(Typeface typeface) {
|
||||
this(typeface, Typeface.Style.PLAIN, Typeface.ALIGN_LEFT, Colors.WHITE, 2);
|
||||
this(typeface, Typeface.Style.PLAIN, Typeface.ALIGN_LEFT, Colors.WHITE);
|
||||
}
|
||||
|
||||
public Font() {
|
||||
@ -71,62 +68,30 @@ public class Font {
|
||||
return color;
|
||||
}
|
||||
|
||||
public int getScale() {
|
||||
return scale;
|
||||
public Renderable assemble(
|
||||
CharSequence chars,
|
||||
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 assemble(CharSequence chars, float maxWidth) {
|
||||
return applyScale(typeface.assembleStatic(chars, 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 Renderable assembleDynamic(
|
||||
Supplier<CharSequence> supplier,
|
||||
float maxWidth
|
||||
) {
|
||||
return typeface.assembleDynamic(supplier, style, align, maxWidth, color);
|
||||
}
|
||||
|
||||
public int getWidth(CharSequence chars, float maxWidth) {
|
||||
return scale * typeface.getWidth(chars, style, align, maxWidth);
|
||||
return typeface.getWidth(chars, style, align, maxWidth);
|
||||
}
|
||||
|
||||
public int getHeight(CharSequence chars, float maxWidth) {
|
||||
return scale * typeface.getHeight(chars, style, align, maxWidth);
|
||||
return typeface.getHeight(chars, style, align, maxWidth);
|
||||
}
|
||||
|
||||
public Vec2i getSize(CharSequence chars, float maxWidth, Vec2i 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);
|
||||
return typeface.getSize(chars, style, align, maxWidth, result);
|
||||
}
|
||||
|
||||
public boolean supports(char c) {
|
||||
@ -141,7 +106,7 @@ public class Font {
|
||||
* @return the new font
|
||||
*/
|
||||
public Font withStyle(int style) {
|
||||
return new Font(getTypeface(), style, getAlign(), getColor(), getScale());
|
||||
return new Font(getTypeface(), style, getAlign(), getColor());
|
||||
}
|
||||
|
||||
public Font deriveBold() {
|
||||
@ -193,19 +158,15 @@ public class Font {
|
||||
}
|
||||
|
||||
public Font withAlign(float align) {
|
||||
return new Font(getTypeface(), getStyle(), align, getColor(), getScale());
|
||||
return new Font(getTypeface(), getStyle(), align, getColor());
|
||||
}
|
||||
|
||||
public Font withColor(Vec4 color) {
|
||||
return new Font(getTypeface(), getStyle(), getAlign(), color, getScale());
|
||||
return new Font(getTypeface(), getStyle(), getAlign(), color);
|
||||
}
|
||||
|
||||
public Font withColor(int color) {
|
||||
return new Font(getTypeface(), getStyle(), getAlign(), color, getScale());
|
||||
}
|
||||
|
||||
public Font withScale(int scale) {
|
||||
return new Font(getTypeface(), getStyle(), getAlign(), getColor(), scale);
|
||||
return new Font(getTypeface(), getStyle(), getAlign(), color);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public class GNUUnifontLoader {
|
||||
|
||||
private static final AtlasGroup ATLAS_GROUP_GNU_UNIFONT = new AtlasGroup("GNUUnifont", 1 << 12);
|
||||
|
||||
private static final TextureSettings TEXTURE_SETTINGS = new TextureSettings(false);
|
||||
private static final TextureSettings TEXTURE_SETTINGS = new TextureSettings(false, false);
|
||||
|
||||
private static final int BITS_PER_HEX_DIGIT = 4;
|
||||
private static final int PREFIX_LENGTH = "0000:".length();
|
||||
|
@ -48,9 +48,7 @@ public abstract class BasicButton extends Component {
|
||||
this.label = label;
|
||||
|
||||
setLayout(new LayoutAlign(10));
|
||||
if (label != null) {
|
||||
addChild(this.label);
|
||||
}
|
||||
|
||||
setFocusable(true);
|
||||
reassembleAt(ARTrigger.HOVER, ARTrigger.FOCUS, ARTrigger.ENABLE);
|
||||
@ -154,8 +152,4 @@ public abstract class BasicButton extends Component {
|
||||
return label;
|
||||
}
|
||||
|
||||
public boolean hasLabel() {
|
||||
return label != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,16 +18,11 @@
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
|
||||
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) {
|
||||
super(name, label, labelFont);
|
||||
}
|
||||
@ -42,53 +37,26 @@ public class Button extends BasicButton {
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (isPressed() || isHovered() || isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
String state;
|
||||
if (!isEnabled()) {
|
||||
state = "Disabled";
|
||||
} else if (isPressed()) {
|
||||
state = "Pressed";
|
||||
} else if (isHovered()) {
|
||||
state = "Hovered";
|
||||
} else if (isFocused()) {
|
||||
state = "Focused";
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
state = "Inactive";
|
||||
}
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), borderColor);
|
||||
|
||||
// Border
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), ColorScheme.get("Core:ButtonBorder" + state));
|
||||
|
||||
// Inside area
|
||||
|
||||
if (isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (isHovered() && isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
target.fill(
|
||||
getX() + MARGIN,
|
||||
getY() + MARGIN,
|
||||
getWidth() - 2 * MARGIN,
|
||||
getHeight() - 2 * MARGIN,
|
||||
backgroundColor
|
||||
);
|
||||
}
|
||||
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, ColorScheme.get("Core:ButtonFill" + state));
|
||||
|
||||
// Change label font color
|
||||
|
||||
if (hasLabel()) {
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:ButtonText" + state)));
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,6 @@
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
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.Typefaces;
|
||||
@ -43,34 +41,28 @@ public class Checkbox extends BasicButton {
|
||||
int x = getX();
|
||||
int y = getY() + (getHeight() - size) / 2;
|
||||
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
String state;
|
||||
if (!Checkbox.this.isEnabled()) {
|
||||
state = "Disabled";
|
||||
} else if (Checkbox.this.isPressed()) {
|
||||
state = "Pressed";
|
||||
} else if (Checkbox.this.isHovered()) {
|
||||
state = "Hovered";
|
||||
} else if (Checkbox.this.isFocused()) {
|
||||
state = "Focused";
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
state = "Inactive";
|
||||
}
|
||||
target.fill(x, y, size, size, borderColor);
|
||||
|
||||
// Border
|
||||
target.fill(x, y, size, size, ColorScheme.get("Core:CheckboxBorder" + state));
|
||||
|
||||
// Inside area
|
||||
|
||||
if (Checkbox.this.isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (Checkbox.this.isHovered() && Checkbox.this.isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
target.fill(x + 2, y + 2, size - 4, size - 4, backgroundColor);
|
||||
}
|
||||
target.fill(x + 2, y + 2, size - 4, size - 4, ColorScheme.get("Core:CheckboxFill" + state));
|
||||
|
||||
// "Tick"
|
||||
|
||||
if (Checkbox.this.isChecked()) {
|
||||
target.fill(x + 4, y + 4, size - 8, size - 8, Colors.BLUE);
|
||||
target.fill(x + 4, y + 4, size - 8, size - 8, ColorScheme.get("Core:CheckboxCheck" + state));
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,22 +120,21 @@ public class Checkbox extends BasicButton {
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Change label font color
|
||||
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
|
||||
String state;
|
||||
if (!Checkbox.this.isEnabled()) {
|
||||
state = "Disabled";
|
||||
} else if (Checkbox.this.isPressed()) {
|
||||
state = "Pressed";
|
||||
} else if (Checkbox.this.isHovered()) {
|
||||
state = "Hovered";
|
||||
} else if (Checkbox.this.isFocused()) {
|
||||
state = "Focused";
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
state = "Inactive";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
// Change label font color
|
||||
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:CheckboxText" + state)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Progressia
|
||||
* Copyright (C) 2020-2022 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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.jputil.SyntaxException;
|
||||
import ru.windcorp.jputil.chars.StringUtil;
|
||||
import ru.windcorp.progressia.common.resource.Resource;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
import ru.windcorp.progressia.common.util.namespaces.IllegalIdException;
|
||||
import ru.windcorp.progressia.common.util.namespaces.NamespacedUtil;
|
||||
|
||||
public class ColorScheme {
|
||||
|
||||
private static Map<String, Vec4> defaultScheme;
|
||||
|
||||
public static Vec4 get(String key) {
|
||||
Vec4 color = defaultScheme.get(key);
|
||||
if (color == null) {
|
||||
throw CrashReports.report(null, "ColorScheme does not contain color %s", key);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
public static void load(Resource resource) {
|
||||
Map<String, Vec4> tmpMap = new HashMap<>();
|
||||
|
||||
try {
|
||||
for (String fullLine : StringUtil.split(resource.readAsString(), '\n')) {
|
||||
String line = fullLine.trim();
|
||||
if (line.isEmpty() || line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String[] parts = StringUtil.split(line, '=', 2);
|
||||
if (parts[1] == null) {
|
||||
throw new SyntaxException("Could not parse \"" + line + "\": '=' not found");
|
||||
}
|
||||
|
||||
String key = parts[0].trim();
|
||||
checkKeyName(key);
|
||||
if (tmpMap.containsKey(key)) {
|
||||
throw new SyntaxException("Duplicate key " + key);
|
||||
}
|
||||
|
||||
String value = parts[1].trim();
|
||||
Vec4 color;
|
||||
|
||||
if (value.startsWith("#")) {
|
||||
color = parseValueAsHex(value);
|
||||
} else if (value.startsWith("$")) {
|
||||
color = parseValueAsReference(value, tmpMap);
|
||||
} else {
|
||||
throw new SyntaxException("Unknown value format \"" + value + "\"");
|
||||
}
|
||||
|
||||
tmpMap.put(key, color);
|
||||
}
|
||||
} catch (SyntaxException e) {
|
||||
throw CrashReports.report(e, "Could not load ColorScheme from %s", resource);
|
||||
}
|
||||
|
||||
defaultScheme = ImmutableMap.copyOf(tmpMap);
|
||||
}
|
||||
|
||||
private static void checkKeyName(String key) throws SyntaxException {
|
||||
try {
|
||||
NamespacedUtil.checkId(key);
|
||||
} catch (IllegalIdException e) {
|
||||
throw new SyntaxException("Illegal key name \"" + key + "\"", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static int parseHex(String from, int start, int length) {
|
||||
return Integer.parseInt(from.substring(start, start + length), 0x10);
|
||||
}
|
||||
|
||||
private static Vec4 parseValueAsHex(String value) throws SyntaxException {
|
||||
int a = 0xFF;
|
||||
int r, g, b;
|
||||
|
||||
switch (value.length() - 1) {
|
||||
case 3:
|
||||
// #RGB
|
||||
r = parseHex(value, 1, 1) * 0x11;
|
||||
g = parseHex(value, 2, 1) * 0x11;
|
||||
b = parseHex(value, 3, 1) * 0x11;
|
||||
break;
|
||||
case 4:
|
||||
// #ARGB
|
||||
a = parseHex(value, 1, 1) * 0x11;
|
||||
r = parseHex(value, 2, 1) * 0x11;
|
||||
g = parseHex(value, 3, 1) * 0x11;
|
||||
b = parseHex(value, 4, 1) * 0x11;
|
||||
break;
|
||||
case 6:
|
||||
// #RRGGBB
|
||||
r = parseHex(value, 1, 2);
|
||||
g = parseHex(value, 3, 2);
|
||||
b = parseHex(value, 5, 2);
|
||||
break;
|
||||
case 8:
|
||||
// #AARRGGBB
|
||||
a = parseHex(value, 1, 2);
|
||||
r = parseHex(value, 3, 2);
|
||||
g = parseHex(value, 5, 2);
|
||||
b = parseHex(value, 7, 2);
|
||||
break;
|
||||
default:
|
||||
throw new SyntaxException("Could not parse hex color \"" + value + "\": expecting #RGB, #ARGB, #RRGGBB or #AARRGGBB");
|
||||
}
|
||||
|
||||
return new Vec4(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
|
||||
}
|
||||
|
||||
private static Vec4 parseValueAsReference(String value, Map<String, Vec4> map) throws SyntaxException {
|
||||
String otherKey = value.substring(1);
|
||||
checkKeyName(otherKey);
|
||||
if (!map.containsKey(otherKey)) {
|
||||
throw new SyntaxException("Key $" + otherKey + " not found");
|
||||
}
|
||||
return map.get(otherKey);
|
||||
}
|
||||
|
||||
}
|
@ -30,9 +30,7 @@ import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
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.Clip;
|
||||
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.EnableEvent;
|
||||
@ -45,7 +43,6 @@ 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;
|
||||
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.crash.CrashReports;
|
||||
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
|
||||
@ -560,8 +557,10 @@ public class Component extends Named {
|
||||
}
|
||||
|
||||
public void removeInputListener(InputListener<?> listener) {
|
||||
if (inputBus != null) {
|
||||
inputBus.unregister(listener);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean passInputToChildren(InputEvent e) {
|
||||
return true;
|
||||
@ -763,20 +762,6 @@ 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.
|
||||
// * @return a {@link Aligner} initialized to center this component
|
||||
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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() {
|
||||
}
|
||||
|
||||
}
|
@ -33,7 +33,7 @@ public class DynamicLabel extends Component {
|
||||
super(name);
|
||||
this.font = font;
|
||||
this.contents = contents;
|
||||
setPreferredSize(width, font.getHeight("", Float.POSITIVE_INFINITY));
|
||||
setPreferredSize(width, font.getHeight("", Float.POSITIVE_INFINITY) * 2);
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
@ -46,7 +46,7 @@ public class DynamicLabel extends Component {
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
target.pushTransform(new Mat4().identity().translate(getX(), getY(), -1000));
|
||||
target.pushTransform(new Mat4().identity().translate(getX(), getY(), -1000).scale(2));
|
||||
target.addCustomRenderer(font.assembleDynamic(getContentSupplier(), Float.POSITIVE_INFINITY));
|
||||
target.popTransform();
|
||||
}
|
||||
|
@ -25,12 +25,4 @@ public class Group extends Component {
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
public Group(String name, Layout layout, Component... children) {
|
||||
this(name, layout);
|
||||
|
||||
for (Component child : children) {
|
||||
addChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* 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() {
|
||||
currentText = contents.get();
|
||||
currentSize = font.getSize(currentText, maxWidth, null);
|
||||
currentSize = font.getSize(currentText, maxWidth, null).mul(2);
|
||||
requestReassembly();
|
||||
}
|
||||
|
||||
@ -99,8 +99,12 @@ public class Label extends Component {
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
float startX = getX() + font.getAlign() * (getWidth() - currentSize.x);
|
||||
|
||||
target.pushTransform(new Mat4().identity().translate(startX, getY(), 0));
|
||||
target.pushTransform(
|
||||
new Mat4().identity().translate(startX, getY(), 0).scale(2)
|
||||
);
|
||||
|
||||
target.addCustomRenderer(font.assemble(currentText, maxWidth));
|
||||
|
||||
target.popTransform();
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ package ru.windcorp.progressia.client.graphics.gui;
|
||||
import java.util.Objects;
|
||||
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
|
||||
public class Panel extends Group {
|
||||
@ -36,7 +35,7 @@ public class Panel extends Group {
|
||||
}
|
||||
|
||||
public Panel(String name, Layout layout) {
|
||||
this(name, layout, Colors.WHITE, Colors.LIGHT_GRAY);
|
||||
this(name, layout, ColorScheme.get("Core:Background"), ColorScheme.get("Core:Border"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,7 +21,6 @@ import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
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.Typefaces;
|
||||
@ -52,34 +51,28 @@ public class RadioButton extends BasicButton {
|
||||
int x = getX();
|
||||
int y = getY() + (getHeight() - size) / 2;
|
||||
|
||||
// Border
|
||||
|
||||
Vec4 borderColor;
|
||||
if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) {
|
||||
borderColor = Colors.BLUE;
|
||||
String state;
|
||||
if (!RadioButton.this.isEnabled()) {
|
||||
state = "Disabled";
|
||||
} else if (RadioButton.this.isPressed()) {
|
||||
state = "Pressed";
|
||||
} else if (RadioButton.this.isHovered()) {
|
||||
state = "Hovered";
|
||||
} else if (RadioButton.this.isFocused()) {
|
||||
state = "Focused";
|
||||
} else {
|
||||
borderColor = Colors.LIGHT_GRAY;
|
||||
state = "Inactive";
|
||||
}
|
||||
cross(target, x, y, size, borderColor);
|
||||
|
||||
// Border
|
||||
cross(target, x, y, size, ColorScheme.get("Core:RadioButtonBorder" + state));
|
||||
|
||||
// Inside area
|
||||
|
||||
if (RadioButton.this.isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
Vec4 backgroundColor;
|
||||
if (RadioButton.this.isHovered() && RadioButton.this.isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
} else {
|
||||
backgroundColor = Colors.WHITE;
|
||||
}
|
||||
cross(target, x + 2, y + 2, size - 4, backgroundColor);
|
||||
}
|
||||
cross(target, x + 2, y + 2, size - 4, ColorScheme.get("Core:RadioButtonFill" + state));
|
||||
|
||||
// "Tick"
|
||||
|
||||
if (RadioButton.this.isChecked()) {
|
||||
cross(target, x + 4, y + 4, size - 8, Colors.BLUE);
|
||||
cross(target, x + 4, y + 4, size - 8, ColorScheme.get("Core:RadioButtonCheck" + state));
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,8 +139,8 @@ public class RadioButton extends BasicButton {
|
||||
group.selectNext();
|
||||
removeAction(group.listener);
|
||||
group.buttons.remove(this);
|
||||
group.getSelected(); // Clear reference if this was the only button
|
||||
// in the group
|
||||
// Clear reference if this was the only button in the group
|
||||
group.getSelected();
|
||||
}
|
||||
|
||||
this.group = group;
|
||||
@ -183,22 +176,21 @@ public class RadioButton extends BasicButton {
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target) {
|
||||
// Change label font color
|
||||
|
||||
if (isPressed()) {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
|
||||
String state;
|
||||
if (!RadioButton.this.isEnabled()) {
|
||||
state = "Disabled";
|
||||
} else if (RadioButton.this.isPressed()) {
|
||||
state = "Pressed";
|
||||
} else if (RadioButton.this.isHovered()) {
|
||||
state = "Hovered";
|
||||
} else if (RadioButton.this.isFocused()) {
|
||||
state = "Focused";
|
||||
} else {
|
||||
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
|
||||
}
|
||||
state = "Inactive";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postAssembleSelf(RenderTarget target) {
|
||||
// Apply disable tint
|
||||
|
||||
if (!isEnabled()) {
|
||||
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
|
||||
}
|
||||
// Change label font color
|
||||
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:RadioButtonText" + state)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,9 +20,9 @@ package ru.windcorp.progressia.client.graphics.gui.menu;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.GUI;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.gui.ColorScheme;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Label;
|
||||
@ -50,7 +50,7 @@ public class MenuLayer extends GUILayer {
|
||||
|
||||
setCursorPolicy(CursorPolicy.REQUIRE);
|
||||
|
||||
this.background = new Panel(name + ".Background", new LayoutAlign(10), Colors.toVector(0x66000000), null);
|
||||
this.background = new Panel(name + ".Background", new LayoutAlign(10), ColorScheme.get("Core:MenuLayerTint"), null);
|
||||
this.content = content;
|
||||
|
||||
background.addChild(content);
|
||||
@ -76,12 +76,12 @@ public class MenuLayer extends GUILayer {
|
||||
protected void addTitle() {
|
||||
String translationKey = "Layer" + getName() + ".Title";
|
||||
MutableString titleText = new MutableStringLocalized(translationKey);
|
||||
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f);
|
||||
Font titleFont = new Font().deriveBold().withColor(ColorScheme.get("Core:Text")).withAlign(0.5f);
|
||||
|
||||
Label label = new Label(getName() + ".Title", titleFont, titleText);
|
||||
getContent().addChild(label);
|
||||
|
||||
Panel panel = new Panel(getName() + ".Title.Underscore", null, Colors.BLUE, null);
|
||||
Panel panel = new Panel(getName() + ".Title.Underscore", null, ColorScheme.get("Core:Accent"), null);
|
||||
panel.setLayout(new LayoutFill() {
|
||||
@Override
|
||||
public Vec2i calculatePreferredSize(Component c) {
|
||||
|
@ -126,36 +126,6 @@ public class Shapes {
|
||||
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 {
|
||||
|
||||
private final ShapeRenderProgram program;
|
||||
@ -345,108 +315,4 @@ 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
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ public class Atlases {
|
||||
}
|
||||
}
|
||||
|
||||
private static final TextureSettings SETTINGS = new TextureSettings(false);
|
||||
private static final TextureSettings SETTINGS = new TextureSettings(false, false);
|
||||
|
||||
private static final Map<Resource, Sprite> LOADED = new HashMap<>();
|
||||
private static final Multimap<AtlasGroup, Atlas> ATLASES = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||
|
@ -28,7 +28,7 @@ import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
|
||||
public class SimpleTextures {
|
||||
|
||||
private static final TextureSettings SETTINGS = new TextureSettings(false);
|
||||
private static final TextureSettings SETTINGS = new TextureSettings(false, false);
|
||||
|
||||
private static final Map<Resource, Texture> TEXTURES = new HashMap<>();
|
||||
|
||||
|
@ -23,7 +23,7 @@ import static org.lwjgl.opengl.GL12.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
class TextureData {
|
||||
public class TextureData {
|
||||
|
||||
private final ByteBuffer data;
|
||||
|
||||
|
@ -42,8 +42,16 @@ public class TextureLoader {
|
||||
int width = readResult.getWidth();
|
||||
int height = readResult.getHeight();
|
||||
|
||||
int bufferWidth = BinUtil.roundToGreaterPowerOf2(width);
|
||||
int bufferHeight = BinUtil.roundToGreaterPowerOf2(height);
|
||||
int bufferWidth;
|
||||
int bufferHeight;
|
||||
|
||||
if (settings.allocateExactBuffer()) {
|
||||
bufferWidth = width;
|
||||
bufferHeight = height;
|
||||
} else {
|
||||
bufferWidth = BinUtil.roundToGreaterPowerOf2(width);
|
||||
bufferHeight = BinUtil.roundToGreaterPowerOf2(height);
|
||||
}
|
||||
|
||||
WritableRaster raster = TextureUtil.createRaster(
|
||||
bufferWidth,
|
||||
|
@ -21,13 +21,19 @@ package ru.windcorp.progressia.client.graphics.texture;
|
||||
public class TextureSettings {
|
||||
|
||||
private final boolean isFiltered;
|
||||
private final boolean allocateExactBuffer;
|
||||
|
||||
public TextureSettings(boolean isFiltered) {
|
||||
public TextureSettings(boolean isFiltered, boolean allocateExactBuffer) {
|
||||
this.isFiltered = isFiltered;
|
||||
this.allocateExactBuffer = allocateExactBuffer;
|
||||
}
|
||||
|
||||
public boolean isFiltered() {
|
||||
return isFiltered;
|
||||
}
|
||||
|
||||
public boolean allocateExactBuffer() {
|
||||
return allocateExactBuffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,22 +18,17 @@
|
||||
|
||||
package ru.windcorp.progressia.client.graphics.world;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
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.entity.EntityRenderable;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
|
||||
|
||||
public class LocalPlayer {
|
||||
|
||||
private final Client client;
|
||||
|
||||
private long entityId = EntityData.NULL_ENTITY_ID;
|
||||
private EntityDataPlayer lastKnownEntity = null;
|
||||
private EntityData lastKnownEntity = null;
|
||||
|
||||
private final Selection selection = new Selection();
|
||||
|
||||
@ -64,32 +59,19 @@ public class LocalPlayer {
|
||||
return getEntity() != null;
|
||||
}
|
||||
|
||||
public EntityDataPlayer getEntity() {
|
||||
public EntityData getEntity() {
|
||||
if (!hasEntityId()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
EntityData entity = getClient().getWorld().getData().getEntity(getEntityId());
|
||||
EntityDataPlayer playerEntity;
|
||||
|
||||
if (entity == null || entity instanceof EntityDataPlayer) {
|
||||
playerEntity = (EntityDataPlayer) entity;
|
||||
} else {
|
||||
LogManager.getLogger().warn(
|
||||
"Entity ID of local player is {}, but the entity is not an EntityDataPlayer: {}",
|
||||
EntityData.formatEntityId(getEntityId()),
|
||||
entity
|
||||
);
|
||||
playerEntity = null;
|
||||
if (entity != lastKnownEntity) {
|
||||
getClient().onLocalPlayerEntityChanged(entity, lastKnownEntity);
|
||||
this.lastKnownEntity = entity;
|
||||
}
|
||||
|
||||
if (playerEntity != lastKnownEntity) {
|
||||
ClientEvent event = new NewLocalEntityEvent.Immutable(getClient(), playerEntity, lastKnownEntity);
|
||||
this.lastKnownEntity = playerEntity;
|
||||
getClient().postEvent(event);
|
||||
}
|
||||
|
||||
return playerEntity;
|
||||
return entity;
|
||||
}
|
||||
|
||||
public Selection getSelection() {
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* 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)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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';
|
||||
}
|
||||
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
}
|
@ -1,217 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
@ -42,7 +42,7 @@ public class EntityRenderRegistry extends NamespacedInstanceRegistry<EntityRende
|
||||
ResourceManager.getTextureResource(
|
||||
"entities/" + name
|
||||
),
|
||||
new TextureSettings(false)
|
||||
new TextureSettings(false, false)
|
||||
).getData()
|
||||
);
|
||||
} catch (IOException e) {
|
||||
|
@ -19,18 +19,45 @@
|
||||
package ru.windcorp.progressia.client.world.entity;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.world.UpdatingRenderable;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
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.generic.EntityGeneric;
|
||||
|
||||
public abstract class EntityRenderable extends UpdatingRenderable implements EntityGeneric {
|
||||
public abstract class EntityRenderable implements Renderable, EntityGeneric {
|
||||
|
||||
private final EntityData data;
|
||||
|
||||
private long stateComputedForFrame = -1;
|
||||
|
||||
public EntityRenderable(EntityData 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() {
|
||||
return data;
|
||||
}
|
||||
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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.world.UpdatingRenderable;
|
||||
import ru.windcorp.progressia.common.world.item.ItemData;
|
||||
|
||||
public abstract class ItemRenderable extends UpdatingRenderable {
|
||||
|
||||
private final ItemData data;
|
||||
|
||||
public ItemRenderable(ItemData data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public ItemData getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
@ -65,8 +65,6 @@ public class Units {
|
||||
|
||||
// Volume
|
||||
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_MILLIMETERS = MILLIMETERS * MILLIMETERS * MILLIMETERS;
|
||||
public static final float CUBIC_KILOMETERS = KILOMETERS * KILOMETERS * KILOMETERS;
|
||||
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* 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,13 +22,10 @@ import gnu.trove.map.TIntIntMap;
|
||||
import gnu.trove.map.TIntObjectMap;
|
||||
import gnu.trove.map.hash.TIntIntHashMap;
|
||||
import gnu.trove.map.hash.TIntObjectHashMap;
|
||||
import gnu.trove.set.TIntSet;
|
||||
import gnu.trove.set.hash.TIntHashSet;
|
||||
|
||||
public class HashMapStateStorage extends StateStorage {
|
||||
|
||||
private final TIntIntMap ints = new TIntIntHashMap();
|
||||
private final TIntSet booleans = new TIntHashSet();
|
||||
private final TIntObjectMap<Object> objects = new TIntObjectHashMap<>();
|
||||
|
||||
@Override
|
||||
@ -41,20 +38,6 @@ public class HashMapStateStorage extends StateStorage {
|
||||
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
|
||||
public Object getObject(int index) {
|
||||
return objects.get(index);
|
||||
|
@ -85,21 +85,6 @@ 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 final ObjectCodec<T> codec;
|
||||
@ -138,11 +123,6 @@ public class InspectingStatefulObjectLayout
|
||||
return new Int();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean ofBoolean() {
|
||||
return new Boolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
||||
return new Obj<T>(codec, defaultValue);
|
||||
|
@ -21,13 +21,11 @@ package ru.windcorp.progressia.common.state;
|
||||
public class OptimizedStateStorage extends StateStorage {
|
||||
|
||||
private final int[] ints;
|
||||
private final boolean[] booleans;
|
||||
private final Object[] objects;
|
||||
|
||||
public OptimizedStateStorage(PrimitiveCounters sizes) {
|
||||
this.ints = sizes.getInts() == 0 ? null : new int[sizes.getInts()];
|
||||
this.booleans = sizes.getBooleans() == 0 ? null : new boolean[sizes.getBooleans()];
|
||||
this.objects = sizes.getObjects() == 0 ? null : new Object[sizes.getObjects()];
|
||||
this.ints = new int[sizes.getInts()];
|
||||
this.objects = new Object[sizes.getObjects()];
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -40,16 +38,6 @@ public class OptimizedStateStorage extends StateStorage {
|
||||
ints[index] = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(int index) {
|
||||
return booleans[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoolean(int index, boolean value) {
|
||||
booleans[index] = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getObject(int index) {
|
||||
return objects[index];
|
||||
|
@ -75,16 +75,6 @@ public class OptimizedStatefulObjectLayout
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean ofBoolean() {
|
||||
return new Boolean() {
|
||||
@Override
|
||||
public BooleanStateField build() {
|
||||
return (BooleanStateField) result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue) {
|
||||
return new Obj<T>() {
|
||||
|
@ -21,7 +21,6 @@ package ru.windcorp.progressia.common.state;
|
||||
class PrimitiveCounters {
|
||||
|
||||
private int ints = 0;
|
||||
private int booleans = 0;
|
||||
private int objects = 0;
|
||||
|
||||
public PrimitiveCounters() {
|
||||
@ -29,7 +28,6 @@ class PrimitiveCounters {
|
||||
|
||||
public PrimitiveCounters(PrimitiveCounters copyFrom) {
|
||||
this.ints = copyFrom.ints;
|
||||
this.booleans = copyFrom.booleans;
|
||||
this.objects = copyFrom.objects;
|
||||
}
|
||||
|
||||
@ -41,14 +39,6 @@ class PrimitiveCounters {
|
||||
return this.ints++;
|
||||
}
|
||||
|
||||
public int getBooleans() {
|
||||
return booleans;
|
||||
}
|
||||
|
||||
public int getBooleansThenIncrement() {
|
||||
return this.booleans++;
|
||||
}
|
||||
|
||||
public int getObjects() {
|
||||
return objects;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ package ru.windcorp.progressia.common.state;
|
||||
public interface StateChanger {
|
||||
|
||||
void setInt(IntStateField field, int value);
|
||||
void setBoolean(BooleanStateField field, boolean value);
|
||||
<T> void setObject(ObjectStateField<T> field, T value);
|
||||
|
||||
}
|
||||
|
@ -29,18 +29,12 @@ public interface StateFieldBuilder {
|
||||
IntStateField build();
|
||||
}
|
||||
|
||||
public static interface Boolean {
|
||||
BooleanStateField build();
|
||||
}
|
||||
|
||||
public static interface Obj<T> {
|
||||
ObjectStateField<T> build();
|
||||
}
|
||||
|
||||
Int ofInt();
|
||||
|
||||
Boolean ofBoolean();
|
||||
|
||||
<T> Obj<T> of(ObjectCodec<T> codec, Supplier<T> defaultValue);
|
||||
|
||||
default <T> Obj<T> of(Class<T> clazz, Supplier<T> defaultValue) {
|
||||
|
@ -24,10 +24,6 @@ public abstract class StateStorage {
|
||||
|
||||
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 void setObject(int index, Object object);
|
||||
|
@ -43,16 +43,6 @@ public class StatefulObjectRegistry<T extends StatefulObject> {
|
||||
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 {
|
||||
|
||||
private final Factory<T> factory;
|
||||
@ -121,8 +111,4 @@ public class StatefulObjectRegistry<T extends StatefulObject> {
|
||||
registry.register(new Type<>(id, factory));
|
||||
}
|
||||
|
||||
public void register(String id, IdFactory<T> factory) {
|
||||
register(id, () -> factory.build(id));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,27 +15,26 @@
|
||||
* 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;
|
||||
package ru.windcorp.progressia.common.util.crash.providers;
|
||||
|
||||
public class ItemDataSimple extends ItemData {
|
||||
import java.util.Map;
|
||||
|
||||
private final float mass;
|
||||
private final float volume;
|
||||
import ru.windcorp.progressia.Progressia;
|
||||
import ru.windcorp.progressia.common.util.crash.ContextProvider;
|
||||
|
||||
public ItemDataSimple(String id, float mass, float volume) {
|
||||
super(id);
|
||||
this.mass = mass;
|
||||
this.volume = volume;
|
||||
public class VersionProvider implements ContextProvider {
|
||||
|
||||
@Override
|
||||
public void provideContext(Map<String, String> output) {
|
||||
output.put("Version", Progressia.getVersion());
|
||||
output.put("Git commit", Progressia.getGitCommit());
|
||||
output.put("Git branch", Progressia.getGitBranch());
|
||||
output.put("Build ID", Progressia.getBuildId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMass() {
|
||||
return mass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVolume() {
|
||||
return volume;
|
||||
public String getName() {
|
||||
return "Version Provider";
|
||||
}
|
||||
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user