Compare commits
12 Commits
add-items
...
title-scre
Author | SHA1 | Date | |
---|---|---|---|
22a744f65a | |||
c6de19cf19 | |||
c1a57f7d7a | |||
162b2249b1
|
|||
dececb4589
|
|||
ec17eb7065
|
|||
e4d0570200
|
|||
576cfed99f
|
|||
5af1b7309d | |||
0f0a94811f | |||
51bcca1499 | |||
ce9e95e5ce |
2
.gitattributes
vendored
@ -6,4 +6,4 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.bat text eol=crlf
|
||||
|
||||
*.nsi text eol=crlf
|
||||
|
480
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'
|
||||
|
||||
/*
|
||||
* 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'
|
||||
id 'java'
|
||||
|
||||
// GrGit
|
||||
// A JGit wrapper for Groovy used to access git commit info
|
||||
id 'org.ajoberstar.grgit' version '4.1.1'
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Configure Java version
|
||||
*/
|
||||
|
||||
java {
|
||||
/*
|
||||
* We're Java 8 for now.
|
||||
* Why? As of 2020, most users have Oracle Java, which only supports Java 8.
|
||||
*/
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
@ -34,6 +40,8 @@ compileJava {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Dependencies
|
||||
*/
|
||||
@ -42,7 +50,7 @@ repositories {
|
||||
mavenCentral()
|
||||
|
||||
/*
|
||||
* Specify Windcorp Maven repository
|
||||
* Windcorp Maven repository
|
||||
* Currently used by:
|
||||
* - ru.windcorp.fork.io.github.java-graphics:glm:1.0.1
|
||||
*/
|
||||
@ -72,230 +80,308 @@ dependencies {
|
||||
// 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
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* LWJGL
|
||||
* (auto-generated script)
|
||||
* ((here be dragons))
|
||||
* Version resolution
|
||||
*/
|
||||
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
import org.ajoberstar.grgit.*
|
||||
|
||||
project.ext.lwjglVersion = "3.2.3"
|
||||
// Pattern: vMAJOR.MINOR.PATCH[-SUFFIX]
|
||||
project.ext.tagFormat = /^v(\d+)\.(\d+)\.(\d+)(-[\w\-]*)?$/
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
|
||||
|
||||
implementation "org.lwjgl:lwjgl"
|
||||
implementation "org.lwjgl:lwjgl-glfw"
|
||||
implementation "org.lwjgl:lwjgl-openal"
|
||||
implementation "org.lwjgl:lwjgl-opengl"
|
||||
implementation "org.lwjgl:lwjgl-stb"
|
||||
|
||||
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")
|
||||
String version_parseVersion(String tag, boolean increment) {
|
||||
try {
|
||||
|
||||
def data = (tag =~ tagFormat)[0]
|
||||
|
||||
def major = data[1]
|
||||
def minor = data[2]
|
||||
def patch = data[3] as int
|
||||
def suffix = data[4] ?: ''
|
||||
|
||||
if (increment) {
|
||||
def oldVersion = "$major.$minor.$patch$suffix"
|
||||
patch++
|
||||
def newVersion = "$major.$minor.$patch$suffix"
|
||||
|
||||
logger.info "Version parsed from Git: $oldVersion, incremented to $newVersion"
|
||||
return newVersion
|
||||
} else {
|
||||
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 (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"
|
||||
Tag version_findRelevantTag(Grgit git) {
|
||||
def tags = git.tag.list()
|
||||
|
||||
def commits = [ git.head() ]
|
||||
def visited = new HashSet<>()
|
||||
|
||||
while (true) {
|
||||
if (commits.isEmpty()) return null
|
||||
|
||||
def nextCommits = new HashSet<>()
|
||||
|
||||
def formatSpecificationPrinted = false
|
||||
for (def commit : commits) {
|
||||
def tag = tags.findAll { it.commit == commit } ?.max { it.dateTime }
|
||||
|
||||
if (tag != null) {
|
||||
if (tag.name ==~ tagFormat) {
|
||||
return tag
|
||||
} else {
|
||||
if (!formatSpecificationPrinted) {
|
||||
formatSpecificationPrinted = true
|
||||
logger.info 'Expecting tag format: vMAJOR.MINOR.PATCH[-SUFFIX]'
|
||||
}
|
||||
logger.info 'Ignoring tag due to invalid format: {}', tag.name
|
||||
}
|
||||
}
|
||||
|
||||
nextCommits.addAll commit.parentIds.collect(git.resolve.&toCommit)
|
||||
}
|
||||
|
||||
visited.addAll commits
|
||||
nextCommits.removeAll visited
|
||||
commits = nextCommits
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
task resolveVersion {
|
||||
description 'Resolves version information from Git repository or project properties.'
|
||||
|
||||
doFirst {
|
||||
def classPath = []
|
||||
|
||||
configurations.runtimeClasspath.each {
|
||||
if (isDependencyRequested(it.getName())) {
|
||||
classPath.add("lib/" + it.getName())
|
||||
try {
|
||||
def git = Grgit.open(dir: project.projectDir)
|
||||
|
||||
project.ext.commit = git.head().id
|
||||
project.ext.branch = git.branch.current().name
|
||||
|
||||
if (project.version != 'unspecified') {
|
||||
// Leave version as-is
|
||||
return
|
||||
}
|
||||
|
||||
def tag = version_findRelevantTag(git)
|
||||
if (tag == null) {
|
||||
|
||||
String suffix
|
||||
if (project.hasProperty('buildId')) {
|
||||
suffix = project.buildId;
|
||||
} else {
|
||||
suffix = java.time.ZonedDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern('yyyy_MM_dd'))
|
||||
}
|
||||
project.version = "999.0.0-$suffix"
|
||||
|
||||
logger.warn 'Git repository does not contain an applicable tag, using dummy version {}\nSpecify version with -Pversion=1.2.3 or create a Git tag named v1.2.3', project.version
|
||||
|
||||
} else {
|
||||
println "\tRemoving from JAR classpath (not requested): " + it.getName()
|
||||
|
||||
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 = '-'
|
||||
project.ext.branch = '-'
|
||||
|
||||
logger.warn 'No Git repository found in project root, using dummy version {}\nSpecify version with -Pversion=1.2.3 or create a Git tag named v1.2.3', project.version
|
||||
}
|
||||
|
||||
if (classPath.size() == configurations.runtimeClasspath.size()) {
|
||||
println "Nothing removed from JAR classpath"
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes(
|
||||
"Main-Class": "ru.windcorp.progressia.client.ProgressiaClientMain",
|
||||
"Class-Path": configurations.runtimeClasspath.collect { "lib/" + it.getName() } .findAll { isDependencyRequested(it) } .join(' ')
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
doLast {
|
||||
if (!project.hasProperty('buildId')) {
|
||||
project.ext.buildId = '-'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jar.dependsOn specifyLocalManifest
|
||||
|
||||
|
||||
/*
|
||||
* Library export
|
||||
* Configure JAR manifest
|
||||
*/
|
||||
|
||||
task configureManifest {
|
||||
description 'Populates JAR manifest with Main-Class, Class-Path and version metadata.'
|
||||
|
||||
jar.dependsOn configureManifest
|
||||
dependsOn resolveVersion
|
||||
|
||||
doFirst {
|
||||
jar.manifest.attributes(
|
||||
'Main-Class': 'ru.windcorp.progressia.client.ProgressiaClientMain',
|
||||
'Class-Path': configurations.runtimeClasspath.collect { "lib/${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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Copy libraries into buil/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.'
|
||||
|
||||
jar.dependsOn exportLibs
|
||||
|
||||
into libsDirectory.get().getAsFile().getPath() + "/lib"
|
||||
exclude { !isDependencyRequested(it.getName()) }
|
||||
from configurations.runtimeClasspath
|
||||
into 'build/libs/lib'
|
||||
}
|
||||
|
||||
jar.dependsOn(exportLibs)
|
||||
|
||||
|
||||
/*
|
||||
* Packaging
|
||||
* Apply LWJGL logic
|
||||
*/
|
||||
apply from: 'build_logic/lwjgl.gradle'
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Packaging working directory configuration
|
||||
*/
|
||||
|
||||
task packageDebian(type: Exec) {
|
||||
description 'Builds the project and creates a Debain package.'
|
||||
group 'Progressia'
|
||||
|
||||
dependsOn build
|
||||
dependsOn requestLinuxDependencies
|
||||
|
||||
commandLine './buildPackages.sh', 'debian'
|
||||
import java.nio.file.*
|
||||
import java.nio.file.attribute.*
|
||||
|
||||
task createPackagingDirs() {
|
||||
description 'Resets build/tmp/packaging directory.'
|
||||
|
||||
doLast {
|
||||
println "Debian package available in build_packages/"
|
||||
def tmpDir = buildDir.toPath().resolve 'tmp/packaging'
|
||||
|
||||
def nuke = new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
|
||||
if (e == null) {
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
} else {
|
||||
// directory iteration failed
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fckn nuke tmpDir from orbit
|
||||
// I'm so done with deleting file trees in Java/Groovy/whatever
|
||||
// ...Not using File.deleteDir() because the latter recurses into symlinks, and we don't want to wipe build/libs/lib
|
||||
if (Files.exists(tmpDir)) {
|
||||
Files.walkFileTree tmpDir, nuke
|
||||
}
|
||||
|
||||
Files.createDirectories tmpDir.resolve('workingDir')
|
||||
Files.createDirectories buildDir.toPath().resolve('packages')
|
||||
}
|
||||
}
|
||||
|
||||
task linkBuildOutputForPackaging() {
|
||||
description 'Symlinks the contents of build/libs into packaging working directory.'
|
||||
|
||||
dependsOn build
|
||||
dependsOn createPackagingDirs
|
||||
|
||||
onlyIf { preparePackaging.ext.mode == 'symlink' }
|
||||
|
||||
doLast {
|
||||
def from = buildDir.toPath().resolve 'libs'
|
||||
def into = buildDir.toPath().resolve "tmp/packaging/workingDir/${preparePackaging.ext.buildDest}"
|
||||
|
||||
Files.createDirectories into
|
||||
|
||||
Files.list(from).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 into.resolve(it.fileName), it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task copyBuildOutputForPackaging(type: Copy) {
|
||||
description 'Copies the contents of build/libs into packaging working directory.'
|
||||
|
||||
dependsOn build
|
||||
dependsOn createPackagingDirs
|
||||
|
||||
onlyIf { preparePackaging.ext.mode == 'copy' }
|
||||
|
||||
from 'build/libs'
|
||||
filesMatching("${project.name}*.jar") {
|
||||
include tasks.jar.archiveFileName.get()
|
||||
}
|
||||
into "build/tmp/packaging/workingDir/${ -> preparePackaging.ext.buildDest}"
|
||||
}
|
||||
|
||||
task preparePackaging {
|
||||
preparePackaging.ext.buildDest = ''
|
||||
preparePackaging.ext.mode = 'symlink'
|
||||
|
||||
dependsOn createPackagingDirs
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
task packageWindows(type: Exec) {
|
||||
description 'Builds the project and creates a Windows installer.'
|
||||
group 'Progressia'
|
||||
|
||||
dependsOn build
|
||||
dependsOn requestWindowsDependencies
|
||||
|
||||
commandLine './buildPackages.sh', 'windows'
|
||||
|
||||
doLast {
|
||||
println "Windows installer available in build_packages/"
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Convenience build tasks
|
||||
*/
|
||||
|
||||
task buildCrossPlatform {
|
||||
description 'Builds the project including native libraries for all available platforms.'
|
||||
@ -305,17 +391,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
|
117
build_logic/lwjgl.gradle
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Build logic for Progressia
|
||||
* LWJGL dependency logic
|
||||
*/
|
||||
|
||||
project.ext.lwjgl = new HashMap<>()
|
||||
|
||||
// Version of LWJGL
|
||||
lwjgl.version = '3.2.3'
|
||||
|
||||
/*
|
||||
* 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<>()
|
||||
|
||||
// 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 = 'macos'
|
||||
break
|
||||
case OperatingSystem.WINDOWS:
|
||||
lwjgl.localArch = System.getProperty('os.arch').contains('64') ? 'windows' : 'windows-x86'
|
||||
break
|
||||
}
|
||||
|
||||
// Declare pure-Java dependencies
|
||||
dependencies {
|
||||
// BOM
|
||||
implementation platform("org.lwjgl:lwjgl-bom:${lwjgl.version}")
|
||||
|
||||
// Core
|
||||
implementation 'org.lwjgl:lwjgl'
|
||||
|
||||
// Components
|
||||
lwjgl.libraries.each { implementation "org.lwjgl:lwjgl-$it" }
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds LWJGL native libraries to runtimeOnly configuration
|
||||
*/
|
||||
task lwjgl_addNativesToRuntimeOnly {
|
||||
// Make sure runtimeOnly has not been resolved
|
||||
compileJava.dependsOn lwjgl_addNativesToRuntimeOnly
|
||||
configureManifest.dependsOn lwjgl_addNativesToRuntimeOnly
|
||||
exportLibs.dependsOn 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(', ')
|
||||
}
|
||||
|
||||
dependencies {
|
||||
lwjgl.targets.each { target ->
|
||||
runtimeOnly "org.lwjgl:lwjgl::natives-$target"
|
||||
lwjgl.libraries.each { lib ->
|
||||
runtimeOnly "org.lwjgl:lwjgl-$lib::natives-$target"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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-x86'
|
||||
requestTask 'MacOS', 'macos'
|
38
build_logic/packaging/deb/script.gradle
Normal file
@ -0,0 +1,38 @@
|
||||
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
|
||||
|
||||
executable 'dpkg-deb'
|
||||
args '--root-owner-group'
|
||||
args '--build', 'build/tmp/packaging/workingDir'
|
||||
args 'build/packages'
|
||||
}
|
50
build_logic/packaging/nsis/script.gradle
Normal file
@ -0,0 +1,50 @@
|
||||
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
|
||||
|
||||
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'
|
||||
}
|
41
build_logic/packaging/zip/script.gradle
Normal file
@ -0,0 +1,41 @@
|
||||
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
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
@ -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.
|
||||
|
103
docs/building/BuildScriptReference.md
Normal file
@ -0,0 +1,103 @@
|
||||
# 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` 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.
|
||||
|
||||
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 and Git branch are correspond to the state of the local Git repository, if any. In case Git metadata is
|
||||
unavailable, `-` fallback is used for both fields.
|
||||
|
||||
### Build ID
|
||||
|
||||
Build ID uniquely identifies artifacts produced by automated build systems. For example, builds executed by WindCorp
|
||||
Jenkins suite have build IDs like `WJ3` or `WJ142`. Build ID must be provided explicitly; it is `-` unless specified
|
||||
otherwise.
|
||||
|
||||
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-x86` | `requestWindowsDependencies` |
|
||||
| `macos` | `requestMacOSDependencies` |
|
1
logs/game.log
Normal file
@ -0,0 +1 @@
|
||||
22:26:25.948 [Music Thread ] WARN ru.windcorp.progressia.test.TestMusicPlayer > No music found
|
@ -15,9 +15,180 @@
|
||||
* 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;
|
||||
|
||||
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;
|
||||
@ -32,6 +34,8 @@ public class ProgressiaLauncher {
|
||||
public static void launch(String[] args, Proxy proxy) {
|
||||
arguments = args.clone();
|
||||
setupCrashReports();
|
||||
|
||||
LogManager.getRootLogger().info("Launching " + Progressia.getName() + " version " + Progressia.getFullVersion());
|
||||
|
||||
proxy.initialize();
|
||||
ProgressiaLauncher.proxy = proxy;
|
||||
@ -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());
|
||||
|
@ -15,20 +15,30 @@
|
||||
* 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 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.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 {
|
||||
|
||||
@ -63,14 +73,20 @@ class LWJGLInitializer {
|
||||
glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE);
|
||||
|
||||
long handle = glfwCreateWindow(900, 900, "ProgressiaTest", NULL, NULL);
|
||||
long handle = glfwCreateWindow(
|
||||
800,
|
||||
600,
|
||||
Progressia.getName() + " " + Progressia.getFullerVersion(),
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
// TODO Check that handle != NULL
|
||||
|
||||
GraphicsBackend.setWindowHandle(handle);
|
||||
|
||||
glfwMakeContextCurrent(handle);
|
||||
glfwSwapInterval(0); // TODO: remove after config system is added
|
||||
glfwSwapInterval(0); // TODO: remove after config system is added
|
||||
}
|
||||
|
||||
private static void positionWindow() {
|
||||
@ -79,8 +95,30 @@ class LWJGLInitializer {
|
||||
}
|
||||
|
||||
private static void createWindowIcons() {
|
||||
// TODO Auto-generated method stub
|
||||
if (glfwGetVersionString().toLowerCase().contains("wayland")) {
|
||||
// glfwSetWindowIcon is not supported on Wayland
|
||||
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() {
|
||||
@ -112,19 +150,19 @@ class LWJGLInitializer {
|
||||
glfwSetScrollCallback(handle, InputHandler::handleWheelScroll);
|
||||
|
||||
GraphicsInterface.subscribeToInputEvents(new Object() {
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onFrameResized(FrameResizeEvent event) {
|
||||
GUI.invalidateEverything();
|
||||
}
|
||||
|
||||
|
||||
@Subscribe
|
||||
public void onInputEvent(InputEvent event) {
|
||||
GUI.dispatchInput(event);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -0,0 +1,28 @@
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import glm.mat._4.Mat4;
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
|
||||
public class Background extends GUILayer {
|
||||
|
||||
protected Texture backgroundTexture;
|
||||
|
||||
public Background(String name, Layout layout, Texture inTexture) {
|
||||
super(name, layout);
|
||||
|
||||
backgroundTexture = inTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assemble(RenderTarget target) {
|
||||
getRoot().setBounds(0, 0, getWidth(), getHeight());
|
||||
getRoot().invalidate();
|
||||
target.pushTransform(new Mat4(1).translate(new Vec3(0,0,500)));
|
||||
target.drawTexture(0, 0, getWidth(), getHeight(), backgroundTexture);
|
||||
target.popTransform();
|
||||
getRoot().assemble(target);
|
||||
}
|
||||
|
||||
}
|
@ -23,6 +23,10 @@ import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
|
||||
/** Class for a traditional button that gets clicked to activate
|
||||
*
|
||||
* @author opfromthestart
|
||||
*/
|
||||
public class Button extends BasicButton {
|
||||
|
||||
public Button(String name, String label, Font labelFont) {
|
||||
@ -51,9 +55,7 @@ public class Button extends BasicButton {
|
||||
|
||||
// Inside area
|
||||
|
||||
if (isPressed()) {
|
||||
// Do nothing
|
||||
} else {
|
||||
if (!isPressed()) {
|
||||
Vec4 backgroundColor;
|
||||
if (isHovered() && isEnabled()) {
|
||||
backgroundColor = Colors.HOVER_BLUE;
|
||||
|
@ -0,0 +1,23 @@
|
||||
package ru.windcorp.progressia.client.graphics.gui;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.texture.Texture;
|
||||
|
||||
public class TextureComponent extends Component {
|
||||
|
||||
private final Texture texture;
|
||||
|
||||
public TextureComponent(String name, Texture texture2) {
|
||||
super(name);
|
||||
|
||||
texture = texture2;
|
||||
setPreferredSize(texture.getSprite().getWidth(),texture.getSprite().getHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target)
|
||||
{
|
||||
target.drawTexture(getX(), getY(), getWidth(), getHeight(), texture);
|
||||
}
|
||||
|
||||
}
|
@ -27,8 +27,8 @@ import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||
|
||||
public class LayoutAlign implements Layout {
|
||||
|
||||
private final int margin;
|
||||
private double alignX, alignY;
|
||||
protected final int margin;
|
||||
protected double alignX, alignY;
|
||||
|
||||
public LayoutAlign(double alignX, double alignY, int margin) {
|
||||
this.alignX = alignX;
|
||||
@ -72,7 +72,7 @@ public class LayoutAlign implements Layout {
|
||||
Vec2i result = new Vec2i(0, 0);
|
||||
|
||||
c.getChildren().stream()
|
||||
.map(child -> child.getPreferredSize())
|
||||
.map(Component::getPreferredSize)
|
||||
.forEach(size -> {
|
||||
result.x = max(size.x, result.x);
|
||||
result.y = max(size.y, result.y);
|
||||
|
@ -0,0 +1,56 @@
|
||||
package ru.windcorp.progressia.client.graphics.gui.layout;
|
||||
|
||||
import glm.vec._2.i.Vec2i;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Layout;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
public class LayoutEdges implements Layout {
|
||||
|
||||
private final int margin;
|
||||
|
||||
public LayoutEdges(int margin) {
|
||||
this.margin = margin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layout(Component c) {
|
||||
for (int i=0;i<2;i++)
|
||||
{
|
||||
Component child = c.getChild(i);
|
||||
|
||||
Vec2i size = child.getPreferredSize();
|
||||
|
||||
int cWidth = c.getWidth() - 2 * margin;
|
||||
int cHeight = c.getHeight() - 2 * margin;
|
||||
|
||||
size.x = min(size.x, cWidth);
|
||||
size.y = min(size.y, cHeight);
|
||||
|
||||
if (i==0) {
|
||||
child.setBounds(
|
||||
c.getX() + margin,
|
||||
c.getY(),
|
||||
size
|
||||
);
|
||||
} else {
|
||||
child.setBounds(
|
||||
1920 - size.x - margin,
|
||||
c.getY(),
|
||||
size
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec2i calculatePreferredSize(Component c) {
|
||||
Vec2i result = new Vec2i(1920,0);
|
||||
c.getChildren().stream()
|
||||
.map(Component::getPreferredSize)
|
||||
.forEach(size -> result.y = max(Math.abs(size.y), result.y));
|
||||
return result;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -41,9 +41,17 @@ public class TextureLoader {
|
||||
|
||||
int width = readResult.getWidth();
|
||||
int height = readResult.getHeight();
|
||||
|
||||
int bufferWidth;
|
||||
int bufferHeight;
|
||||
|
||||
int bufferWidth = BinUtil.roundToGreaterPowerOf2(width);
|
||||
int bufferHeight = BinUtil.roundToGreaterPowerOf2(height);
|
||||
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";
|
||||
}
|
||||
|
||||
}
|
@ -43,10 +43,8 @@ public class Region {
|
||||
|
||||
private static final boolean RESET_CORRUPTED = true;
|
||||
|
||||
public int loadedChunks;
|
||||
|
||||
private AtomicBoolean isUsing = new AtomicBoolean(false);
|
||||
private AtomicBoolean isClosed = new AtomicBoolean(false);
|
||||
private final AtomicBoolean isUsing = new AtomicBoolean(false);
|
||||
private final AtomicBoolean isClosed = new AtomicBoolean(false);
|
||||
|
||||
private final RegionFile file;
|
||||
|
||||
@ -60,6 +58,7 @@ public class Region {
|
||||
} catch (IOException e) {
|
||||
|
||||
RegionWorldContainer.LOG.debug("Uh the file broke");
|
||||
RegionWorldContainer.LOG.debug(e.getLocalizedMessage());
|
||||
if (RESET_CORRUPTED) {
|
||||
this.file.makeHeader(regionCoords);
|
||||
}
|
||||
@ -132,7 +131,7 @@ public class Region {
|
||||
DecodingException {
|
||||
isUsing.set(true);
|
||||
|
||||
int dataOffset = 0;
|
||||
int dataOffset;
|
||||
Vec3i pos = RegionWorldContainer.getInRegionCoords(chunkPos);
|
||||
|
||||
if (hasOffset(pos)) {
|
||||
|
@ -26,9 +26,9 @@ public class RegionFile {
|
||||
private static final int ID_HEADER_SIZE = 16;
|
||||
private static final byte[] HEADER_ID = {'P','R','O','G'};
|
||||
|
||||
final byte endBytes[] = new byte[SECTOR_SIZE];
|
||||
final byte[] endBytes = new byte[SECTOR_SIZE];
|
||||
|
||||
public static enum SectorType {
|
||||
public enum SectorType {
|
||||
Ending(0), // Just an empty block
|
||||
Data(1), // has a byte counting up in position 1, and then
|
||||
PartitionLink(2),
|
||||
@ -54,7 +54,7 @@ public class RegionFile {
|
||||
|
||||
public void confirmHeaderHealth(ChunkMap<Integer> offsets, Vec3i regionCoords) throws IOException {
|
||||
|
||||
Set<Integer> used = new HashSet<Integer>();
|
||||
Set<Integer> used = new HashSet<>();
|
||||
int maxUsed = 0;
|
||||
final int chunksPerRegion = REGION_DIAMETER * REGION_DIAMETER * REGION_DIAMETER;
|
||||
|
||||
@ -63,9 +63,10 @@ public class RegionFile {
|
||||
}
|
||||
|
||||
|
||||
char prog;
|
||||
byte prog;
|
||||
file.seek(0);
|
||||
for (int i=0;i<4;i++) {
|
||||
prog = file.readChar();
|
||||
prog = file.readByte();
|
||||
if (prog != HEADER_ID[i])
|
||||
{
|
||||
throw new IOException("File is not a .progressia_chunk file");
|
||||
@ -109,7 +110,7 @@ public class RegionFile {
|
||||
throw new IOException("A sector is used twice");
|
||||
}
|
||||
|
||||
file.seek(HEADER_SIZE + SECTOR_SIZE * offset);
|
||||
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * offset);
|
||||
byte type = file.readByte();
|
||||
|
||||
if (type == SectorType.Data.data) {
|
||||
@ -131,25 +132,26 @@ public class RegionFile {
|
||||
}
|
||||
|
||||
public void makeHeader(Vec3i regionCoords) throws IOException {
|
||||
file.seek(0);
|
||||
for (int i = 0; i < HEADER_SIZE; i++) {
|
||||
file.write(0);
|
||||
}
|
||||
file.seek(0);
|
||||
file.write(HEADER_ID);
|
||||
file.writeInt(regionCoords.x);
|
||||
file.writeInt(regionCoords.y);
|
||||
file.writeInt(regionCoords.z);
|
||||
for (int i = 0; i < HEADER_SIZE; i++) {
|
||||
file.write(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeBuffer(byte[] buffer, int dataOffset, Vec3i pos) throws IOException {
|
||||
file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset);
|
||||
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset);
|
||||
int loc = 0;
|
||||
byte tempBuffer[] = new byte[SECTOR_SIZE];
|
||||
byte[] tempBuffer = new byte[SECTOR_SIZE];
|
||||
byte counter = 0;
|
||||
boolean isDone = false;
|
||||
while (!isDone) {
|
||||
if (file.length() > HEADER_SIZE + SECTOR_SIZE * (dataOffset + 1)) {
|
||||
file.seek(HEADER_SIZE + SECTOR_SIZE * (dataOffset + 1));
|
||||
if (file.length() > HEADER_SIZE + (long) SECTOR_SIZE * (dataOffset + 1)) {
|
||||
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * (dataOffset + 1));
|
||||
byte header = file.readByte();
|
||||
if (header == SectorType.Data.data) {
|
||||
byte fileCounter = file.readByte();
|
||||
@ -157,7 +159,7 @@ public class RegionFile {
|
||||
// partition place
|
||||
{
|
||||
int newOffset = allocateEmptySector();
|
||||
file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset);
|
||||
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset);
|
||||
file.write(2);
|
||||
file.writeInt(newOffset);
|
||||
dataOffset = newOffset;
|
||||
@ -179,7 +181,7 @@ public class RegionFile {
|
||||
if (file.getFilePointer() < 256)
|
||||
LogManager.getLogger("Region")
|
||||
.debug("at {}, ({},{},{}), {}", file.getFilePointer(), pos.x, pos.y, pos.z, dataOffset);
|
||||
file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset);
|
||||
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset);
|
||||
dataOffset++;
|
||||
file.write(tempBuffer);
|
||||
}
|
||||
@ -197,7 +199,7 @@ public class RegionFile {
|
||||
file.seek(definitionOffset);
|
||||
file.writeInt(dataOffset + 1);
|
||||
|
||||
file.setLength(HEADER_SIZE + dataOffset * SECTOR_SIZE);
|
||||
file.setLength(HEADER_SIZE + (long) dataOffset * SECTOR_SIZE);
|
||||
return dataOffset;
|
||||
}
|
||||
|
||||
@ -206,17 +208,17 @@ public class RegionFile {
|
||||
|
||||
int dataOffset = (int) Math.ceil((double) (outputLen - HEADER_SIZE) / SECTOR_SIZE);
|
||||
|
||||
file.setLength(HEADER_SIZE + dataOffset * SECTOR_SIZE);
|
||||
file.setLength(HEADER_SIZE + (long) dataOffset * SECTOR_SIZE);
|
||||
|
||||
return dataOffset;
|
||||
}
|
||||
|
||||
public byte[] readBuffer(int dataOffset) throws IOException {
|
||||
file.seek(HEADER_SIZE + SECTOR_SIZE * dataOffset);
|
||||
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * dataOffset);
|
||||
|
||||
int bufferPos = 0;
|
||||
byte buffer[] = new byte[SECTOR_SIZE * 16];
|
||||
byte tempBuffer[] = new byte[SECTOR_SIZE];
|
||||
byte[] buffer = new byte[SECTOR_SIZE * 16];
|
||||
byte[] tempBuffer = new byte[SECTOR_SIZE];
|
||||
|
||||
boolean reachedEnd = false;
|
||||
byte counter = 0;
|
||||
@ -229,31 +231,24 @@ public class RegionFile {
|
||||
if (tempBuffer[0] == SectorType.Data.data) {
|
||||
if (tempBuffer[1] != counter) {
|
||||
throw new IOException(
|
||||
"Sectors were read out of order\nExpected chunk number " + Byte.toString(counter)
|
||||
+ " but encountered number " + Byte.toString(tempBuffer[1])
|
||||
"Sectors were read out of order\nExpected chunk number " + counter
|
||||
+ " but encountered number " + tempBuffer[1]
|
||||
);
|
||||
}
|
||||
counter++;
|
||||
if (buffer.length - bufferPos < SECTOR_SIZE - SECTOR_HEADER_SIZE - 1) {
|
||||
byte newBuffer[] = new byte[buffer.length + SECTOR_SIZE * 16];
|
||||
for (int i = 0; i < buffer.length; i++) // TODO dedicated
|
||||
// copy, java-y at
|
||||
// least
|
||||
{
|
||||
newBuffer[i] = buffer[i];
|
||||
}
|
||||
byte[] newBuffer = new byte[buffer.length + SECTOR_SIZE * 16];
|
||||
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
|
||||
buffer = newBuffer;
|
||||
}
|
||||
for (int i = 0; i < SECTOR_SIZE - SECTOR_HEADER_SIZE - 1; i++) {
|
||||
buffer[bufferPos + i] = tempBuffer[i + 2];
|
||||
}
|
||||
System.arraycopy(tempBuffer, 2, buffer, bufferPos, SECTOR_SIZE - SECTOR_HEADER_SIZE - 1);
|
||||
bufferPos += SECTOR_SIZE - SECTOR_HEADER_SIZE - 1;
|
||||
} else if (tempBuffer[0] == SectorType.Ending.data) {
|
||||
reachedEnd = true;
|
||||
} else if (tempBuffer[0] == SectorType.PartitionLink.data) {
|
||||
ByteBuffer intBuffer = ByteBuffer.wrap(tempBuffer);
|
||||
int newOffset = intBuffer.getInt(1);
|
||||
file.seek(HEADER_SIZE + SECTOR_SIZE * newOffset);
|
||||
file.seek(HEADER_SIZE + (long) SECTOR_SIZE * newOffset);
|
||||
} else {
|
||||
throw new IOException("Invalid sector ID.");
|
||||
}
|
||||
|
108
src/main/java/ru/windcorp/progressia/test/CubeComponent.java
Normal file
@ -0,0 +1,108 @@
|
||||
package ru.windcorp.progressia.test;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import glm.mat._4.Mat4;
|
||||
import glm.vec._3.Vec3;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
|
||||
public class CubeComponent extends Component {
|
||||
|
||||
private final Mat4[] transforms;
|
||||
private final Vec4[] normals;
|
||||
private final long startTime;
|
||||
|
||||
private final double r3 = Math.sqrt(3+.01);
|
||||
|
||||
private final int size;
|
||||
|
||||
public CubeComponent(String name, int size) {
|
||||
super(name);
|
||||
this.size = size;
|
||||
transforms = new Mat4[6];
|
||||
normals = new Vec4[6];
|
||||
setPreferredSize((int) Math.ceil(r3*size),(int) Math.ceil(r3*size));
|
||||
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
|
||||
executor.scheduleAtFixedRate(this::requestReassembly, 1, 60, TimeUnit.MILLISECONDS);
|
||||
startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// Notes to me
|
||||
// z axis is through the screen
|
||||
// y is horizontal spin
|
||||
// x is vertical spin
|
||||
|
||||
|
||||
private void computeTransforms()
|
||||
{
|
||||
//Creates all of the sides
|
||||
transforms[0] = new Mat4(1);
|
||||
transforms[1] = new Mat4(1);
|
||||
transforms[2] = new Mat4(1);
|
||||
transforms[3] = new Mat4(1);
|
||||
transforms[4] = new Mat4(1);
|
||||
transforms[5] = new Mat4(1);
|
||||
|
||||
//Gets time since creation(for rotation amount)
|
||||
long time = System.currentTimeMillis()-startTime;
|
||||
|
||||
//Initializes the way each face is facing
|
||||
normals[0] = new Vec4(0,0,-1,0);
|
||||
normals[1] = new Vec4(0,1,0,0);
|
||||
normals[2] = new Vec4(1,0,0,0);
|
||||
normals[3] = new Vec4(0,0,1,0);
|
||||
normals[4] = new Vec4(0,-1,0,0);
|
||||
normals[5] = new Vec4(-1,0,0,0);
|
||||
|
||||
for (int i=0;i<6;i++)
|
||||
{
|
||||
//Rotates given side with the time one first, then ot get it on its off axis, then gets the image of each axis under the given rotation
|
||||
//The rotate functions do change the transforms, but the multiplication does not
|
||||
normals[i] = transforms[i].rotate((float) (time%(6000*6.28) )/ 6000, new Vec3(0,1,0)).rotate((float) 24, new Vec3(1,.5,0)).mul_(normals[i]);
|
||||
}
|
||||
double pi2 = Math.PI / 2;
|
||||
|
||||
//Move and rotate the sides from the middle of the cube to the appropriate edges
|
||||
transforms[0].translate(new Vec3(-size/2f,-size/2f,size/2f));
|
||||
transforms[1].translate(new Vec3(-size/2f,-size/2f,-size/2f)).rotate((float) pi2, new Vec3(1,0,0));
|
||||
transforms[2].translate(new Vec3(-size/2f,-size/2f,size/2f)).rotate((float) pi2, new Vec3(0,1,0));
|
||||
transforms[3].translate(new Vec3(-size/2f,-size/2f,-size/2f));
|
||||
transforms[4].translate(new Vec3(-size/2f,size/2f,-size/2f)).rotate((float) pi2, new Vec3(1,0,0));
|
||||
transforms[5].translate(new Vec3(size/2f,-size/2f,size/2f)).rotate((float) pi2, new Vec3(0,1,0));
|
||||
|
||||
for (int i=0;i<6;i++) // I have no clue why this is necessary, without it the sides of the cube mess up; may need to be changed if the title screen changes position.
|
||||
{
|
||||
transforms[i] = transforms[i].translate(new Vec3(0,0,17.5-3*(i<2 ? 1 : 0)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assembleSelf(RenderTarget target)
|
||||
{
|
||||
computeTransforms();
|
||||
|
||||
setPosition(750,780);
|
||||
|
||||
target.pushTransform(new Mat4(1).translate(new Vec3(getX()+size*r3/2,getY()-size*r3/2,0))); //-size*r3/2
|
||||
|
||||
for (int b=0; b<6;b++)
|
||||
{
|
||||
target.pushTransform(transforms[b]);
|
||||
|
||||
float dot = normals[b].dot(new Vec4(-1,0,0,0)); //Gets the "amount" the given side is pointing in the -x direction
|
||||
|
||||
Vec4 color = new Vec4(.4+.3*dot, .4+.3*dot, .6+.4*dot,1.0); //More aligned means brighter color
|
||||
|
||||
target.fill(0,0, size, size, color);
|
||||
|
||||
target.popTransform();
|
||||
}
|
||||
|
||||
target.popTransform();
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
|
||||
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;
|
||||
@ -30,6 +31,8 @@ import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||
|
||||
public class LayerAbout extends GUILayer {
|
||||
|
||||
public static String version = "pre-alpha 3";
|
||||
|
||||
public LayerAbout() {
|
||||
super("LayerAbout", new LayoutAlign(1, 1, 5));
|
||||
|
||||
@ -50,7 +53,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())
|
||||
)
|
||||
);
|
||||
|
||||
|
53
src/main/java/ru/windcorp/progressia/test/LayerOptions.java
Normal file
@ -0,0 +1,53 @@
|
||||
package ru.windcorp.progressia.test;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.Colors;
|
||||
import ru.windcorp.progressia.client.graphics.GUI;
|
||||
import ru.windcorp.progressia.client.graphics.font.Font;
|
||||
import ru.windcorp.progressia.client.graphics.gui.*;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||
import ru.windcorp.progressia.client.graphics.texture.SimpleTextures;
|
||||
import ru.windcorp.progressia.client.localization.Localizer;
|
||||
import ru.windcorp.progressia.client.localization.MutableString;
|
||||
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LayerOptions extends Background {
|
||||
public LayerOptions(String name) {
|
||||
super(name, new LayoutAlign(0, 1f, 15), SimpleTextures.get("title/background"));
|
||||
|
||||
Group content = new Group("Layer" + name + ".Group", new LayoutVertical(15));
|
||||
|
||||
Font font = new Font().withColor(Colors.BLUE).withAlign(0.5f);
|
||||
|
||||
MutableString languageText = new MutableStringLocalized("Layer" + name + ".Language");
|
||||
content.addChild(new Button(name + ".Language", new Label(name + ".Language", font, languageText)).addAction(this::toggleLanguage));
|
||||
|
||||
MutableString playText = new MutableStringLocalized("Layer" + name + ".Return");
|
||||
content.addChild(new Button(name + ".Return", new Label(name + ".Return", font, playText)).addAction(this::openTitle));
|
||||
|
||||
getRoot().addChild(content);
|
||||
}
|
||||
|
||||
private void openTitle(BasicButton basicButton) {
|
||||
GUI.removeLayer(this);
|
||||
GUI.addTopLayer(new LayerTitle("Title"));
|
||||
}
|
||||
|
||||
private void toggleLanguage(BasicButton basicButton)
|
||||
{
|
||||
String curLang = Localizer.getInstance().getLanguage();
|
||||
List<String> allLangs = Localizer.getInstance().getLanguages();
|
||||
int pos = allLangs.indexOf(curLang);
|
||||
pos++;
|
||||
if (pos >= allLangs.size())
|
||||
{
|
||||
Localizer.getInstance().setLanguage(allLangs.get(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
Localizer.getInstance().setLanguage(allLangs.get(pos));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,20 @@
|
||||
package ru.windcorp.progressia.test;
|
||||
|
||||
import ru.windcorp.progressia.Progressia;
|
||||
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.Background;
|
||||
import ru.windcorp.progressia.client.graphics.gui.BasicButton;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Button;
|
||||
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Group;
|
||||
import ru.windcorp.progressia.client.graphics.gui.Label;
|
||||
import ru.windcorp.progressia.client.graphics.gui.TextureComponent;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutEdges;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||
import ru.windcorp.progressia.client.graphics.texture.SimpleTextures;
|
||||
import ru.windcorp.progressia.client.localization.MutableString;
|
||||
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
|
||||
import ru.windcorp.progressia.common.util.crash.CrashReports;
|
||||
@ -24,34 +28,58 @@ import java.nio.file.Paths;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
public class LayerTitle extends GUILayer {
|
||||
|
||||
public class LayerTitle extends Background {
|
||||
|
||||
private final BasicButton resetButton;
|
||||
|
||||
public LayerTitle(String name) {
|
||||
super(name, new LayoutAlign(0.5f, 0.7f, 15));
|
||||
super(name, new LayoutAlign(0, 1f, 15), SimpleTextures.get("title/background"));
|
||||
Group content = new Group("Layer" + name + ".Group", new LayoutVertical(15));
|
||||
Group info = new Group("Layer"+name+".InfoGroup", new LayoutEdges(30));
|
||||
Group buttonContent = new Group("Layer" + name + ".ButtonGroup", new LayoutColumn(15, 320));
|
||||
|
||||
MutableString title = new MutableStringLocalized("Layer" + name + ".Title");
|
||||
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f);
|
||||
content.addChild(new Label(name + ".Title", titleFont, title));
|
||||
Font titleFont = new Font().deriveBold().withColor(Colors.BLUE).withAlign(0.5f);
|
||||
content.addChild(new TextureComponent(name + ".Title", SimpleTextures.get("title/progressia")));
|
||||
|
||||
info.addChild(new Label(
|
||||
"About",
|
||||
titleFont,
|
||||
new MutableStringLocalized("LayerAbout.Title")
|
||||
)
|
||||
);
|
||||
|
||||
info.addChild(
|
||||
new Label(
|
||||
"Version",
|
||||
titleFont,
|
||||
Progressia.getFullerVersion()
|
||||
)
|
||||
);
|
||||
content.addChild(info);
|
||||
|
||||
Font buttonFont = titleFont.deriveNotBold();
|
||||
MutableString playText = new MutableStringLocalized("Layer" + name + ".Play");
|
||||
content.addChild(new Button(name + ".Play", new Label(name + ".Play", buttonFont, playText)).addAction(this::startGame));
|
||||
|
||||
buttonContent.addChild(new Button(name + ".Play", new Label(name + ".Play", buttonFont, playText)).addAction(this::startGame));
|
||||
|
||||
MutableString resetText = new MutableStringLocalized("Layer" + name + ".Reset");
|
||||
this.resetButton = new Button(name + ".Reset", new Label(name + ".Reset", buttonFont, resetText)).addAction(this::resetWorld);
|
||||
content.addChild(resetButton);
|
||||
|
||||
buttonContent.addChild(resetButton);
|
||||
|
||||
updateResetButton();
|
||||
|
||||
MutableString settingsText = new MutableStringLocalized("Layer" + name + ".Options");
|
||||
buttonContent.addChild(new Button(name + ".Options", new Label(name + ".Options", buttonFont, settingsText)).addAction(this::openOptions));
|
||||
|
||||
MutableString quitText = new MutableStringLocalized("Layer" + name + ".Quit");
|
||||
content.addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> {
|
||||
System.exit(0);
|
||||
}));
|
||||
|
||||
buttonContent.addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> System.exit(0)));
|
||||
|
||||
content.addChild(buttonContent);
|
||||
getRoot().addChild(content);
|
||||
buttonContent.setPreferredSize(500, 1000);
|
||||
|
||||
CubeComponent cube = new CubeComponent(name+".Cube",300);
|
||||
|
||||
getRoot().addChild(cube);
|
||||
}
|
||||
|
||||
private void updateResetButton() {
|
||||
@ -67,7 +95,7 @@ public class LayerTitle extends GUILayer {
|
||||
throw CrashReports.report(e, "Problem with loading server");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void resetWorld(BasicButton basicButton) {
|
||||
Path rootPath = Paths.get("tmp_world");
|
||||
|
||||
@ -88,8 +116,13 @@ public class LayerTitle extends GUILayer {
|
||||
} catch (IOException e) {
|
||||
throw CrashReports.report(e, "Could not reset world");
|
||||
}
|
||||
|
||||
|
||||
updateResetButton();
|
||||
}
|
||||
|
||||
private void openOptions(BasicButton basicButton) {
|
||||
GUI.removeLayer(this);
|
||||
GUI.addTopLayer(new LayerOptions("Options"));
|
||||
}
|
||||
|
||||
}
|
||||
|
33
src/main/java/ru/windcorp/progressia/test/LayoutColumn.java
Normal file
@ -0,0 +1,33 @@
|
||||
package ru.windcorp.progressia.test;
|
||||
|
||||
import ru.windcorp.progressia.client.graphics.gui.Component;
|
||||
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
|
||||
|
||||
public class LayoutColumn extends LayoutVertical {
|
||||
|
||||
protected int maxWidth;
|
||||
private final int margin;
|
||||
|
||||
public LayoutColumn(int gap, int maxWidth)
|
||||
{
|
||||
super(gap);
|
||||
this.maxWidth = maxWidth;
|
||||
margin = gap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layout(Component c) {
|
||||
int x = c.getX() + margin,
|
||||
y = c.getY() + c.getHeight();
|
||||
|
||||
synchronized (c.getChildren()) {
|
||||
for (Component child : c.getChildren()) {
|
||||
|
||||
int height = child.getPreferredSize().y;
|
||||
y -= margin + height;
|
||||
child.setBounds(x, y, maxWidth, height);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
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
|
@ -24,5 +24,8 @@ LayerTitle.Reset = Reset World
|
||||
LayerTitle.Options = Options
|
||||
LayerTitle.Quit = Quit
|
||||
|
||||
LayerOptions.Return = Back To Menu
|
||||
LayerOptions.Language = US English
|
||||
|
||||
LayerText.Load = Loading...
|
||||
LayerText.Save = Saving...
|
@ -24,5 +24,8 @@ LayerTitle.Reset = Сбросить мир
|
||||
LayerTitle.Options = Настройки
|
||||
LayerTitle.Quit = Выход
|
||||
|
||||
LayerOptions.Return = Главное меню
|
||||
LayerOptions.Language = Русский
|
||||
|
||||
LayerText.Load = Загрузка...
|
||||
LayerText.Save = Сохранение...
|
BIN
src/main/resources/assets/textures/title/background.png
Normal file
After Width: | Height: | Size: 133 B |
BIN
src/main/resources/assets/textures/title/progressia.png
Normal file
After Width: | Height: | Size: 12 KiB |
@ -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
|
@ -1,161 +1,164 @@
|
||||
;NSIS Modern User Interface
|
||||
;Welcome/Finish Page Example Script
|
||||
;Written by Joost Verburg
|
||||
|
||||
;--------------------------------
|
||||
;Include Modern UI
|
||||
|
||||
!include "MUI2.nsh"
|
||||
|
||||
;--------------------------------
|
||||
;General
|
||||
|
||||
!define PROJECT_NAME "Progressia"
|
||||
|
||||
; MUI Settings / Icons
|
||||
!define MUI_ICON "logo.ico"
|
||||
;!define MUI_UNICON ;Uninstall icon
|
||||
|
||||
; MUI Settings / Header
|
||||
; !define MUI_HEADERIMAGE
|
||||
; !define MUI_HEADERIMAGE_RIGHT
|
||||
; !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-r-nsis.bmp"
|
||||
; !define MUI_HEADERIMAGE_UNBITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-uninstall-r-nsis.bmp"
|
||||
|
||||
; MUI Settings / Wizard
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "left_side.bmp"
|
||||
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "left_side.bmp"
|
||||
|
||||
;Name and file
|
||||
Name "${PROJECT_NAME}"
|
||||
OutFile "${PROJECT_NAME}Installer.exe"
|
||||
Unicode True
|
||||
|
||||
;Default installation folder
|
||||
InstallDir "$PROGRAMFILES\${PROJECT_NAME}"
|
||||
|
||||
;Get installation folder from registry if available
|
||||
InstallDirRegKey HKLM "Software\${PROJECT_NAME}" ""
|
||||
|
||||
;Request application privileges for Windows Vista
|
||||
RequestExecutionLevel admin
|
||||
|
||||
;--------------------------------
|
||||
;Interface Settings
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
;--------------------------------
|
||||
;Pages
|
||||
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "LICENSE.txt"
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_TEXT "Start ${PROJECT_NAME}"
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_COMPONENTS
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
;--------------------------------
|
||||
;Languages
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
;--------------------------------
|
||||
;Installer Sections
|
||||
|
||||
Section "Install ${PROJECT_NAME}" SEC0000
|
||||
|
||||
SectionIn RO ;Make it read-only
|
||||
SetOutPath "$INSTDIR"
|
||||
SetOverwrite on
|
||||
|
||||
;Files
|
||||
File Progressia.jar
|
||||
File logo.ico
|
||||
File /r lib
|
||||
|
||||
;Store installation folder
|
||||
WriteRegStr HKLM SOFTWARE\Progressia "Install_Dir" "$INSTDIR"
|
||||
|
||||
;Create uninstaller
|
||||
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "DisplayName" "${PROJECT_NAME} (remove only)"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Create Desktop Shortcut" SEC0001
|
||||
SetOutPath "$APPDATA\${PROJECT_NAME}"
|
||||
CreateShortCut "$DESKTOP\${PROJECT_NAME}.lnk" "$INSTDIR\${PROJECT_NAME}.jar" "" "$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"
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Uninstaller Section
|
||||
|
||||
Section "Uninstall"
|
||||
|
||||
;ADD YOUR OWN FILES HERE...
|
||||
|
||||
Delete $INSTDIR\Uninstall.exe
|
||||
Delete $INSTDIR\Progressia.jar
|
||||
Delete $INSTDIR\lib\*.*
|
||||
Delete $INSTDIR\logo.ico
|
||||
|
||||
RMDir $INSTDIR\lib
|
||||
|
||||
Delete $DESKTOP\${PROJECT_NAME}.lnk
|
||||
|
||||
Delete $SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk
|
||||
Delete $SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk
|
||||
|
||||
RMDir $INSTDIR
|
||||
|
||||
RMDir /r $SMPROGRAMS\${PROJECT_NAME}
|
||||
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}"
|
||||
DeleteRegKey HKLM "Software\${PROJECT_NAME}"
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "un.Remove user data"
|
||||
|
||||
RMDir /r "$APPDATA\${PROJECT_NAME}"
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Functions
|
||||
|
||||
Function LaunchLink
|
||||
SetOutPath "$APPDATA\${PROJECT_NAME}"
|
||||
ExecShell "" "$INSTDIR\${PROJECT_NAME}.jar"
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Descriptions
|
||||
|
||||
;Language strings
|
||||
LangString DESC_SecDummy ${LANG_ENGLISH} "Install ${PROJECT_NAME}."
|
||||
|
||||
;Assign language strings to sections
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC0000} $(DESC_SecDummy)
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
||||
;NSIS Modern User Interface
|
||||
;Welcome/Finish Page Example Script
|
||||
;Written by Joost Verburg
|
||||
|
||||
;--------------------------------
|
||||
;Include Modern UI
|
||||
|
||||
!include "MUI2.nsh"
|
||||
|
||||
;--------------------------------
|
||||
;General
|
||||
|
||||
; Expecting the following symbols from caller:
|
||||
; PROJECT_NAME
|
||||
; PROJECT_VERSION
|
||||
; MAIN_JAR_FILE
|
||||
|
||||
; MUI Settings / Icons
|
||||
!define MUI_ICON "logo.ico"
|
||||
;!define MUI_UNICON ;Uninstall icon
|
||||
|
||||
; MUI Settings / Header
|
||||
; !define MUI_HEADERIMAGE
|
||||
; !define MUI_HEADERIMAGE_RIGHT
|
||||
; !define MUI_HEADERIMAGE_BITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-r-nsis.bmp"
|
||||
; !define MUI_HEADERIMAGE_UNBITMAP "${NSISDIR}\Contrib\Graphics\Header\orange-uninstall-r-nsis.bmp"
|
||||
|
||||
; MUI Settings / Wizard
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "left_side.bmp"
|
||||
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "left_side.bmp"
|
||||
|
||||
;Name and file
|
||||
Name "${PROJECT_NAME}"
|
||||
OutFile "${OUTPUT_DIR}/${PROJECT_NAME}-${PROJECT_VERSION}-installer.exe"
|
||||
Unicode True
|
||||
|
||||
;Default installation folder
|
||||
InstallDir "$PROGRAMFILES\${PROJECT_NAME}"
|
||||
|
||||
;Get installation folder from registry if available
|
||||
InstallDirRegKey HKLM "Software\${PROJECT_NAME}" ""
|
||||
|
||||
;Request application privileges for Windows Vista
|
||||
RequestExecutionLevel admin
|
||||
|
||||
;--------------------------------
|
||||
;Interface Settings
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
;--------------------------------
|
||||
;Pages
|
||||
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
!insertmacro MUI_PAGE_LICENSE "LICENSE.txt"
|
||||
!insertmacro MUI_PAGE_COMPONENTS
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
!define MUI_FINISHPAGE_RUN
|
||||
!define MUI_FINISHPAGE_RUN_TEXT "Start ${PROJECT_NAME}"
|
||||
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_WELCOME
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_COMPONENTS
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
;--------------------------------
|
||||
;Languages
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
;--------------------------------
|
||||
;Installer Sections
|
||||
|
||||
Section "Install ${PROJECT_NAME}" SEC0000
|
||||
|
||||
SectionIn RO ;Make it read-only
|
||||
SetOutPath "$INSTDIR"
|
||||
SetOverwrite on
|
||||
|
||||
;Files
|
||||
File "${MAIN_JAR_FILE}"
|
||||
File logo.ico
|
||||
File /r lib
|
||||
|
||||
;Store installation folder
|
||||
WriteRegStr HKLM "SOFTWARE\${PROJECT_NAME}" "Install_Dir" "$INSTDIR"
|
||||
|
||||
;Create uninstaller
|
||||
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "DisplayName" "${PROJECT_NAME} (remove only)"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "Create Desktop Shortcut" SEC0001
|
||||
SetOutPath "$APPDATA\${PROJECT_NAME}"
|
||||
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\${MAIN_JAR_FILE}" "" "$INSTDIR\logo.ico"
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Uninstaller Section
|
||||
|
||||
Section "Uninstall"
|
||||
|
||||
;ADD YOUR OWN FILES HERE...
|
||||
|
||||
Delete $INSTDIR\Uninstall.exe
|
||||
Delete "$INSTDIR\${MAIN_JAR_FILE}"
|
||||
Delete $INSTDIR\lib\*.*
|
||||
Delete $INSTDIR\logo.ico
|
||||
|
||||
RMDir $INSTDIR\lib
|
||||
|
||||
Delete $DESKTOP\${PROJECT_NAME}.lnk
|
||||
|
||||
Delete $SMPROGRAMS\${PROJECT_NAME}\Uninstall.lnk
|
||||
Delete $SMPROGRAMS\${PROJECT_NAME}\${PROJECT_NAME}.lnk
|
||||
|
||||
RMDir $INSTDIR
|
||||
|
||||
RMDir /r $SMPROGRAMS\${PROJECT_NAME}
|
||||
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PROJECT_NAME}"
|
||||
DeleteRegKey HKLM "Software\${PROJECT_NAME}"
|
||||
|
||||
SectionEnd
|
||||
|
||||
Section "un.Remove user data"
|
||||
|
||||
RMDir /r "$APPDATA\${PROJECT_NAME}"
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Functions
|
||||
|
||||
Function LaunchLink
|
||||
SetOutPath "$APPDATA\${PROJECT_NAME}"
|
||||
ExecShell "" "$INSTDIR\${MAIN_JAR_FILE}"
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Descriptions
|
||||
|
||||
;Language strings
|
||||
LangString DESC_SecDummy ${LANG_ENGLISH} "Install ${PROJECT_NAME}."
|
||||
|
||||
;Assign language strings to sections
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
|
||||
!insertmacro MUI_DESCRIPTION_TEXT ${SEC0000} $(DESC_SecDummy)
|
||||
!insertmacro MUI_FUNCTION_DESCRIPTION_END
|
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@"
|