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