Compare commits

..

11 Commits

Author SHA1 Message Date
5472576606
Fixed a compilation issue under Windows and MacOS, added safeguards 2022-01-15 19:45:53 +03:00
4a6aa5dbf7
Set source code encoding in build.gradle 2022-01-14 13:28:02 +03:00
c3bbc8661d
Added GLFW error handling and fixed a bug
- GLFW errors are now detected
- Added IntConstantsMap
- Removed window maximization on init
2022-01-14 00:28:52 +03:00
eadc85bfda
Fixed GitHub issue forms 2022-01-12 21:23:53 +03:00
ca8ac6e7b6
Added issue forms for GitHub 2022-01-12 17:23:46 +03:00
0638794a80
Added ColorScheme to manage GUI colors; changed BG color slightly 2022-01-12 12:09:55 +03:00
e6e55a6c40
Fixed 'HEAD' in detected Git branch on Jenkins 2022-01-10 23:59:09 +03:00
57a86b544e
Fixed dependency detection for external tools 2022-01-10 21:19:31 +03:00
b18eac44b8
Updated all dependencies
- Updated LWJGL to 3.3.0
  - Targets windows-arm64 and macos-arm64 are now available
- Updated Guava to 31.0.1
- Updated Log4j to 2.17.1
2022-01-10 19:54:14 +03:00
c3c8a6e5e0
Updated Gradle wrapper to 7.3.3 2022-01-09 21:09:02 +03:00
fe01e1b81c
Fixed first-time packaging issue in build script 2022-01-09 21:02:56 +03:00
45 changed files with 1253 additions and 802 deletions

49
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View 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
View 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
View 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

View File

@ -42,6 +42,16 @@ compileJava {
/*
* Set encoding
*/
compileJava {
options.encoding = 'utf8'
}
/* /*
* Dependencies * Dependencies
*/ */
@ -60,7 +70,7 @@ repositories {
dependencies { dependencies {
// Google Guava // Google Guava
// A generic utilities library // A generic utilities library
implementation 'com.google.guava:guava:30.0-jre' implementation 'com.google.guava:guava:31.0.1-jre'
// Trove4j // Trove4j
// Provides optimized Collections for primitive types // Provides optimized Collections for primitive types
@ -73,8 +83,8 @@ dependencies {
// Log4j // Log4j
// A logging library // A logging library
implementation 'org.apache.logging.log4j:log4j-api:2.17.0' implementation 'org.apache.logging.log4j:log4j-api:2.17.1'
implementation 'org.apache.logging.log4j:log4j-core:2.17.0' implementation 'org.apache.logging.log4j:log4j-core:2.17.1'
// JUnit // JUnit
// A unit-testing library // A unit-testing library
@ -163,49 +173,85 @@ task resolveVersion {
description 'Resolves version information from Git repository or project properties.' description 'Resolves version information from Git repository or project properties.'
doFirst { doFirst {
project.ext.commit = System.env.GIT_COMMIT
project.ext.branch = System.env.GIT_BRANCH
try { try {
def git = Grgit.open(dir: project.projectDir) def git = Grgit.open(dir: project.projectDir)
project.ext.commit = git.head().id project.ext.commit = commit ?: git.head().id
project.ext.branch = git.branch.current().name project.ext.branch = branch ?: git.branch.current().name
if (project.version != 'unspecified') { if (project.version != 'unspecified') {
// Leave version as-is // Leave version as-is
return
}
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 { } else {
project.version = version_parseVersion(tag.name, tag.commit != git.head()) // 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) { } catch (org.eclipse.jgit.errors.RepositoryNotFoundException e) {
if (project.version == 'unspecified') project.version = 'dev' if (project.version == 'unspecified') project.version = 'dev'
project.ext.commit = '-' project.ext.commit = commit ?: '-'
project.ext.branch = '-' 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 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
} }
}
doLast { if (branch.contains '/') {
// Strip remote - no one wants that
project.ext.branch = branch.takeAfter '/'
}
if (!project.hasProperty('buildId')) { if (!project.hasProperty('buildId')) {
project.ext.buildId = '-' project.ext.buildId = '-'
} }
} }
doLast {
}
}
/*
* Apply LWJGL logic
*/
apply from: 'build_logic/lwjgl.gradle'
/*
* Copy libraries into build/libs/lib directory, next to Progressia.jar
*/
task exportLibs(type: Sync) {
description 'Copies runtime libraries into a subdirectory next to the output JAR.'
jar.dependsOn exportLibs
dependsOn lwjgl_addNativesToRuntimeOnly
// from defined in configureManifest
into 'build/libs/lib'
} }
@ -219,11 +265,16 @@ task configureManifest {
jar.dependsOn configureManifest jar.dependsOn configureManifest
dependsOn resolveVersion dependsOn resolveVersion
dependsOn lwjgl_addNativesToRuntimeOnly
doFirst { doFirst {
def classPath = project.lwjgl.replaceNativesIn(configurations.runtimeClasspath)
exportLibs.from classPath
jar.manifest.attributes( jar.manifest.attributes(
'Main-Class': 'ru.windcorp.progressia.client.ProgressiaClientMain', 'Main-Class': 'ru.windcorp.progressia.client.ProgressiaClientMain',
'Class-Path': configurations.runtimeClasspath.collect { "lib/${it.name}" } .join(' '), 'Class-Path': classPath.collect { "lib/${java.net.URLEncoder.encode it.name}" } .join(' '),
'Specification-Title': 'Progressia', 'Specification-Title': 'Progressia',
@ -238,28 +289,6 @@ task configureManifest {
/*
* Copy libraries into buil/libs/lib directory, next to Progressia.jar
*/
task exportLibs(type: Sync) {
description 'Copies runtime libraries into a subdirectory next to the output JAR.'
jar.dependsOn exportLibs
from configurations.runtimeClasspath
into 'build/libs/lib'
}
/*
* Apply LWJGL logic
*/
apply from: 'build_logic/lwjgl.gradle'
/* /*
* Packaging working directory configuration * Packaging working directory configuration
*/ */
@ -267,64 +296,40 @@ apply from: 'build_logic/lwjgl.gradle'
import java.nio.file.* import java.nio.file.*
import java.nio.file.attribute.* import java.nio.file.attribute.*
task createPackagingDirs() { task deletePackagingDirs(type: Delete) {
description 'Resets build/tmp/packaging directory.' description 'Deletes build/tmp/packaging directory.'
followSymlinks = false
doLast { delete 'build/tmp/packaging'
def tmpDir = buildDir.toPath().resolve 'tmp/packaging'
def nuke = new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
if (e == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
} else {
// directory iteration failed
throw e;
}
}
}
// Fckn nuke tmpDir from orbit
// I'm so done with deleting file trees in Java/Groovy/whatever
// ...Not using File.deleteDir() because the latter recurses into symlinks, and we don't want to wipe build/libs/lib
if (Files.exists(tmpDir)) {
Files.walkFileTree tmpDir, nuke
}
Files.createDirectories tmpDir.resolve('workingDir')
Files.createDirectories buildDir.toPath().resolve('packages')
}
} }
task linkBuildOutputForPackaging() { task linkBuildOutputForPackaging {
description 'Symlinks the contents of build/libs into packaging working directory.' description 'Symlinks the contents of build/libs into packaging working directory.'
dependsOn build dependsOn build
dependsOn createPackagingDirs mustRunAfter deletePackagingDirs
onlyIf { preparePackaging.ext.mode == 'symlink' } 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 { doLast {
def from = buildDir.toPath().resolve 'libs' def fromPath = Paths.get from
def into = buildDir.toPath().resolve "tmp/packaging/workingDir/${preparePackaging.ext.buildDest}" def intoPath = Paths.get into
Files.createDirectories into Files.createDirectories intoPath
Files.list(from).each { Files.list(fromPath).each {
def fileName = it.fileName.toString() def fileName = it.fileName.toString()
// Exclude all JARs except the current one // Exclude all JARs except the current one
if (fileName ==~ "${project.name}.*\\.jar" && fileName != tasks.jar.archiveFileName.get()) if (fileName ==~ "${project.name}.*\\.jar" && fileName != tasks.jar.archiveFileName.get())
return return
Files.createSymbolicLink into.resolve(it.fileName), it Files.createSymbolicLink intoPath.resolve(it.fileName), intoPath.relativize(it)
} }
} }
} }
@ -333,7 +338,7 @@ task copyBuildOutputForPackaging(type: Copy) {
description 'Copies the contents of build/libs into packaging working directory.' description 'Copies the contents of build/libs into packaging working directory.'
dependsOn build dependsOn build
dependsOn createPackagingDirs mustRunAfter deletePackagingDirs
onlyIf { preparePackaging.ext.mode == 'copy' } onlyIf { preparePackaging.ext.mode == 'copy' }
@ -348,7 +353,7 @@ task preparePackaging {
preparePackaging.ext.buildDest = '' preparePackaging.ext.buildDest = ''
preparePackaging.ext.mode = 'symlink' preparePackaging.ext.mode = 'symlink'
dependsOn createPackagingDirs dependsOn deletePackagingDirs
dependsOn linkBuildOutputForPackaging dependsOn linkBuildOutputForPackaging
dependsOn copyBuildOutputForPackaging dependsOn copyBuildOutputForPackaging
} }

View File

@ -6,14 +6,14 @@
project.ext.lwjgl = new HashMap<>() project.ext.lwjgl = new HashMap<>()
// Version of LWJGL // Version of LWJGL
lwjgl.version = '3.2.3' lwjgl.version = '3.3.0'
/* /*
* Target platforms for current operation. * Target platforms for current operation.
* This is filled in by the request* tasks. This is referenced by the addLwjglNatives task. * This is filled in by the request* tasks. This is referenced by the addLwjglNatives task.
* When empty, current platform is assumed. * When empty, current platform is assumed.
*/ */
lwjgl.targets = new HashSet<>() lwjgl.targets = new HashSet<String>()
// LWJGL components. To include org.lwjgl:lwjgl-foobar, add 'foobar' to this list. // LWJGL components. To include org.lwjgl:lwjgl-foobar, add 'foobar' to this list.
lwjgl.libraries = [ lwjgl.libraries = [
@ -33,34 +33,49 @@ switch (OperatingSystem.current()) {
: 'linux' : 'linux'
break break
case OperatingSystem.MAC_OS: case OperatingSystem.MAC_OS:
lwjgl.localArch = 'macos' lwjgl.localArch = System.getProperty('os.arch').startsWith('aarch64') ? 'macos-arm64' : 'macos'
break break
case OperatingSystem.WINDOWS: case OperatingSystem.WINDOWS:
lwjgl.localArch = System.getProperty('os.arch').contains('64') ? 'windows' : 'windows-x86' def osArch = System.getProperty('os.arch')
lwjgl.localArch = osArch.contains('64')
? "windows${osArch.startsWith('aarch64') ? '-arm64' : ''}"
: 'windows-x86'
break 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 // Declare pure-Java dependencies
dependencies { dependencies {
// BOM // BOM
implementation platform("org.lwjgl:lwjgl-bom:${lwjgl.version}")
def bom = platform("org.lwjgl:lwjgl-bom:${lwjgl.version}")
implementation bom
lwjglNatives bom
// Core // Core
implementation 'org.lwjgl:lwjgl' implementation 'org.lwjgl:lwjgl'
// Local natives for core
runtimeOnly "org.lwjgl:lwjgl::natives-${lwjgl.localArch}"
// Components // Components
lwjgl.libraries.each { implementation "org.lwjgl:lwjgl-$it" } 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 runtimeOnly configuration * Adds LWJGL native libraries to lwjglNatives configuration
*/ */
task lwjgl_addNativesToRuntimeOnly { task lwjgl_addNativesToRuntimeOnly {
// Make sure runtimeOnly has not been resolved
compileJava.dependsOn lwjgl_addNativesToRuntimeOnly
configureManifest.dependsOn lwjgl_addNativesToRuntimeOnly
exportLibs.dependsOn lwjgl_addNativesToRuntimeOnly
doFirst { doFirst {
if (project.hasProperty('forceTargets')) { if (project.hasProperty('forceTargets')) {
try { try {
@ -82,17 +97,34 @@ task lwjgl_addNativesToRuntimeOnly {
logger.info 'Adding LWJGL native dependencies for platforms: {}', lwjgl.targets.sort().join(', ') 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 { dependencies {
lwjgl.targets.each { target -> lwjgl.targets.each { target ->
runtimeOnly "org.lwjgl:lwjgl::natives-$target" lwjglNatives "org.lwjgl:lwjgl::natives-$target"
lwjgl.libraries.each { lib -> lwjgl.libraries.each { lib ->
runtimeOnly "org.lwjgl:lwjgl-$lib::natives-$target" 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 { task requestCrossPlatformDependencies {
description 'Adds LWJGL natives for all available platforms.' description 'Adds LWJGL natives for all available platforms.'
@ -113,5 +145,5 @@ def requestTask(String name, String... targets) {
} }
requestTask 'Linux', 'linux', 'linux-arm32', 'linux-arm64' requestTask 'Linux', 'linux', 'linux-arm32', 'linux-arm64'
requestTask 'Windows', 'windows', 'windows-x86' requestTask 'Windows', 'windows', 'windows-arm64', 'windows-x86'
requestTask 'MacOS', 'macos' requestTask 'MacOS', 'macos', 'macos-arm64'

View File

@ -15,7 +15,7 @@ task packageDeb_configure() {
preparePackaging.mustRunAfter packageDeb_configure preparePackaging.mustRunAfter packageDeb_configure
doLast { doLast {
tasks.preparePackaging.ext.buildDest = '/usr/share/progressia' tasks.preparePackaging.ext.buildDest = 'usr/share/progressia'
tasks.preparePackaging.ext.mode = 'copy' tasks.preparePackaging.ext.mode = 'copy'
} }
} }
@ -31,6 +31,10 @@ task packageDeb(type: Exec) {
dependsOn packageDeb_processResources dependsOn packageDeb_processResources
doFirst {
mkdir 'build/packages'
}
executable 'dpkg-deb' executable 'dpkg-deb'
args '--root-owner-group' args '--root-owner-group'
args '--build', 'build/tmp/packaging/workingDir' args '--build', 'build/tmp/packaging/workingDir'

View File

@ -40,6 +40,10 @@ task packageNsis(type: Exec) {
dependsOn packageNsis_generateIcon dependsOn packageNsis_generateIcon
dependsOn packageNsis_generateLeftSide dependsOn packageNsis_generateLeftSide
doFirst {
mkdir 'build/packages'
}
executable 'makensis' executable 'makensis'
args '-NOCONFIG' args '-NOCONFIG'
args "-DPROJECT_NAME=${project.name}" args "-DPROJECT_NAME=${project.name}"

View File

@ -36,6 +36,10 @@ task packageZip(type: Zip) {
archiveVersion = project.version archiveVersion = project.version
} }
doFirst {
mkdir 'build/packages'
}
from 'build/tmp/packaging/workingDir' from 'build/tmp/packaging/workingDir'
destinationDirectory = file('build/packages') destinationDirectory = file('build/packages')
} }

View File

@ -143,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 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: 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; - `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; - `requestWindowsDependencies` requests that `natives-windows`, `natives-windows-arm64` and `natives-windows-x86` binaries are included;
- `requestMacOSDependencies` requests that `natives-macos` 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 These requests can be applied in any combination. For example, the following command produces a build containing only
GNU/Linux and Windows natives: GNU/Linux and Windows natives:

View File

@ -12,8 +12,8 @@ This document is a user's reference for the build script of Progressia. For a be
- `packageDeb` creates a Debian package. 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. - `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. - `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. - `requestWindowsDependencies` requests that `natives-windows`, `natives-windows-arm64` and `natives-windows-x86` binaries are included when building.
- `requestMacOSDependencies` requests that `natives-macos` 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. - `requestCrossPlatformDependencies` requests that all binaries are included when building.
To execute a task, run `./gradlew <task-name>`. To execute a task, run `./gradlew <task-name>`.
@ -60,14 +60,21 @@ In all other cases, a fallback dummy value is used for version, appended with bu
### Git metadata ### Git metadata
Git commit and Git branch are correspond to the state of the local Git repository, if any. In case Git metadata is Git commit is determined from `GIT_COMMIT` environment variable if it exists, or the state of the local Git
unavailable, `-` fallback is used for both fields. 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
Build ID uniquely identifies artifacts produced by automated build systems. For example, builds executed by WindCorp Build ID uniquely identifies artifacts produced by automated build systems. Build ID must be provided explicitly; it
Jenkins suite have build IDs like `WJ3` or `WJ142`. Build ID must be provided explicitly; it is `-` unless specified is `-` unless specified otherwise.
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 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` line argument `-PbuildId=WJ3`
@ -93,11 +100,13 @@ detected current architecture.
### Available targets ### Available targets
| Name | Task | | Name | Task |
|---------------|------------------------------| |-----------------|------------------------------|
| `linux` | `requestLinuxDependencies` | | `linux` | `requestLinuxDependencies` |
| `linux-arm32` | `requestLinuxDependencies` | | `linux-arm32` | `requestLinuxDependencies` |
| `linux-arm64` | `requestLinuxDependencies` | | `linux-arm64` | `requestLinuxDependencies` |
| `windows` | `requestWindowsDependencies` | | `windows` | `requestWindowsDependencies` |
| `windows-x86` | `requestWindowsDependencies` | | `windows-arm64` | `requestWindowsDependencies` |
| `macos` | `requestMacOSDependencies` | | `windows-x86` | `requestWindowsDependencies` |
| `macos` | `requestMacOSDependencies` |
| `macos-arm64` | `requestMacOSDependencies` |

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

269
gradlew vendored
View File

@ -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"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with 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 # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" 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. # 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"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 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." location of your Java installation."
fi fi
else 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. 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 Please set the JAVA_HOME variable in your environment to match the
@ -105,79 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
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" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --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 # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 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" "$@" exec "$JAVACMD" "$@"

25
gradlew.bat vendored
View File

@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% 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. @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" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 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_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail 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 :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @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 :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@ -1 +0,0 @@
22:26:25.948 [Music Thread ] WARN ru.windcorp.progressia.test.TestMusicPlayer > No music found

View 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);
}
}

View 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
)
);
}
}
}

View File

@ -25,6 +25,7 @@ import ru.windcorp.progressia.client.graphics.backend.RenderTaskQueue;
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram; import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader; import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader;
import ru.windcorp.progressia.client.graphics.font.Typefaces; import ru.windcorp.progressia.client.graphics.font.Typefaces;
import ru.windcorp.progressia.client.graphics.gui.ColorScheme;
import ru.windcorp.progressia.client.graphics.texture.Atlases; import ru.windcorp.progressia.client.graphics.texture.Atlases;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram; import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.localization.Localizer; import ru.windcorp.progressia.client.localization.Localizer;
@ -51,6 +52,7 @@ public class ClientProxy implements Proxy {
throw CrashReports.report(e, "ClientProxy failed"); throw CrashReports.report(e, "ClientProxy failed");
} }
ColorScheme.load(ResourceManager.getResource("assets/default.colorScheme"));
Localizer.getInstance().setLanguage("en-US"); Localizer.getInstance().setLanguage("en-US");
TestContent.registerContent(); TestContent.registerContent();

View File

@ -34,13 +34,7 @@ public class Colors {
DEBUG_BLUE = toVector(0xFF0000FF), DEBUG_BLUE = toVector(0xFF0000FF),
DEBUG_CYAN = toVector(0xFF00FFFF), DEBUG_CYAN = toVector(0xFF00FFFF),
DEBUG_MAGENTA = toVector(0xFFFF00FF), DEBUG_MAGENTA = toVector(0xFFFF00FF),
DEBUG_YELLOW = toVector(0xFFFFFF00), DEBUG_YELLOW = toVector(0xFFFFFF00);
LIGHT_GRAY = toVector(0xFFCBCBD0),
BLUE = toVector(0xFF37A2E6),
HOVER_BLUE = toVector(0xFFC3E4F7),
DISABLED_GRAY = toVector(0xFFE5E5E5),
DISABLED_BLUE = toVector(0xFFB2D8ED);
public static Vec4 toVector(int argb) { public static Vec4 toVector(int argb) {
return toVector(argb, new Vec4()); return toVector(argb, new Vec4());

View File

@ -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);
}
}

View File

@ -24,6 +24,7 @@ import static org.lwjgl.system.MemoryUtil.*;
import java.io.IOException; import java.io.IOException;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWImage; import org.lwjgl.glfw.GLFWImage;
import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL;
@ -55,6 +56,7 @@ class LWJGLInitializer {
setupWindowCallbacks(); setupWindowCallbacks();
glfwShowWindow(GraphicsBackend.getWindowHandle()); glfwShowWindow(GraphicsBackend.getWindowHandle());
GraphicsBackend.onFrameResized(GraphicsBackend.getWindowHandle(), 800, 600);
} }
private static void checkEnvironment() { private static void checkEnvironment() {
@ -62,8 +64,12 @@ class LWJGLInitializer {
} }
private static void initializeGLFW() { private static void initializeGLFW() {
// TODO Do GLFW error handling: check glfwInit, setup error callback GLFWErrorCallback.create(new GLFWErrorHandler()::onError).set();
glfwInit();
if (!glfwInit()) {
throw CrashReports.report(null, "GLFW could not be initialized: glfwInit() has failed");
}
GraphicsBackend.setGLFWInitialized(true); GraphicsBackend.setGLFWInitialized(true);
} }
@ -71,17 +77,13 @@ class LWJGLInitializer {
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE); glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
long handle = glfwCreateWindow( String windowTitle = Progressia.getName() + " " + Progressia.getFullerVersion();
800, long handle = glfwCreateWindow(800, 600, windowTitle, NULL, NULL);
600,
Progressia.getName() + " " + Progressia.getFullerVersion(),
NULL,
NULL
);
// TODO Check that handle != NULL if (handle == 0) {
throw CrashReports.report(null, "Could not create game window");
}
GraphicsBackend.setWindowHandle(handle); GraphicsBackend.setWindowHandle(handle);
@ -95,8 +97,8 @@ class LWJGLInitializer {
} }
private static void createWindowIcons() { private static void createWindowIcons() {
if (glfwGetVersionString().toLowerCase().contains("wayland")) { if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
// glfwSetWindowIcon is not supported on Wayland // Wayland does not support changing window icons
return; return;
} }

View File

@ -1,28 +0,0 @@
package ru.windcorp.progressia.client.graphics.gui;
import glm.mat._4.Mat4;
import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.texture.Texture;
public class Background extends GUILayer {
protected Texture backgroundTexture;
public Background(String name, Layout layout, Texture inTexture) {
super(name, layout);
backgroundTexture = inTexture;
}
@Override
protected void assemble(RenderTarget target) {
getRoot().setBounds(0, 0, getWidth(), getHeight());
getRoot().invalidate();
target.pushTransform(new Mat4(1).translate(new Vec3(0,0,500)));
target.drawTexture(0, 0, getWidth(), getHeight(), backgroundTexture);
target.popTransform();
getRoot().assemble(target);
}
}

View File

@ -18,15 +18,9 @@
package ru.windcorp.progressia.client.graphics.gui; 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.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.Colors;
/** Class for a traditional button that gets clicked to activate
*
* @author opfromthestart
*/
public class Button extends BasicButton { public class Button extends BasicButton {
public Button(String name, String label, Font labelFont) { public Button(String name, String label, Font labelFont) {
@ -43,43 +37,26 @@ public class Button extends BasicButton {
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
// Border String state;
if (!isEnabled()) {
Vec4 borderColor; state = "Disabled";
if (isPressed() || isHovered() || isFocused()) { } else if (isPressed()) {
borderColor = Colors.BLUE; state = "Pressed";
} else if (isHovered()) {
state = "Hovered";
} else if (isFocused()) {
state = "Focused";
} else { } 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 // Inside area
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, ColorScheme.get("Core:ButtonFill" + state));
if (!isPressed()) {
Vec4 backgroundColor;
if (isHovered() && isEnabled()) {
backgroundColor = Colors.HOVER_BLUE;
} else {
backgroundColor = Colors.WHITE;
}
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor);
}
// Change label font color // Change label font color
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:ButtonText" + state)));
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));
}
} }
} }

View File

@ -18,8 +18,6 @@
package ru.windcorp.progressia.client.graphics.gui; package ru.windcorp.progressia.client.graphics.gui;
import glm.vec._2.i.Vec2i; 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.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.font.Typefaces; import ru.windcorp.progressia.client.graphics.font.Typefaces;
@ -43,34 +41,28 @@ public class Checkbox extends BasicButton {
int x = getX(); int x = getX();
int y = getY() + (getHeight() - size) / 2; int y = getY() + (getHeight() - size) / 2;
// Border String state;
if (!Checkbox.this.isEnabled()) {
Vec4 borderColor; state = "Disabled";
if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) { } else if (Checkbox.this.isPressed()) {
borderColor = Colors.BLUE; state = "Pressed";
} else if (Checkbox.this.isHovered()) {
state = "Hovered";
} else if (Checkbox.this.isFocused()) {
state = "Focused";
} else { } 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 // Inside area
target.fill(x + 2, y + 2, size - 4, size - 4, ColorScheme.get("Core:CheckboxFill" + state));
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);
}
// "Tick" // "Tick"
if (Checkbox.this.isChecked()) { 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 @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
// Change label font color String state;
if (!Checkbox.this.isEnabled()) {
if (isPressed()) { state = "Disabled";
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE)); } else if (Checkbox.this.isPressed()) {
state = "Pressed";
} else if (Checkbox.this.isHovered()) {
state = "Hovered";
} else if (Checkbox.this.isFocused()) {
state = "Focused";
} else { } else {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); state = "Inactive";
} }
}
@Override // Change label font color
protected void postAssembleSelf(RenderTarget target) { getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:CheckboxText" + state)));
// Apply disable tint
if (!isEnabled()) {
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
}
} }
} }

View File

@ -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);
}
}

View File

@ -20,7 +20,6 @@ package ru.windcorp.progressia.client.graphics.gui;
import java.util.Objects; import java.util.Objects;
import glm.vec._4.Vec4; 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.flat.RenderTarget;
public class Panel extends Group { public class Panel extends Group {
@ -36,7 +35,7 @@ public class Panel extends Group {
} }
public Panel(String name, Layout layout) { 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"));
} }
/** /**

View File

@ -21,7 +21,6 @@ import org.lwjgl.glfw.GLFW;
import glm.vec._2.i.Vec2i; import glm.vec._2.i.Vec2i;
import glm.vec._4.Vec4; 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.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.font.Typefaces; import ru.windcorp.progressia.client.graphics.font.Typefaces;
@ -52,34 +51,28 @@ public class RadioButton extends BasicButton {
int x = getX(); int x = getX();
int y = getY() + (getHeight() - size) / 2; int y = getY() + (getHeight() - size) / 2;
// Border String state;
if (!RadioButton.this.isEnabled()) {
Vec4 borderColor; state = "Disabled";
if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) { } else if (RadioButton.this.isPressed()) {
borderColor = Colors.BLUE; state = "Pressed";
} else if (RadioButton.this.isHovered()) {
state = "Hovered";
} else if (RadioButton.this.isFocused()) {
state = "Focused";
} else { } 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 // Inside area
cross(target, x + 2, y + 2, size - 4, ColorScheme.get("Core:RadioButtonFill" + state));
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);
}
// "Tick" // "Tick"
if (RadioButton.this.isChecked()) { 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(); group.selectNext();
removeAction(group.listener); removeAction(group.listener);
group.buttons.remove(this); group.buttons.remove(this);
group.getSelected(); // Clear reference if this was the only button // Clear reference if this was the only button in the group
// in the group group.getSelected();
} }
this.group = group; this.group = group;
@ -183,22 +176,21 @@ public class RadioButton extends BasicButton {
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
// Change label font color String state;
if (!RadioButton.this.isEnabled()) {
if (isPressed()) { state = "Disabled";
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE)); } else if (RadioButton.this.isPressed()) {
state = "Pressed";
} else if (RadioButton.this.isHovered()) {
state = "Hovered";
} else if (RadioButton.this.isFocused()) {
state = "Focused";
} else { } else {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); state = "Inactive";
} }
}
@Override // Change label font color
protected void postAssembleSelf(RenderTarget target) { getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:RadioButtonText" + state)));
// Apply disable tint
if (!isEnabled()) {
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
}
} }
} }

View File

@ -1,23 +0,0 @@
package ru.windcorp.progressia.client.graphics.gui;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.texture.Texture;
public class TextureComponent extends Component {
private final Texture texture;
public TextureComponent(String name, Texture texture2) {
super(name);
texture = texture2;
setPreferredSize(texture.getSprite().getWidth(),texture.getSprite().getHeight());
}
@Override
protected void assembleSelf(RenderTarget target)
{
target.drawTexture(getX(), getY(), getWidth(), getHeight(), texture);
}
}

View File

@ -27,8 +27,8 @@ import ru.windcorp.progressia.client.graphics.gui.Layout;
public class LayoutAlign implements Layout { public class LayoutAlign implements Layout {
protected final int margin; private final int margin;
protected double alignX, alignY; private double alignX, alignY;
public LayoutAlign(double alignX, double alignY, int margin) { public LayoutAlign(double alignX, double alignY, int margin) {
this.alignX = alignX; this.alignX = alignX;
@ -72,7 +72,7 @@ public class LayoutAlign implements Layout {
Vec2i result = new Vec2i(0, 0); Vec2i result = new Vec2i(0, 0);
c.getChildren().stream() c.getChildren().stream()
.map(Component::getPreferredSize) .map(child -> child.getPreferredSize())
.forEach(size -> { .forEach(size -> {
result.x = max(size.x, result.x); result.x = max(size.x, result.x);
result.y = max(size.y, result.y); result.y = max(size.y, result.y);

View File

@ -1,56 +0,0 @@
package ru.windcorp.progressia.client.graphics.gui.layout;
import glm.vec._2.i.Vec2i;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.client.graphics.gui.Layout;
import static java.lang.Math.max;
import static java.lang.Math.min;
public class LayoutEdges implements Layout {
private final int margin;
public LayoutEdges(int margin) {
this.margin = margin;
}
@Override
public void layout(Component c) {
for (int i=0;i<2;i++)
{
Component child = c.getChild(i);
Vec2i size = child.getPreferredSize();
int cWidth = c.getWidth() - 2 * margin;
int cHeight = c.getHeight() - 2 * margin;
size.x = min(size.x, cWidth);
size.y = min(size.y, cHeight);
if (i==0) {
child.setBounds(
c.getX() + margin,
c.getY(),
size
);
} else {
child.setBounds(
1920 - size.x - margin,
c.getY(),
size
);
}
}
}
@Override
public Vec2i calculatePreferredSize(Component c) {
Vec2i result = new Vec2i(1920,0);
c.getChildren().stream()
.map(Component::getPreferredSize)
.forEach(size -> result.y = max(Math.abs(size.y), result.y));
return result;
}
}

View File

@ -20,9 +20,9 @@ package ru.windcorp.progressia.client.graphics.gui.menu;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import glm.vec._2.i.Vec2i; 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.GUI;
import ru.windcorp.progressia.client.graphics.font.Font; 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.Component;
import ru.windcorp.progressia.client.graphics.gui.GUILayer; import ru.windcorp.progressia.client.graphics.gui.GUILayer;
import ru.windcorp.progressia.client.graphics.gui.Label; import ru.windcorp.progressia.client.graphics.gui.Label;
@ -50,7 +50,7 @@ public class MenuLayer extends GUILayer {
setCursorPolicy(CursorPolicy.REQUIRE); 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; this.content = content;
background.addChild(content); background.addChild(content);
@ -76,12 +76,12 @@ public class MenuLayer extends GUILayer {
protected void addTitle() { protected void addTitle() {
String translationKey = "Layer" + getName() + ".Title"; String translationKey = "Layer" + getName() + ".Title";
MutableString titleText = new MutableStringLocalized(translationKey); 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); Label label = new Label(getName() + ".Title", titleFont, titleText);
getContent().addChild(label); 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() { panel.setLayout(new LayoutFill() {
@Override @Override
public Vec2i calculatePreferredSize(Component c) { public Vec2i calculatePreferredSize(Component c) {

View File

@ -43,8 +43,10 @@ public class Region {
private static final boolean RESET_CORRUPTED = true; private static final boolean RESET_CORRUPTED = true;
private final AtomicBoolean isUsing = new AtomicBoolean(false); public int loadedChunks;
private final AtomicBoolean isClosed = new AtomicBoolean(false);
private AtomicBoolean isUsing = new AtomicBoolean(false);
private AtomicBoolean isClosed = new AtomicBoolean(false);
private final RegionFile file; private final RegionFile file;
@ -58,7 +60,6 @@ public class Region {
} catch (IOException e) { } catch (IOException e) {
RegionWorldContainer.LOG.debug("Uh the file broke"); RegionWorldContainer.LOG.debug("Uh the file broke");
RegionWorldContainer.LOG.debug(e.getLocalizedMessage());
if (RESET_CORRUPTED) { if (RESET_CORRUPTED) {
this.file.makeHeader(regionCoords); this.file.makeHeader(regionCoords);
} }
@ -131,7 +132,7 @@ public class Region {
DecodingException { DecodingException {
isUsing.set(true); isUsing.set(true);
int dataOffset; int dataOffset = 0;
Vec3i pos = RegionWorldContainer.getInRegionCoords(chunkPos); Vec3i pos = RegionWorldContainer.getInRegionCoords(chunkPos);
if (hasOffset(pos)) { if (hasOffset(pos)) {

View File

@ -26,9 +26,9 @@ public class RegionFile {
private static final int ID_HEADER_SIZE = 16; private static final int ID_HEADER_SIZE = 16;
private static final byte[] HEADER_ID = {'P','R','O','G'}; private static final byte[] HEADER_ID = {'P','R','O','G'};
final byte[] endBytes = new byte[SECTOR_SIZE]; final byte endBytes[] = new byte[SECTOR_SIZE];
public enum SectorType { public static enum SectorType {
Ending(0), // Just an empty block Ending(0), // Just an empty block
Data(1), // has a byte counting up in position 1, and then Data(1), // has a byte counting up in position 1, and then
PartitionLink(2), PartitionLink(2),
@ -54,7 +54,7 @@ public class RegionFile {
public void confirmHeaderHealth(ChunkMap<Integer> offsets, Vec3i regionCoords) throws IOException { public void confirmHeaderHealth(ChunkMap<Integer> offsets, Vec3i regionCoords) throws IOException {
Set<Integer> used = new HashSet<>(); Set<Integer> used = new HashSet<Integer>();
int maxUsed = 0; int maxUsed = 0;
final int chunksPerRegion = REGION_DIAMETER * REGION_DIAMETER * REGION_DIAMETER; final int chunksPerRegion = REGION_DIAMETER * REGION_DIAMETER * REGION_DIAMETER;
@ -63,10 +63,9 @@ public class RegionFile {
} }
byte prog; char prog;
file.seek(0);
for (int i=0;i<4;i++) { for (int i=0;i<4;i++) {
prog = file.readByte(); prog = file.readChar();
if (prog != HEADER_ID[i]) if (prog != HEADER_ID[i])
{ {
throw new IOException("File is not a .progressia_chunk file"); throw new IOException("File is not a .progressia_chunk file");
@ -110,7 +109,7 @@ public class RegionFile {
throw new IOException("A sector is used twice"); throw new IOException("A sector is used twice");
} }
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * offset); file.seek(HEADER_SIZE + SECTOR_SIZE * offset);
byte type = file.readByte(); byte type = file.readByte();
if (type == SectorType.Data.data) { if (type == SectorType.Data.data) {
@ -132,26 +131,25 @@ public class RegionFile {
} }
public void makeHeader(Vec3i regionCoords) throws IOException { public void makeHeader(Vec3i regionCoords) throws IOException {
file.seek(0);
for (int i = 0; i < HEADER_SIZE; i++) {
file.write(0);
}
file.seek(0); file.seek(0);
file.write(HEADER_ID); file.write(HEADER_ID);
file.writeInt(regionCoords.x); file.writeInt(regionCoords.x);
file.writeInt(regionCoords.y); file.writeInt(regionCoords.y);
file.writeInt(regionCoords.z); file.writeInt(regionCoords.z);
for (int i = 0; i < HEADER_SIZE; i++) {
file.write(0);
}
} }
public void writeBuffer(byte[] buffer, int dataOffset, Vec3i pos) throws IOException { public void writeBuffer(byte[] buffer, int dataOffset, Vec3i pos) throws IOException {
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset); file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset);
int loc = 0; int loc = 0;
byte[] tempBuffer = new byte[SECTOR_SIZE]; byte tempBuffer[] = new byte[SECTOR_SIZE];
byte counter = 0; byte counter = 0;
boolean isDone = false; boolean isDone = false;
while (!isDone) { while (!isDone) {
if (file.length() > HEADER_SIZE + (long) SECTOR_SIZE * (dataOffset + 1)) { if (file.length() > HEADER_SIZE + SECTOR_SIZE * (dataOffset + 1)) {
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * (dataOffset + 1)); file.seek(HEADER_SIZE + SECTOR_SIZE * (dataOffset + 1));
byte header = file.readByte(); byte header = file.readByte();
if (header == SectorType.Data.data) { if (header == SectorType.Data.data) {
byte fileCounter = file.readByte(); byte fileCounter = file.readByte();
@ -159,7 +157,7 @@ public class RegionFile {
// partition place // partition place
{ {
int newOffset = allocateEmptySector(); int newOffset = allocateEmptySector();
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset); file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset);
file.write(2); file.write(2);
file.writeInt(newOffset); file.writeInt(newOffset);
dataOffset = newOffset; dataOffset = newOffset;
@ -181,7 +179,7 @@ public class RegionFile {
if (file.getFilePointer() < 256) if (file.getFilePointer() < 256)
LogManager.getLogger("Region") LogManager.getLogger("Region")
.debug("at {}, ({},{},{}), {}", file.getFilePointer(), pos.x, pos.y, pos.z, dataOffset); .debug("at {}, ({},{},{}), {}", file.getFilePointer(), pos.x, pos.y, pos.z, dataOffset);
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset); file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset);
dataOffset++; dataOffset++;
file.write(tempBuffer); file.write(tempBuffer);
} }
@ -199,7 +197,7 @@ public class RegionFile {
file.seek(definitionOffset); file.seek(definitionOffset);
file.writeInt(dataOffset + 1); file.writeInt(dataOffset + 1);
file.setLength(HEADER_SIZE + (long) dataOffset * SECTOR_SIZE); file.setLength(HEADER_SIZE + dataOffset * SECTOR_SIZE);
return dataOffset; return dataOffset;
} }
@ -208,17 +206,17 @@ public class RegionFile {
int dataOffset = (int) Math.ceil((double) (outputLen - HEADER_SIZE) / SECTOR_SIZE); int dataOffset = (int) Math.ceil((double) (outputLen - HEADER_SIZE) / SECTOR_SIZE);
file.setLength(HEADER_SIZE + (long) dataOffset * SECTOR_SIZE); file.setLength(HEADER_SIZE + dataOffset * SECTOR_SIZE);
return dataOffset; return dataOffset;
} }
public byte[] readBuffer(int dataOffset) throws IOException { public byte[] readBuffer(int dataOffset) throws IOException {
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset); file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset);
int bufferPos = 0; int bufferPos = 0;
byte[] buffer = new byte[SECTOR_SIZE * 16]; byte buffer[] = new byte[SECTOR_SIZE * 16];
byte[] tempBuffer = new byte[SECTOR_SIZE]; byte tempBuffer[] = new byte[SECTOR_SIZE];
boolean reachedEnd = false; boolean reachedEnd = false;
byte counter = 0; byte counter = 0;
@ -231,24 +229,31 @@ public class RegionFile {
if (tempBuffer[0] == SectorType.Data.data) { if (tempBuffer[0] == SectorType.Data.data) {
if (tempBuffer[1] != counter) { if (tempBuffer[1] != counter) {
throw new IOException( throw new IOException(
"Sectors were read out of order\nExpected chunk number " + counter "Sectors were read out of order\nExpected chunk number " + Byte.toString(counter)
+ " but encountered number " + tempBuffer[1] + " but encountered number " + Byte.toString(tempBuffer[1])
); );
} }
counter++; counter++;
if (buffer.length - bufferPos < SECTOR_SIZE - SECTOR_HEADER_SIZE - 1) { if (buffer.length - bufferPos < SECTOR_SIZE - SECTOR_HEADER_SIZE - 1) {
byte[] newBuffer = new byte[buffer.length + SECTOR_SIZE * 16]; byte newBuffer[] = new byte[buffer.length + SECTOR_SIZE * 16];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); for (int i = 0; i < buffer.length; i++) // TODO dedicated
// copy, java-y at
// least
{
newBuffer[i] = buffer[i];
}
buffer = newBuffer; buffer = newBuffer;
} }
System.arraycopy(tempBuffer, 2, buffer, bufferPos, SECTOR_SIZE - SECTOR_HEADER_SIZE - 1); for (int i = 0; i < SECTOR_SIZE - SECTOR_HEADER_SIZE - 1; i++) {
buffer[bufferPos + i] = tempBuffer[i + 2];
}
bufferPos += SECTOR_SIZE - SECTOR_HEADER_SIZE - 1; bufferPos += SECTOR_SIZE - SECTOR_HEADER_SIZE - 1;
} else if (tempBuffer[0] == SectorType.Ending.data) { } else if (tempBuffer[0] == SectorType.Ending.data) {
reachedEnd = true; reachedEnd = true;
} else if (tempBuffer[0] == SectorType.PartitionLink.data) { } else if (tempBuffer[0] == SectorType.PartitionLink.data) {
ByteBuffer intBuffer = ByteBuffer.wrap(tempBuffer); ByteBuffer intBuffer = ByteBuffer.wrap(tempBuffer);
int newOffset = intBuffer.getInt(1); int newOffset = intBuffer.getInt(1);
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * newOffset); file.seek(HEADER_SIZE + SECTOR_SIZE * newOffset);
} else { } else {
throw new IOException("Invalid sector ID."); throw new IOException("Invalid sector ID.");
} }

View File

@ -1,108 +0,0 @@
package ru.windcorp.progressia.test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import glm.mat._4.Mat4;
import glm.vec._3.Vec3;
import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.gui.Component;
public class CubeComponent extends Component {
private final Mat4[] transforms;
private final Vec4[] normals;
private final long startTime;
private final double r3 = Math.sqrt(3+.01);
private final int size;
public CubeComponent(String name, int size) {
super(name);
this.size = size;
transforms = new Mat4[6];
normals = new Vec4[6];
setPreferredSize((int) Math.ceil(r3*size),(int) Math.ceil(r3*size));
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(this::requestReassembly, 1, 60, TimeUnit.MILLISECONDS);
startTime = System.currentTimeMillis();
}
// Notes to me
// z axis is through the screen
// y is horizontal spin
// x is vertical spin
private void computeTransforms()
{
//Creates all of the sides
transforms[0] = new Mat4(1);
transforms[1] = new Mat4(1);
transforms[2] = new Mat4(1);
transforms[3] = new Mat4(1);
transforms[4] = new Mat4(1);
transforms[5] = new Mat4(1);
//Gets time since creation(for rotation amount)
long time = System.currentTimeMillis()-startTime;
//Initializes the way each face is facing
normals[0] = new Vec4(0,0,-1,0);
normals[1] = new Vec4(0,1,0,0);
normals[2] = new Vec4(1,0,0,0);
normals[3] = new Vec4(0,0,1,0);
normals[4] = new Vec4(0,-1,0,0);
normals[5] = new Vec4(-1,0,0,0);
for (int i=0;i<6;i++)
{
//Rotates given side with the time one first, then ot get it on its off axis, then gets the image of each axis under the given rotation
//The rotate functions do change the transforms, but the multiplication does not
normals[i] = transforms[i].rotate((float) (time%(6000*6.28) )/ 6000, new Vec3(0,1,0)).rotate((float) 24, new Vec3(1,.5,0)).mul_(normals[i]);
}
double pi2 = Math.PI / 2;
//Move and rotate the sides from the middle of the cube to the appropriate edges
transforms[0].translate(new Vec3(-size/2f,-size/2f,size/2f));
transforms[1].translate(new Vec3(-size/2f,-size/2f,-size/2f)).rotate((float) pi2, new Vec3(1,0,0));
transforms[2].translate(new Vec3(-size/2f,-size/2f,size/2f)).rotate((float) pi2, new Vec3(0,1,0));
transforms[3].translate(new Vec3(-size/2f,-size/2f,-size/2f));
transforms[4].translate(new Vec3(-size/2f,size/2f,-size/2f)).rotate((float) pi2, new Vec3(1,0,0));
transforms[5].translate(new Vec3(size/2f,-size/2f,size/2f)).rotate((float) pi2, new Vec3(0,1,0));
for (int i=0;i<6;i++) // I have no clue why this is necessary, without it the sides of the cube mess up; may need to be changed if the title screen changes position.
{
transforms[i] = transforms[i].translate(new Vec3(0,0,17.5-3*(i<2 ? 1 : 0)));
}
}
@Override
protected void assembleSelf(RenderTarget target)
{
computeTransforms();
setPosition(750,780);
target.pushTransform(new Mat4(1).translate(new Vec3(getX()+size*r3/2,getY()-size*r3/2,0))); //-size*r3/2
for (int b=0; b<6;b++)
{
target.pushTransform(transforms[b]);
float dot = normals[b].dot(new Vec4(-1,0,0,0)); //Gets the "amount" the given side is pointing in the -x direction
Vec4 color = new Vec4(.4+.3*dot, .4+.3*dot, .6+.4*dot,1.0); //More aligned means brighter color
target.fill(0,0, size, size, color);
target.popTransform();
}
target.popTransform();
}
}

View File

@ -22,6 +22,7 @@ import ru.windcorp.progressia.Progressia;
import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.font.Typeface; import ru.windcorp.progressia.client.graphics.font.Typeface;
import ru.windcorp.progressia.client.graphics.gui.ColorScheme;
import ru.windcorp.progressia.client.graphics.gui.GUILayer; import ru.windcorp.progressia.client.graphics.gui.GUILayer;
import ru.windcorp.progressia.client.graphics.gui.Label; import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.Group; import ru.windcorp.progressia.client.graphics.gui.Group;
@ -31,15 +32,13 @@ import ru.windcorp.progressia.client.localization.MutableStringLocalized;
public class LayerAbout extends GUILayer { public class LayerAbout extends GUILayer {
public static String version = "pre-alpha 3";
public LayerAbout() { public LayerAbout() {
super("LayerAbout", new LayoutAlign(1, 1, 5)); super("LayerAbout", new LayoutAlign(1, 1, 5));
Group group = new Group("ControlDisplays", new LayoutVertical(5)); Group group = new Group("ControlDisplays", new LayoutVertical(5));
Font font = new Font().withColor(Colors.WHITE).deriveOutlined().withAlign(Typeface.ALIGN_RIGHT); Font font = new Font().withColor(Colors.WHITE).deriveOutlined().withAlign(Typeface.ALIGN_RIGHT);
Font aboutFont = font.withColor(0xFF37A3E6).deriveBold(); Font aboutFont = font.withColor(ColorScheme.get("Core:Accent")).deriveBold();
group.addChild( group.addChild(
new Label( new Label(

View File

@ -20,11 +20,11 @@ package ru.windcorp.progressia.test;
import java.util.Collection; import java.util.Collection;
import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.GUI; import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.gui.Button; import ru.windcorp.progressia.client.graphics.gui.Button;
import ru.windcorp.progressia.client.graphics.gui.Checkbox; import ru.windcorp.progressia.client.graphics.gui.Checkbox;
import ru.windcorp.progressia.client.graphics.gui.ColorScheme;
import ru.windcorp.progressia.client.graphics.gui.Label; import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.RadioButton; import ru.windcorp.progressia.client.graphics.gui.RadioButton;
import ru.windcorp.progressia.client.graphics.gui.RadioButtonGroup; import ru.windcorp.progressia.client.graphics.gui.RadioButtonGroup;
@ -65,7 +65,7 @@ public class LayerButtonTest extends MenuLayer {
getContent().getChild(getContent().getChildren().size() - 1).setEnabled(false); getContent().getChild(getContent().getChildren().size() - 1).setEnabled(false);
getContent().addChild(new Label("Hint", new Font().withColor(Colors.LIGHT_GRAY), "This is a MenuLayer")); getContent().addChild(new Label("Hint", new Font().withColor(ColorScheme.get("Core:Border")), "This is a MenuLayer"));
getContent().addChild(new Button("Continue", "Continue").addAction(b -> { getContent().addChild(new Button("Continue", "Continue").addAction(b -> {
getCloseAction().run(); getCloseAction().run();

View File

@ -1,53 +0,0 @@
package ru.windcorp.progressia.test;
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.*;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
import ru.windcorp.progressia.client.graphics.texture.SimpleTextures;
import ru.windcorp.progressia.client.localization.Localizer;
import ru.windcorp.progressia.client.localization.MutableString;
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
import java.util.List;
public class LayerOptions extends Background {
public LayerOptions(String name) {
super(name, new LayoutAlign(0, 1f, 15), SimpleTextures.get("title/background"));
Group content = new Group("Layer" + name + ".Group", new LayoutVertical(15));
Font font = new Font().withColor(Colors.BLUE).withAlign(0.5f);
MutableString languageText = new MutableStringLocalized("Layer" + name + ".Language");
content.addChild(new Button(name + ".Language", new Label(name + ".Language", font, languageText)).addAction(this::toggleLanguage));
MutableString playText = new MutableStringLocalized("Layer" + name + ".Return");
content.addChild(new Button(name + ".Return", new Label(name + ".Return", font, playText)).addAction(this::openTitle));
getRoot().addChild(content);
}
private void openTitle(BasicButton basicButton) {
GUI.removeLayer(this);
GUI.addTopLayer(new LayerTitle("Title"));
}
private void toggleLanguage(BasicButton basicButton)
{
String curLang = Localizer.getInstance().getLanguage();
List<String> allLangs = Localizer.getInstance().getLanguages();
int pos = allLangs.indexOf(curLang);
pos++;
if (pos >= allLangs.size())
{
Localizer.getInstance().setLanguage(allLangs.get(0));
}
else
{
Localizer.getInstance().setLanguage(allLangs.get(pos));
}
}
}

View File

@ -1,11 +1,13 @@
package ru.windcorp.progressia.test; package ru.windcorp.progressia.test;
import java.util.function.Consumer; import java.util.function.Consumer;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.gui.ColorScheme;
import ru.windcorp.progressia.client.graphics.gui.GUILayer; import ru.windcorp.progressia.client.graphics.gui.GUILayer;
import ru.windcorp.progressia.client.graphics.gui.Label; import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.Panel;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
import ru.windcorp.progressia.client.localization.MutableString; import ru.windcorp.progressia.client.localization.MutableString;
public class LayerTestText extends GUILayer { public class LayerTestText extends GUILayer {
@ -13,11 +15,13 @@ public class LayerTestText extends GUILayer {
private final Consumer<LayerTestText> remover; private final Consumer<LayerTestText> remover;
public LayerTestText(String name, MutableString value, Consumer<LayerTestText> remover) { public LayerTestText(String name, MutableString value, Consumer<LayerTestText> remover) {
super(name, new LayoutAlign(15)); super(name, new LayoutFill());
this.remover = remover; this.remover = remover;
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f); Panel panel = new Panel(name + ".Background", new LayoutAlign(15), ColorScheme.get("Core:Background"), null);
getRoot().addChild(new Label(name + ".Text", titleFont, value)); Font titleFont = new Font().deriveBold().withColor(ColorScheme.get("Core:Text")).withAlign(0.5f);
panel.addChild(new Label(name + ".Text", titleFont, value));
getRoot().addChild(panel);
} }
@Override @Override

View File

@ -1,20 +1,16 @@
package ru.windcorp.progressia.test; package ru.windcorp.progressia.test;
import ru.windcorp.progressia.Progressia;
import ru.windcorp.progressia.client.ClientState; import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.GUI; import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.gui.Background;
import ru.windcorp.progressia.client.graphics.gui.BasicButton; import ru.windcorp.progressia.client.graphics.gui.BasicButton;
import ru.windcorp.progressia.client.graphics.gui.Button; import ru.windcorp.progressia.client.graphics.gui.Button;
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
import ru.windcorp.progressia.client.graphics.gui.Group; import ru.windcorp.progressia.client.graphics.gui.Group;
import ru.windcorp.progressia.client.graphics.gui.Label; import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.TextureComponent;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutEdges;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
import ru.windcorp.progressia.client.graphics.texture.SimpleTextures;
import ru.windcorp.progressia.client.localization.MutableString; import ru.windcorp.progressia.client.localization.MutableString;
import ru.windcorp.progressia.client.localization.MutableStringLocalized; import ru.windcorp.progressia.client.localization.MutableStringLocalized;
import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.crash.CrashReports;
@ -28,58 +24,34 @@ import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
public class LayerTitle extends Background { public class LayerTitle extends GUILayer {
private final BasicButton resetButton; private final BasicButton resetButton;
public LayerTitle(String name) { public LayerTitle(String name) {
super(name, new LayoutAlign(0, 1f, 15), SimpleTextures.get("title/background")); super(name, new LayoutAlign(0.5f, 0.7f, 15));
Group content = new Group("Layer" + name + ".Group", new LayoutVertical(15)); Group content = new Group("Layer" + name + ".Group", new LayoutVertical(15));
Group info = new Group("Layer"+name+".InfoGroup", new LayoutEdges(30));
Group buttonContent = new Group("Layer" + name + ".ButtonGroup", new LayoutColumn(15, 320));
Font titleFont = new Font().deriveBold().withColor(Colors.BLUE).withAlign(0.5f); MutableString title = new MutableStringLocalized("Layer" + name + ".Title");
content.addChild(new TextureComponent(name + ".Title", SimpleTextures.get("title/progressia"))); Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f);
content.addChild(new Label(name + ".Title", titleFont, title));
info.addChild(new Label(
"About",
titleFont,
new MutableStringLocalized("LayerAbout.Title")
)
);
info.addChild(
new Label(
"Version",
titleFont,
Progressia.getFullerVersion()
)
);
content.addChild(info);
Font buttonFont = titleFont.deriveNotBold(); Font buttonFont = titleFont.deriveNotBold();
MutableString playText = new MutableStringLocalized("Layer" + name + ".Play"); MutableString playText = new MutableStringLocalized("Layer" + name + ".Play");
buttonContent.addChild(new Button(name + ".Play", new Label(name + ".Play", buttonFont, playText)).addAction(this::startGame)); content.addChild(new Button(name + ".Play", new Label(name + ".Play", buttonFont, playText)).addAction(this::startGame));
MutableString resetText = new MutableStringLocalized("Layer" + name + ".Reset"); MutableString resetText = new MutableStringLocalized("Layer" + name + ".Reset");
this.resetButton = new Button(name + ".Reset", new Label(name + ".Reset", buttonFont, resetText)).addAction(this::resetWorld); this.resetButton = new Button(name + ".Reset", new Label(name + ".Reset", buttonFont, resetText)).addAction(this::resetWorld);
buttonContent.addChild(resetButton); content.addChild(resetButton);
updateResetButton(); updateResetButton();
MutableString settingsText = new MutableStringLocalized("Layer" + name + ".Options");
buttonContent.addChild(new Button(name + ".Options", new Label(name + ".Options", buttonFont, settingsText)).addAction(this::openOptions));
MutableString quitText = new MutableStringLocalized("Layer" + name + ".Quit"); MutableString quitText = new MutableStringLocalized("Layer" + name + ".Quit");
buttonContent.addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> System.exit(0))); content.addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> {
System.exit(0);
}));
content.addChild(buttonContent);
getRoot().addChild(content); getRoot().addChild(content);
buttonContent.setPreferredSize(500, 1000);
CubeComponent cube = new CubeComponent(name+".Cube",300);
getRoot().addChild(cube);
} }
private void updateResetButton() { private void updateResetButton() {
@ -120,9 +92,4 @@ public class LayerTitle extends Background {
updateResetButton(); updateResetButton();
} }
private void openOptions(BasicButton basicButton) {
GUI.removeLayer(this);
GUI.addTopLayer(new LayerOptions("Options"));
}
} }

View File

@ -1,33 +0,0 @@
package ru.windcorp.progressia.test;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
public class LayoutColumn extends LayoutVertical {
protected int maxWidth;
private final int margin;
public LayoutColumn(int gap, int maxWidth)
{
super(gap);
this.maxWidth = maxWidth;
margin = gap;
}
@Override
public void layout(Component c) {
int x = c.getX() + margin,
y = c.getY() + c.getHeight();
synchronized (c.getChildren()) {
for (Component child : c.getChildren()) {
int height = child.getPreferredSize().y;
y -= margin + height;
child.setBounds(x, y, maxWidth, height);
}
}
}
}

View File

@ -0,0 +1,80 @@
# Default color scheme for Progressia
#
# Line format:
# KEY = VALUE
# KEY must be a legal ID
# VALUE may be one of the following:
# #RGB
# #ARGB
# #RRGGBB
# #AARRGGBB
# $OTHER_KEY
Core:Background = #EFF0F1
Core:Border = #CBCBD0
Core:DisabledBackground = $Core:Background
Core:DisabledBorder = #DEDFE1
Core:Accent = #37A3E6
Core:AccentLighter = #C3E4F7
Core:Text = #31363B
Core:ButtonBorderDisabled = $Core:DisabledBorder
Core:ButtonBorderPressed = $Core:Accent
Core:ButtonBorderHovered = $Core:Accent
Core:ButtonBorderFocused = $Core:Accent
Core:ButtonBorderInactive = $Core:Border
Core:ButtonFillDisabled = $Core:DisabledBackground
Core:ButtonFillPressed = $Core:Accent
Core:ButtonFillHovered = $Core:AccentLighter
Core:ButtonFillFocused = $Core:Background
Core:ButtonFillInactive = $Core:Background
Core:ButtonTextDisabled = $Core:DisabledBorder
Core:ButtonTextPressed = $Core:Background
Core:ButtonTextHovered = $Core:Text
Core:ButtonTextFocused = $Core:Text
Core:ButtonTextInactive = $Core:Text
Core:CheckboxBorderDisabled = $Core:DisabledBorder
Core:CheckboxBorderPressed = $Core:Accent
Core:CheckboxBorderHovered = $Core:Accent
Core:CheckboxBorderFocused = $Core:Accent
Core:CheckboxBorderInactive = $Core:Border
Core:CheckboxFillDisabled = $Core:DisabledBackground
Core:CheckboxFillPressed = $Core:Accent
Core:CheckboxFillHovered = $Core:AccentLighter
Core:CheckboxFillFocused = $Core:Background
Core:CheckboxFillInactive = $Core:Background
Core:CheckboxTextDisabled = $Core:DisabledBorder
Core:CheckboxTextPressed = $Core:Accent
Core:CheckboxTextHovered = $Core:Text
Core:CheckboxTextFocused = $Core:Text
Core:CheckboxTextInactive = $Core:Text
Core:CheckboxCheckDisabled = $Core:DisabledBorder
Core:CheckboxCheckPressed = $Core:Accent
Core:CheckboxCheckHovered = $Core:Accent
Core:CheckboxCheckFocused = $Core:Accent
Core:CheckboxCheckInactive = $Core:Accent
Core:RadioButtonBorderDisabled = $Core:DisabledBorder
Core:RadioButtonBorderPressed = $Core:Accent
Core:RadioButtonBorderHovered = $Core:Accent
Core:RadioButtonBorderFocused = $Core:Accent
Core:RadioButtonBorderInactive = $Core:Border
Core:RadioButtonFillDisabled = $Core:DisabledBackground
Core:RadioButtonFillPressed = $Core:Accent
Core:RadioButtonFillHovered = $Core:AccentLighter
Core:RadioButtonFillFocused = $Core:Background
Core:RadioButtonFillInactive = $Core:Background
Core:RadioButtonTextDisabled = $Core:DisabledBorder
Core:RadioButtonTextPressed = $Core:Accent
Core:RadioButtonTextHovered = $Core:Text
Core:RadioButtonTextFocused = $Core:Text
Core:RadioButtonTextInactive = $Core:Text
Core:RadioButtonCheckDisabled = $Core:DisabledBorder
Core:RadioButtonCheckPressed = $Core:Accent
Core:RadioButtonCheckHovered = $Core:Accent
Core:RadioButtonCheckFocused = $Core:Accent
Core:RadioButtonCheckInactive = $Core:Accent
Core:MenuLayerTint = #6000

View File

@ -24,8 +24,5 @@ LayerTitle.Reset = Reset World
LayerTitle.Options = Options LayerTitle.Options = Options
LayerTitle.Quit = Quit LayerTitle.Quit = Quit
LayerOptions.Return = Back To Menu
LayerOptions.Language = US English
LayerText.Load = Loading... LayerText.Load = Loading...
LayerText.Save = Saving... LayerText.Save = Saving...

View File

@ -24,8 +24,5 @@ LayerTitle.Reset = Сбросить мир
LayerTitle.Options = Настройки LayerTitle.Options = Настройки
LayerTitle.Quit = Выход LayerTitle.Quit = Выход
LayerOptions.Return = Главное меню
LayerOptions.Language = Русский
LayerText.Load = Загрузка... LayerText.Load = Загрузка...
LayerText.Save = Сохранение... LayerText.Save = Сохранение...

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB