Compare commits

..

8 Commits

Author SHA1 Message Date
opfromthestart
22a744f65a Added Options
-Added options menu
-You can move from options to title and back
-Added language change button
*Double check the Russian, I just copied and pasted from other files
2022-01-08 21:16:51 -05:00
opfromthestart
c6de19cf19 Rebased everything on master
Now has the dynamic version thing
fixed warnings
2022-01-08 13:57:57 -05:00
opfromthestart
c1a57f7d7a Slightly better alignment
The mode for alignment is more concise
2022-01-08 12:45:28 -05:00
576cfed99f
Fixed import warnings 2021-10-17 14:05:40 +03:00
opfromthestart
5af1b7309d Better Alignment
-Created some Layouts to properly adjust where things go
    -LayoutEdges for text on the same row on opposite sides of the screen
    -LayoutColumn for a non-max width column
-More accessible version string
2021-10-13 23:37:18 -04:00
opfromthestart
0f0a94811f Cleaning
-Cleaned up offsets to make it look like a cube and not 6 squares.
-Fixed error where regions would incorrectly reset files
-Some additions to try to match the intended look. I really dont
understand layouts.
2021-09-25 20:45:17 -04:00
opfromthestart
51bcca1499 Betterish title screen
-Black background used
	-New Background class for displaying a single texture to the back of
the screen(probably not the best way)
-Title now uses an image
	-Made TextureComponent, I think this probably exists elsewhere but I
couldnt find it
-Cube faces now change color based on where they are facing, looks a lot
like the source material except for rearranging
2021-09-13 13:05:59 -04:00
opfromthestart
ce9e95e5ce Well, its [i]a[/i] cube.
-Added CubeComponent to render a cube to the screen
-Added it to the title screen
2021-09-11 21:11:59 -04:00
45 changed files with 802 additions and 1253 deletions

View File

@ -1,49 +0,0 @@
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

View File

@ -1,5 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: Official Progressia Discord
url: https://discord.gg/TWuXbVmX23
about: Ask developers or community members for help

View File

@ -1,41 +0,0 @@
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,16 +42,6 @@ compileJava {
/*
* Set encoding
*/
compileJava {
options.encoding = 'utf8'
}
/* /*
* Dependencies * Dependencies
*/ */
@ -70,7 +60,7 @@ repositories {
dependencies { dependencies {
// Google Guava // Google Guava
// A generic utilities library // A generic utilities library
implementation 'com.google.guava:guava:31.0.1-jre' implementation 'com.google.guava:guava:30.0-jre'
// Trove4j // Trove4j
// Provides optimized Collections for primitive types // Provides optimized Collections for primitive types
@ -83,8 +73,8 @@ dependencies {
// Log4j // Log4j
// A logging library // A logging library
implementation 'org.apache.logging.log4j:log4j-api:2.17.1' implementation 'org.apache.logging.log4j:log4j-api:2.17.0'
implementation 'org.apache.logging.log4j:log4j-core:2.17.1' implementation 'org.apache.logging.log4j:log4j-core:2.17.0'
// JUnit // JUnit
// A unit-testing library // A unit-testing library
@ -173,89 +163,53 @@ 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 = commit ?: git.head().id project.ext.commit = git.head().id
project.ext.branch = branch ?: git.branch.current().name project.ext.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 {
// Resolve version from Git project.version = version_parseVersion(tag.name, tag.commit != git.head())
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 = commit ?: '-' project.ext.commit = '-'
project.ext.branch = branch ?: '-' project.ext.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
} }
if (branch.contains '/') {
// Strip remote - no one wants that
project.ext.branch = branch.takeAfter '/'
}
if (!project.hasProperty('buildId')) {
project.ext.buildId = '-'
}
} }
doLast { doLast {
if (!project.hasProperty('buildId')) {
project.ext.buildId = '-'
}
} }
} }
/*
* 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'
}
/* /*
* Configure JAR manifest * Configure JAR manifest
*/ */
@ -265,16 +219,11 @@ 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': classPath.collect { "lib/${java.net.URLEncoder.encode it.name}" } .join(' '), 'Class-Path': configurations.runtimeClasspath.collect { "lib/${it.name}" } .join(' '),
'Specification-Title': 'Progressia', 'Specification-Title': 'Progressia',
@ -289,6 +238,28 @@ 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
*/ */
@ -296,40 +267,64 @@ task configureManifest {
import java.nio.file.* import java.nio.file.*
import java.nio.file.attribute.* import java.nio.file.attribute.*
task deletePackagingDirs(type: Delete) { task createPackagingDirs() {
description 'Deletes build/tmp/packaging directory.' description 'Resets build/tmp/packaging directory.'
followSymlinks = false
delete 'build/tmp/packaging' doLast {
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
mustRunAfter deletePackagingDirs dependsOn createPackagingDirs
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 fromPath = Paths.get from def from = buildDir.toPath().resolve 'libs'
def intoPath = Paths.get into def into = buildDir.toPath().resolve "tmp/packaging/workingDir/${preparePackaging.ext.buildDest}"
Files.createDirectories intoPath Files.createDirectories into
Files.list(fromPath).each { Files.list(from).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 intoPath.resolve(it.fileName), intoPath.relativize(it) Files.createSymbolicLink into.resolve(it.fileName), it
} }
} }
} }
@ -338,7 +333,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
mustRunAfter deletePackagingDirs dependsOn createPackagingDirs
onlyIf { preparePackaging.ext.mode == 'copy' } onlyIf { preparePackaging.ext.mode == 'copy' }
@ -353,7 +348,7 @@ task preparePackaging {
preparePackaging.ext.buildDest = '' preparePackaging.ext.buildDest = ''
preparePackaging.ext.mode = 'symlink' preparePackaging.ext.mode = 'symlink'
dependsOn deletePackagingDirs dependsOn createPackagingDirs
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.3.0' lwjgl.version = '3.2.3'
/* /*
* 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<String>() lwjgl.targets = new HashSet<>()
// 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,49 +33,34 @@ switch (OperatingSystem.current()) {
: 'linux' : 'linux'
break break
case OperatingSystem.MAC_OS: case OperatingSystem.MAC_OS:
lwjgl.localArch = System.getProperty('os.arch').startsWith('aarch64') ? 'macos-arm64' : 'macos' lwjgl.localArch = 'macos'
break break
case OperatingSystem.WINDOWS: case OperatingSystem.WINDOWS:
def osArch = System.getProperty('os.arch') lwjgl.localArch = System.getProperty('os.arch').contains('64') ? 'windows' : 'windows-x86'
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 { lib -> lwjgl.libraries.each { implementation "org.lwjgl:lwjgl-$it" }
implementation "org.lwjgl:lwjgl-$lib"
// Local natives for component
runtimeOnly "org.lwjgl:lwjgl-$lib::natives-${lwjgl.localArch}"
}
} }
/* /*
* Adds LWJGL native libraries to lwjglNatives configuration * Adds LWJGL native libraries to runtimeOnly 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 {
@ -97,34 +82,17 @@ 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 ->
lwjglNatives "org.lwjgl:lwjgl::natives-$target" runtimeOnly "org.lwjgl:lwjgl::natives-$target"
lwjgl.libraries.each { lib -> lwjgl.libraries.each { lib ->
lwjglNatives "org.lwjgl:lwjgl-$lib::natives-$target" runtimeOnly "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.'
@ -145,5 +113,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-arm64', 'windows-x86' requestTask 'Windows', 'windows', 'windows-x86'
requestTask 'MacOS', 'macos', 'macos-arm64' requestTask 'MacOS', 'macos'

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,10 +31,6 @@ 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,10 +40,6 @@ 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,10 +36,6 @@ 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`, `natives-windows-arm64` and `natives-windows-x86` binaries are included; - `requestWindowsDependencies` requests that `natives-windows` and `natives-windows-x86` binaries are included;
- `requestMacOSDependencies` requests that `natives-macos`, `natives-macos-arm64` binaries are included. - `requestMacOSDependencies` requests that `natives-macos` 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`, `natives-windows-arm64` and `natives-windows-x86` binaries are included when building. - `requestWindowsDependencies` requests that `natives-windows` and `natives-windows-x86` binaries are included when building.
- `requestMacOSDependencies` requests that `natives-macos` and `natives-macos-arm64` binaries are included when building. - `requestMacOSDependencies` requests that `natives-macos` 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,21 +60,14 @@ In all other cases, a fallback dummy value is used for version, appended with bu
### Git metadata ### Git metadata
Git commit is determined from `GIT_COMMIT` environment variable if it exists, or the state of the local Git Git commit and Git branch are correspond to the state of the local Git repository, if any. In case Git metadata is
repository, if any, or `-`. unavailable, `-` fallback is used for both fields.
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. Build ID must be provided explicitly; it Build ID uniquely identifies artifacts produced by automated build systems. For example, builds executed by WindCorp
is `-` unless specified otherwise. Jenkins suite have build IDs like `WJ3` or `WJ142`. Build ID must be provided explicitly; it is `-` unless specified
otherwise.
The proposed scheme for naming build IDs is `<builder><build-system><build attempt no.>`. For example, builds
executed by WindCorp Jenkins suite have build IDs like `WJ3` or `WJ142`.
Build ID may be set with `buildId` project property. This may be done in a variety of ways, for example with command 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`
@ -100,13 +93,11 @@ 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-arm64` | `requestWindowsDependencies` | | `windows-x86` | `requestWindowsDependencies` |
| `windows-x86` | `requestWindowsDependencies` | | `macos` | `requestMacOSDependencies` |
| `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-7.3.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

259
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/bin/sh #!/usr/bin/env sh
# #
# Copyright © 2015-2021 the original authors. # Copyright 2015 the original author or 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,113 +17,78 @@
# #
############################################################################## ##############################################################################
# ##
# Gradle start up script for POSIX generated by Gradle. ## Gradle start up script for UN*X
# ##
# 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
app_path=$0 PRG="$0"
# Need this for relative symlinks.
# Need this for daisy-chained symlinks. while [ -h "$PRG" ] ; do
while ls=`ls -ld "$PRG"`
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path link=`expr "$ls" : '.*-> \(.*\)$'`
[ -h "$app_path" ] if expr "$link" : '/.*' > /dev/null; then
do PRG="$link"
ls=$( ls -ld "$app_path" ) else
link=${ls#*' -> '} PRG=`dirname "$PRG"`"/$link"
case $link in #( fi
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=${0##*/} APP_BASE_NAME=`basename "$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=true ;; #( CYGWIN* )
Darwin* ) darwin=true ;; #( cygwin=true
MSYS* | MINGW* ) msys=true ;; #( ;;
NONSTOP* ) nonstop=true ;; Darwin* )
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
@ -132,7 +97,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
@ -140,95 +105,79 @@ 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" && ! "$darwin" && ! "$nonstop" ; then if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
case $MAX_FD in #( MAX_FD_LIMIT=`ulimit -H -n`
max*) if [ $? -eq 0 ] ; then
MAX_FD=$( ulimit -H -n ) || if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
warn "Could not query maximum file descriptor limit" MAX_FD="$MAX_FD_LIMIT"
esac fi
case $MAX_FD in #( ulimit -n $MAX_FD
'' | soft) :;; #( if [ $? -ne 0 ] ; then
*) warn "Could not set maximum file descriptor limit: $MAX_FD"
ulimit -n "$MAX_FD" || fi
warn "Could not set maximum file descriptor limit to $MAX_FD" else
esac warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi fi
# Collect all arguments for the java command, stacking in reverse order: # For Darwin, add options to specify how the application appears in the dock
# * args from the command line if $darwin; then
# * the main class name GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
# * -classpath fi
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
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`
# Now convert the arguments - kludge to limit ourselves to /bin/sh SEP=""
for arg do for dir in $ROOTDIRSRAW ; do
if ROOTDIRS="$ROOTDIRS$SEP$dir"
case $arg in #( SEP="|"
-*) 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 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
fi fi
# Collect all arguments for the java command; # Escape application args
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of save () {
# shell script including quotes and variable substitutions, so put them in for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
# double quotes to make sure that they get re-expanded; and echo " "
# * put everything else in single quotes, so that it's not re-expanded. }
APP_ARGS=`save "$@"`
set -- \ # Collect all arguments for the java command, following the shell quoting and substitution rules
"-Dorg.gradle.appname=$APP_BASE_NAME" \ eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-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,9 +29,6 @@ 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"
@ -40,7 +37,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 execute if "%ERRORLEVEL%" == "0" goto init
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.
@ -54,7 +51,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 execute if exist "%JAVA_EXE%" goto init
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%
@ -64,14 +61,28 @@ 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 %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

1
logs/game.log Normal file
View File

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

View File

@ -1,45 +0,0 @@
/*
* 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

@ -1,307 +0,0 @@
/*
* 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,7 +25,6 @@ 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,8 +50,7 @@ public class ClientProxy implements Proxy {
} catch (InterruptedException e) { } catch (InterruptedException e) {
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,7 +34,13 @@ 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

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

View File

@ -0,0 +1,28 @@
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,9 +18,15 @@
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) {
@ -37,26 +43,43 @@ public class Button extends BasicButton {
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
String state;
if (!isEnabled()) {
state = "Disabled";
} else if (isPressed()) {
state = "Pressed";
} else if (isHovered()) {
state = "Hovered";
} else if (isFocused()) {
state = "Focused";
} else {
state = "Inactive";
}
// Border // Border
target.fill(getX(), getY(), getWidth(), getHeight(), ColorScheme.get("Core:ButtonBorder" + state));
Vec4 borderColor;
if (isPressed() || isHovered() || isFocused()) {
borderColor = Colors.BLUE;
} else {
borderColor = Colors.LIGHT_GRAY;
}
target.fill(getX(), getY(), getWidth(), getHeight(), borderColor);
// 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,6 +18,8 @@
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;
@ -40,29 +42,35 @@ public class Checkbox extends BasicButton {
int size = getPreferredSize().x; int size = getPreferredSize().x;
int x = getX(); int x = getX();
int y = getY() + (getHeight() - size) / 2; int y = getY() + (getHeight() - size) / 2;
String state;
if (!Checkbox.this.isEnabled()) {
state = "Disabled";
} else if (Checkbox.this.isPressed()) {
state = "Pressed";
} else if (Checkbox.this.isHovered()) {
state = "Hovered";
} else if (Checkbox.this.isFocused()) {
state = "Focused";
} else {
state = "Inactive";
}
// Border // Border
target.fill(x, y, size, size, ColorScheme.get("Core:CheckboxBorder" + state));
Vec4 borderColor;
if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) {
borderColor = Colors.BLUE;
} else {
borderColor = Colors.LIGHT_GRAY;
}
target.fill(x, y, size, size, borderColor);
// 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, ColorScheme.get("Core:CheckboxCheck" + state)); target.fill(x + 4, y + 4, size - 8, size - 8, Colors.BLUE);
} }
} }
@ -120,21 +128,22 @@ public class Checkbox extends BasicButton {
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
String state;
if (!Checkbox.this.isEnabled()) {
state = "Disabled";
} else if (Checkbox.this.isPressed()) {
state = "Pressed";
} else if (Checkbox.this.isHovered()) {
state = "Hovered";
} else if (Checkbox.this.isFocused()) {
state = "Focused";
} else {
state = "Inactive";
}
// Change label font color // Change label font color
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:CheckboxText" + state)));
if (isPressed()) {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
} 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

@ -1,145 +0,0 @@
/*
* 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,6 +20,7 @@ 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 {
@ -35,7 +36,7 @@ public class Panel extends Group {
} }
public Panel(String name, Layout layout) { public Panel(String name, Layout layout) {
this(name, layout, ColorScheme.get("Core:Background"), ColorScheme.get("Core:Border")); this(name, layout, Colors.WHITE, Colors.LIGHT_GRAY);
} }
/** /**

View File

@ -21,6 +21,7 @@ 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;
@ -50,29 +51,35 @@ public class RadioButton extends BasicButton {
int size = getPreferredSize().x; int size = getPreferredSize().x;
int x = getX(); int x = getX();
int y = getY() + (getHeight() - size) / 2; int y = getY() + (getHeight() - size) / 2;
String state;
if (!RadioButton.this.isEnabled()) {
state = "Disabled";
} else if (RadioButton.this.isPressed()) {
state = "Pressed";
} else if (RadioButton.this.isHovered()) {
state = "Hovered";
} else if (RadioButton.this.isFocused()) {
state = "Focused";
} else {
state = "Inactive";
}
// Border // Border
cross(target, x, y, size, ColorScheme.get("Core:RadioButtonBorder" + state));
Vec4 borderColor;
if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) {
borderColor = Colors.BLUE;
} else {
borderColor = Colors.LIGHT_GRAY;
}
cross(target, x, y, size, borderColor);
// 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, ColorScheme.get("Core:RadioButtonCheck" + state)); cross(target, x + 4, y + 4, size - 8, Colors.BLUE);
} }
} }
@ -139,8 +146,8 @@ public class RadioButton extends BasicButton {
group.selectNext(); group.selectNext();
removeAction(group.listener); removeAction(group.listener);
group.buttons.remove(this); group.buttons.remove(this);
// Clear reference if this was the only button in the group group.getSelected(); // Clear reference if this was the only button
group.getSelected(); // in the group
} }
this.group = group; this.group = group;
@ -176,21 +183,22 @@ public class RadioButton extends BasicButton {
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
String state;
if (!RadioButton.this.isEnabled()) {
state = "Disabled";
} else if (RadioButton.this.isPressed()) {
state = "Pressed";
} else if (RadioButton.this.isHovered()) {
state = "Hovered";
} else if (RadioButton.this.isFocused()) {
state = "Focused";
} else {
state = "Inactive";
}
// Change label font color // Change label font color
getLabel().setFont(getLabel().getFont().withColor(ColorScheme.get("Core:RadioButtonText" + state)));
if (isPressed()) {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
} 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

@ -0,0 +1,23 @@
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 {
private final int margin; protected final int margin;
private double alignX, alignY; protected 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(child -> child.getPreferredSize()) .map(Component::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

@ -0,0 +1,56 @@
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), ColorScheme.get("Core:MenuLayerTint"), null); this.background = new Panel(name + ".Background", new LayoutAlign(10), Colors.toVector(0x66000000), 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(ColorScheme.get("Core:Text")).withAlign(0.5f); Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).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, ColorScheme.get("Core:Accent"), null); Panel panel = new Panel(getName() + ".Title.Underscore", null, Colors.BLUE, null);
panel.setLayout(new LayoutFill() { panel.setLayout(new LayoutFill() {
@Override @Override
public Vec2i calculatePreferredSize(Component c) { public Vec2i calculatePreferredSize(Component c) {

View File

@ -43,10 +43,8 @@ public class Region {
private static final boolean RESET_CORRUPTED = true; private static final boolean RESET_CORRUPTED = true;
public int loadedChunks; private final AtomicBoolean isUsing = new AtomicBoolean(false);
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;
@ -60,6 +58,7 @@ 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);
} }
@ -132,7 +131,7 @@ public class Region {
DecodingException { DecodingException {
isUsing.set(true); isUsing.set(true);
int dataOffset = 0; int dataOffset;
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 static enum SectorType { public 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<Integer>(); Set<Integer> used = new HashSet<>();
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,9 +63,10 @@ public class RegionFile {
} }
char prog; byte prog;
file.seek(0);
for (int i=0;i<4;i++) { for (int i=0;i<4;i++) {
prog = file.readChar(); prog = file.readByte();
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");
@ -109,7 +110,7 @@ public class RegionFile {
throw new IOException("A sector is used twice"); throw new IOException("A sector is used twice");
} }
file.seek(HEADER_SIZE + SECTOR_SIZE * offset); file.seek(HEADER_SIZE + (long) SECTOR_SIZE * offset);
byte type = file.readByte(); byte type = file.readByte();
if (type == SectorType.Data.data) { if (type == SectorType.Data.data) {
@ -131,25 +132,26 @@ 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 + SECTOR_SIZE * dataOffset); file.seek(HEADER_SIZE + (long) 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 + SECTOR_SIZE * (dataOffset + 1)) { if (file.length() > HEADER_SIZE + (long) SECTOR_SIZE * (dataOffset + 1)) {
file.seek(HEADER_SIZE + SECTOR_SIZE * (dataOffset + 1)); file.seek(HEADER_SIZE + (long) 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();
@ -157,7 +159,7 @@ public class RegionFile {
// partition place // partition place
{ {
int newOffset = allocateEmptySector(); int newOffset = allocateEmptySector();
file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset); file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset);
file.write(2); file.write(2);
file.writeInt(newOffset); file.writeInt(newOffset);
dataOffset = newOffset; dataOffset = newOffset;
@ -179,7 +181,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 + SECTOR_SIZE * dataOffset); file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset);
dataOffset++; dataOffset++;
file.write(tempBuffer); file.write(tempBuffer);
} }
@ -197,7 +199,7 @@ public class RegionFile {
file.seek(definitionOffset); file.seek(definitionOffset);
file.writeInt(dataOffset + 1); file.writeInt(dataOffset + 1);
file.setLength(HEADER_SIZE + dataOffset * SECTOR_SIZE); file.setLength(HEADER_SIZE + (long) dataOffset * SECTOR_SIZE);
return dataOffset; return dataOffset;
} }
@ -206,17 +208,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 + dataOffset * SECTOR_SIZE); file.setLength(HEADER_SIZE + (long) 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 + SECTOR_SIZE * dataOffset); file.seek(HEADER_SIZE + (long) 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;
@ -229,31 +231,24 @@ 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 " + Byte.toString(counter) "Sectors were read out of order\nExpected chunk number " + counter
+ " but encountered number " + Byte.toString(tempBuffer[1]) + " but encountered number " + 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];
for (int i = 0; i < buffer.length; i++) // TODO dedicated System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
// copy, java-y at
// least
{
newBuffer[i] = buffer[i];
}
buffer = newBuffer; buffer = newBuffer;
} }
for (int i = 0; i < SECTOR_SIZE - SECTOR_HEADER_SIZE - 1; i++) { System.arraycopy(tempBuffer, 2, buffer, bufferPos, SECTOR_SIZE - SECTOR_HEADER_SIZE - 1);
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 + SECTOR_SIZE * newOffset); file.seek(HEADER_SIZE + (long) SECTOR_SIZE * newOffset);
} else { } else {
throw new IOException("Invalid sector ID."); throw new IOException("Invalid sector ID.");
} }

View File

@ -0,0 +1,108 @@
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,7 +22,6 @@ 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;
@ -32,13 +31,15 @@ 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(ColorScheme.get("Core:Accent")).deriveBold(); Font aboutFont = font.withColor(0xFF37A3E6).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(ColorScheme.get("Core:Border")), "This is a MenuLayer")); getContent().addChild(new Label("Hint", new Font().withColor(Colors.LIGHT_GRAY), "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

@ -0,0 +1,53 @@
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,13 +1,11 @@
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 {
@ -15,13 +13,11 @@ 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 LayoutFill()); super(name, new LayoutAlign(15));
this.remover = remover; this.remover = remover;
Panel panel = new Panel(name + ".Background", new LayoutAlign(15), ColorScheme.get("Core:Background"), null); Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f);
Font titleFont = new Font().deriveBold().withColor(ColorScheme.get("Core:Text")).withAlign(0.5f); getRoot().addChild(new Label(name + ".Text", titleFont, value));
panel.addChild(new Label(name + ".Text", titleFont, value));
getRoot().addChild(panel);
} }
@Override @Override

View File

@ -1,16 +1,20 @@
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;
@ -24,34 +28,58 @@ 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 GUILayer { public class LayerTitle extends Background {
private final BasicButton resetButton; private final BasicButton resetButton;
public LayerTitle(String name) { public LayerTitle(String name) {
super(name, new LayoutAlign(0.5f, 0.7f, 15)); super(name, new LayoutAlign(0, 1f, 15), SimpleTextures.get("title/background"));
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));
MutableString title = new MutableStringLocalized("Layer" + name + ".Title"); Font titleFont = new Font().deriveBold().withColor(Colors.BLUE).withAlign(0.5f);
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f); content.addChild(new TextureComponent(name + ".Title", SimpleTextures.get("title/progressia")));
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");
content.addChild(new Button(name + ".Play", new Label(name + ".Play", buttonFont, playText)).addAction(this::startGame)); buttonContent.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);
content.addChild(resetButton); buttonContent.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");
content.addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> { buttonContent.addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> System.exit(0)));
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() {
@ -67,7 +95,7 @@ public class LayerTitle extends GUILayer {
throw CrashReports.report(e, "Problem with loading server"); throw CrashReports.report(e, "Problem with loading server");
} }
} }
private void resetWorld(BasicButton basicButton) { private void resetWorld(BasicButton basicButton) {
Path rootPath = Paths.get("tmp_world"); Path rootPath = Paths.get("tmp_world");
@ -88,8 +116,13 @@ public class LayerTitle extends GUILayer {
} catch (IOException e) { } catch (IOException e) {
throw CrashReports.report(e, "Could not reset world"); throw CrashReports.report(e, "Could not reset world");
} }
updateResetButton(); updateResetButton();
} }
private void openOptions(BasicButton basicButton) {
GUI.removeLayer(this);
GUI.addTopLayer(new LayerOptions("Options"));
}
} }

View File

@ -0,0 +1,33 @@
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

@ -1,80 +0,0 @@
# 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,5 +24,8 @@ 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,5 +24,8 @@ 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.

After

Width:  |  Height:  |  Size: 133 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB