Merge branch 'master' into moduleSystem

This commit is contained in:
Евгений Смирнов 2021-06-12 21:05:15 +03:00
commit 513feb1093
503 changed files with 37550 additions and 28566 deletions

3
.gitattributes vendored
View File

@ -2,5 +2,8 @@
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
* text=auto eol=lf
*.bat text eol=crlf

17
.gitignore vendored
View File

@ -16,7 +16,12 @@ bin
# Ignore MacOS
**/.DS_Store
.idea/
run/
# Ignore the dedicated working directory
run/*
# ... Except the dummy file inside to make sure that the directory exists
!run/.dummy
# Ignore package building artifacts
build_packages/*
@ -25,12 +30,10 @@ build_packages/*
!build_packages/NSIS
build_packages/NSIS/*
!build_packages/NSIS/ProgressiaInstaller.nsi
!build_packages/NSIS/logo.ico
!build_packages/NSIS/left_side.bmp
# ... and except build_packages/DEB/progressia-*/DEBIAN/control
# ... and except build_packages/DEB/template
!build_packages/DEB
build_packages/DEB/*
!build_packages/DEB/progressia-*
build_packages/DEB/progressia-*/*
!build_packages/DEB/progressia-*/DEBIAN
build_packages/DEB/progressia-*/DEBIAN/*
!build_packages/DEB/progressia-*/DEBIAN/control
!build_packages/DEB/template

View File

@ -1,46 +1,58 @@
# Progressia
A free, open source sandbox survival game currently in early development.
A free, open-source sandbox survival game currently in early development.
## Description
The game has barely begun development so much of its features are yet to be implemented.
In broader terms, Progressia is a challenging game about survival, exploration and
engineering in a realistic voxel sandbox environment. The game is heavily inspired by
Minecraft technology mods, Factorio, Vintage Story and Minetest. Progressia's main unique
features will include highly composite items and blocks, a realistically-scaled world,
temperature mechanics and a parallelism-capable server.
## System requirements
- GNU/Linux (x64, arm32 or arm64), Windows XP or later (x64 or x86) or MacOS (x64)
- Java 8 or later
- OpenGL 2.1 or later
- Probably about 0.5 GiB RAM
- Less than 1 GiB of storage space
See [Build Guide](docs/building/BuildGuide.md) for compilation requirements.
## Contributing
For now, contact @Javapony in Telegram for details. Contributing is completely allowed, but we don't have any set guidelines yet.
All contributors welcome. Please contact Javapony in [Telegram](https://t.me/javapony)
or join our [Discord server](https://discord.gg/M4ukyPYgGP) for details or help.
## Building
On GNU/Linux and MacOS:
1. `$ git clone https://github.com/OLEGSHA/Progressia.git`
2. `$ gradlew build`
2. `$ chmod +x gradlew`
3. `$ ./gradlew buildLocal`
### Additional setup for Eclipse IDE
On Windows:
If you have Buildship plugin installed, use File - Import - Gradle - Existing Gradle Project. Main class is `ru.windcorp.progressia.client.ProgressiaClientMain`.
1. `git clone https://github.com/OLEGSHA/Progressia.git`
2. `gradlew.bat buildLocal`
Alternatively do the following:
Alternatively use Linux/MacOS steps in a Bash shell.
1. Add `id 'eclipse'` into `build.gradle` inside `plugins { ... }`:
```
plugins {
// Apply the java-library plugin to add support for Java Library
id 'java-library'
id 'eclipse'
}
```
2. `$ gradlew eclipse`
3. Import the project with File - Import - Existing Projects into Workspace
4. On Windows, make sure the project has UTF-8 encoding with <RMB on project in project tree> - Properties - Resource - Text file encoding - Other - UTF-8
### Additional setup for IntelliJ IDEA
1. Open the project with File - Open Project
2. Press button 'Add configuration...' and open 'Application' in templates list
3. Add `ru.windcorp.progressia.client.ProgressiaClientMain` in 'Main class' text field
4. Choose `Progressia.main` in 'Use classpath of module' drop-down list
5. Click 'Create configuration' and press 'Apply'
For a more in-depth explanation, solutions for common problems and tips for IDE configuration
please see the [Build Guide](docs/building/BuildGuide.md).
## Libraries
* LWJGL - OpenGL, OpenAL, GLFW and several more libraries ported to Java
* Google Guava
* Trove4j
* java-graphics/glm - GLM ported to Java. _Maven Central contains an outdated version, a custom repository used instead_
* OpenSimplex2
* log4j
- [LWJGL](https://www.lwjgl.org/) ([GitHub](https://github.com/LWJGL/lwjgl3)) OpenGL, OpenAL, GLFW and STB libraries ported to Java
- [OpenGL](https://en.wikipedia.org/wiki/OpenGL) a low-level graphics interface
- [OpenAL](https://en.wikipedia.org/wiki/OpenAL) a low-level audio interface
- [GLFW](https://www.glfw.org/) ([GitHub](https://github.com/glfw/glfw)) a minimalistic OpenGL-capable windowing library
- [STB (GitHub)](https://github.com/nothings/stb) a collection of various algorithms. `stb_vorbis` is used
- [Guava (GitHub)](https://github.com/google/guava) a generic utilities library
- [Trove4j (BitBucket)](https://bitbucket.org/trove4j/trove) optimized primitive collections
- [java-graphics/glm (GitHub)](https://github.com/java-graphics/glm) GLM ported to Java. _Maven Central contains an outdated version, a custom repository used instead_
- [OpenSimplex2 (GitHub)](https://github.com/KdotJPG/OpenSimplex2) a minimalistic highly optimized noise generator
- [Log4j](https://logging.apache.org/log4j/2.x/) [(GitHub)](https://github.com/apache/logging-log4j2) a logging library

View File

@ -1,24 +1,47 @@
#!/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'
# Version that the package will receive
version='0.1_all'
directory="build_packages/DEB/progressia-$version"
# .deb control file that must be present
configurationFile="$directory/DEBIAN/control"
outputFile="build_packages/DEB/progressia-$version.deb"
# 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"
@ -27,43 +50,46 @@ buildDebianPackage() {
exit 100
fi
done
if ! [ -r "$configurationFile" ]; then
echoerr "$configurationFile is missing or not readable, cannot package"
exit 101
else
echo "- $configurationFile is present and readable"
fi
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
{
user=`whoami`
homeDir="$directory/home/$user/Progressia/"
mkdir -p "$homeDir" &&
cp -r 'build/libs/lib' "$homeDir/lib" &&
cp 'build/libs/Progressia.jar' "$homeDir/Progressia.jar" &&
echo "------ DPKG-DEB ------" &&
fakeroot dpkg-deb --build "$directory" &&
echo "---- DPKG-DEB END ----" &&
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 "$homeDir" ]; then
rm -r "$homeDir"
if [ -d "$tmpDir" ]; then
rm -r "$tmpDir"
fi
echo "Cleaned up"
} || {
echoerr "Could not clean up after packaging Debian package"
exitCode=2
}
exit "$exitCode"
}
@ -71,15 +97,15 @@ 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"
@ -88,20 +114,21 @@ buildWindowsInstaller() {
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 ----" &&
@ -110,7 +137,7 @@ buildWindowsInstaller() {
echoerr "Could not build Windows installer"
exitCode=1
}
{
if [ -d 'build_packages/NSIS/lib' ]; then
rm -r 'build_packages/NSIS/lib'
@ -118,12 +145,15 @@ buildWindowsInstaller() {
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"
}

View File

@ -1,9 +0,0 @@
Package: Progressia
Version: 0.1
Section: custom
Priority: optional
Architecture: all
Essential: no
Maintainer: Test
Depends: default-jdk
Description: Test package

View File

@ -0,0 +1,8 @@
Package: progressia-techdemo
Version: 1.0
Section: custom
Priority: optional
Architecture: all
Maintainer: Javapony <kvadropups@gmail.com>
Depends: java8-runtime
Description: Progressia Techdemo release

View File

@ -10,16 +10,32 @@
;--------------------------------
;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 "Progressia"
OutFile "ProgressiaInstaller.exe"
Name "${PROJECT_NAME}"
OutFile "${PROJECT_NAME}Installer.exe"
Unicode True
;Default installation folder
InstallDir "$PROGRAMFILES\Progressia"
InstallDir "$PROGRAMFILES\${PROJECT_NAME}"
;Get installation folder from registry if available
InstallDirRegKey HKLM "Software\Progressia" "Install_Dir"
InstallDirRegKey HKLM "Software\${PROJECT_NAME}" ""
;Request application privileges for Windows Vista
RequestExecutionLevel admin
@ -33,14 +49,18 @@
;Pages
!insertmacro MUI_PAGE_WELCOME
;!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt"
!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
@ -52,35 +72,40 @@
;--------------------------------
;Installer Sections
Section "Install Progressia" SecDummy
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\Progressia" "DisplayName" "Progressia (remove only)"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Progressia" "UninstallString" "$INSTDIR\Uninstall.exe"
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
;--------------------------------
;Descriptions
Section "Create Desktop Shortcut" SEC0001
SetOutPath "$APPDATA\${PROJECT_NAME}"
CreateShortCut "$DESKTOP\${PROJECT_NAME}.lnk" "$INSTDIR\${PROJECT_NAME}.jar" "" "$INSTDIR\logo.ico"
SectionEnd
;Language strings
LangString DESC_SecDummy ${LANG_ENGLISH} "A test section."
Section "Start Menu Shortcuts" SEC0002
;Assign language strings to sections
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SecDummy} $(DESC_SecDummy)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
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
@ -92,9 +117,45 @@ Section "Uninstall"
Delete $INSTDIR\Uninstall.exe
Delete $INSTDIR\Progressia.jar
Delete $INSTDIR\lib\*.*
Delete $INSTDIR\logo.ico
RMDir /r "$INSTDIR"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Progressia"
DeleteRegKey HKLM "Software\Progressia"
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

69
docs/CONTRIBUTING.md Normal file
View File

@ -0,0 +1,69 @@
# Contributing Guidelines
This document lists conventions adopted by Progressia developers.
## git
### Branches
Progressia repository contains a `master` branch and several "feature" branches.
`master` is expected to contain a version of the game suitable for demonstration and forking/branching. Do not commit directly to `master` without OLEGSHA's approval.
- `master` must always correctly build without compiler warnings (see below).
- `master` must always pass all unit tests.
- `master` must always be able to launch successfully.
- `master` must always only contain working features.
- `master` should not contain excessive debug code.
- `master` must always have its code and filenames formatted (see below).
"Feature" branches are branches dedicated to the development of a single feature. When the feature reaches completion the branch is merged into `master` and removed. Intermediate merges into `master` may occur when some fitting milestone is reached. Intermediate merges from `master` may be done as necessary. Merges between "feature" branches should generally be avoided.
When beginning work on a new feature, create a new branch based on `master` (or on another "feature" branch if absolutely necessary). Use `all-small-with-dashes` to name the branch: `add-trees` or `rebalance-plastics` are good names. Do not fix unrelated bugs or work on unrelated features in a "feature" branch - create a new one, switch to an existing one or commit directly to `master` if the changes are small enough.
"Feature" branches may not be formatted properly. Formatting is required before merging into `master` or other branches.
### Commits
- Commits must leave the branch in a state that builds without compiler warnings (see below).
- Changes should be grouped in commits semantically. Avoid committing many small related changes in sequence; if necessary, wait and accumulate them. Avoid committing unrelated changes together; if necessary, split staged changes into several commits. This should normally result in about 1-2 commits for a day's work.
- Commit bulk changes (renaming, formatting, ...) separately. Don't ever commit whitespace changes outside formatting commits.
- Message format:
```
Short description of changes
<empty line>
- Enumeration of changes
- Nest when appropriate
- Use dashes only
- List not needed for small commits
```
Example:
```
Changed packages for relations, renamed Face to ShapePart
- Added BlockRelation as an abstract superclass to existing relations
- Must be given an absolute "up" direction before use
- Moved AbsFace, AbsRelation and BlockRelation to .world.rels
- Renamed Face to ShapePart to reduce confusion with AbsFace
```
- Only commit changes described in the commit message. Please double-check staged files before committing.
- Avoid merge conflicts. Pull before committing.
- Better sign commits than not. See: [git](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work), [GitHub](https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification).
## Code
### Warnings
Make sure that all committed code contains no compiler warnings. This specifically includes unused imports, unused private members, missing `@Override`s and warnings related to generics.
Warnings about unknown tokens in `@SuppressWarnings` are temporarily ignored. Please disable them in your IDE.
### Code Style
Formatting code is important.
- The format is specified within the files inside `/templates_and_presets/eclipse_ide`. Import the specifications into Eclipse or IntelliJ IDEA and use the IDEs' format feature. Alternatively format the code manually in accordance with existing files.
- Only use tabs for indentation. Never indent with spaces even when wrapping lines. This is to ensure that indentation does not break when tab width is different.
- Don't use `I` prefix for interfaces (not `IDoable` but `Doable`).
- Prioritize readability over compactness. Do not hesitate to use (very) long identifiers if they aid comprehension.
- Document all mathematics unless it is trivial, especially when using math notation for variable names.
- Use proper English when writing comments. Avoid boxes in comments. Use `//` for single-line comments.

203
docs/building/BuildGuide.md Normal file
View File

@ -0,0 +1,203 @@
# Build Guide
This document is a guide to building Progressia from source.
Compilation should be possible on all platforms that support JDK 8 or later, however, packaging scripts require Bash.
This guide assumes you are familiar with using a terminal or Windows Command Prompt or PowerShell.
See [Eclipse Guide](EclipseGuide.md) and [IntelliJ IDEA Guide](IntelliJIDEAGuide.md) for IDE-specific configuration.
## Basic compilation
### Installing prerequisites
Compiling Progressia requires that a JDK (Java Development Kit) 8 or later is available in your system path. Please
note that JDK is not the same as a JRE (Java Runtime Environment), the software required to execute Java programs;
you may be able to run Progressia but not compile it.
To check whether you have the correct JDK installed please run
`javac -version`.
If this command fails or outputs version 1.7 or lower, then you need to (re-)install JDK. (javac is the Java
Compiler.)
Progressia developers recommend [OpenJDK](https://openjdk.java.net/) as the free, open-source Java implementation.
Confusion may arise from the project's name: OpenJDK issues both JRE and JDK; an OpenJDK JRE is not enough to compile
Progressia. Another popular choice is [Oracle Java](https://www.oracle.com/java/technologies/), which is proprietary
and thus not recommended.
To install OpenJDK JDK on GNU/Linux, install the appropriately named package with your package manager (on Debian,
Ubuntu and other dpkg-based distributions, run
`apt-get install default-jdk`
with root privileges).
To install OpenJDK JDK on MacOS or Windows, Progressia developers recommend [AdoptOpenJDK](https://adoptopenjdk.net/),
which creates and distributes OpenJDK installers and packages. Please confirm that JDK installed correctly using
the aforementioned test.
### Getting the source code
Progressia source code is managed with [git](https://git-scm.com/), a popular open-source tool. It is a program that
automatically keeps track of changes in a set of source code and allows synchronization of those changes between
different computers. A copy of the source code is called a repository. This guide will assume that
[Progressia's GitHub repository](https://github.com/OLEGSHA/Progressia/) is accessible; if it is not, please look up
the relevant instructions.
If git is installed on your system, perform a clone of
`https://github.com/OLEGSHA/Progressia.git`.
The details may vary depending on your git frontend; if you are not using a frontend, issue the following command:
```
git clone https://github.com/OLEGSHA/Progressia.git
```
Run the command in your directory of choice, git will create a subfolder. After the action completes you should
have a local copy of the source code.
If you do not have git installed, use GitHub's 'Download ZIP' option (available through the green 'Code' button at
the time of writing this). Unpack the downloaded archive into any directory.
### Compiling
Compilation and related tasks are managed by [Gradle](https://gradle.org/), another popular open-source tool. The repository
contains a Gradle Wrapper which automatically detects and installs the appropriate Gradle version. Gradle is most
conveniently controlled with one of two scripts, `gradlew` or `gradlew.bat` for Bash and Windows Command Prompt respectively,
which are distributed within the repository as well. Gradle itself uses another file, `build.gradle`, that contains the
relevant instructions in Groovy.
On GNU/Linux and MacOS, the script may need to receive the execution permission before being run:
```
chmod +x gradlew
```
A most basic compilation is achieved with:
```
./gradlew buildLocal
```
This instructs Gradle to compile, check and test a JAR archive with the game, as well as to download all necessary
dependencies. The resulting JAR file will only reference libraries required to run the game on your current platform.
The compiled JAR and all necessary libraries can be found in `build/libs/`. The `lib` directory next to `Progressia.jar`
contains all runtime dependencies; the game may be run with a simple
`java -jar Progressia.jar`
if `lib` is located in the same directory as the JAR file. (On many systems double-clicking `Progressia.jar` has the
same effect.) Otherwise, if there is no `lib` directory next to the JAR, classpath must be set manually with command
line options for `java`.
A more conventional command, `./gradlew build`, may be used to the same effect; however, Progressia developers recommend
against using it as their effects might start to differ with future updates.
## Building for other platforms
### Native libraries and why platforms matter
Although Java is well-known for its portability, Progressia has a limited set of architectures that it supports.
This is a consequence of the fact that Progressia uses [OpenGL](https://en.wikipedia.org/wiki/OpenGL),
[OpenAL](https://en.wikipedia.org/wiki/OpenAL), [GLFW](https://www.glfw.org) and [STB](https://github.com/nothings/stb),
four libraries originally implemented in the C language. In order to access them, a Java wrapper library,
[LWJGL](https://www.lwjgl.org/), is used. Unfortunately such wrappers need to be hand-written for each platform
and require complicated compilation.
In practice this means that along with the pure Java libraries, such as Guava or GLM, Progressia carries several
LWJGL libraries that each consist of a Java interface and a compiled binary implementation (called a native library).
A separate version of a single native library is required to run Progressia on different platforms; if a game only
contains natives for Windows, it cannot be run on GNU/Linux.
### How Gradle is set up
Gradle builds Progressia by first choosing which platform or platforms should be supported. It then downloads,
if necessary, and processes only dependencies that are relevant to the current configuration. When creating the JAR
file, Gradle appends only selected libraries to the JAR's manifest file. It finally copies only the libraries included
in the manifest to the `build/libs/lib` directory.
Why not package all natives all the time? This is inefficient when producing temporary builds for development purposes
because unnecessary dependencies need to be downloaded and processed. This mechanism is also used to trim down the
size of various system-specific installers and packages since, for example, a Windows Installer is not expected to
produce a installation that runs on anything other than Windows, so GNU/Linux and MacOS natives need not be packaged
with it.
Unless instructed otherwise, Gradle only chooses the local platform. Thus the procedure described in 'Basic Compilation'
produces an output that only contains the natives for the platform that performed the compilation. It is unsuitable for
publication and may be generally inconvenient.
### Building cross-platform
Fortunately it is possible to produce a maximally cross-platform version by running Gradle with a different task:
```
./gradlew buildCrossPlatform
```
This command performs the same actions as the `buildLocal` command, except that all possible native libraries are
included in the JAR manifest and copied into `build/libs/lib`. The result may be run on any supported platform.
However, because of the large amount of libraries, it has significantly greater size than a platform-specific
build.
### Building for a specific platform
Some users might find the need to build for a specific set of platforms. Inclusion of GNU/Linux, Windows or MacOS
dependencies individually can be controlled with the following arguments to the `./gradlew build` command:
- `requestLinuxDependencies` requests that `natives-linux`, `natives-linux-arm32` and `natives-linux-arm64` binaries are included;
- `requestWindowsDependencies` requests that `natives-windows` and `natives-windows-x86` binaries are included;
- `requestMacOSDependencies` requests that `natives-macos` binaries are included.
These requests can be applied in any combination. For example, the following command produces a build containing only
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`.
### Creating a Debian package
A Debian package can be created with the following Gradle task:
```
./gradlew packageDebian
```
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.
### Creating a Windows installer
A Windows installer can be created with the following Gradle task:
```
./gradlew packageWindows
```
Gradle will then build all artifacts necessary to run the game on Windows (both x64 and x86 architectures) and invoke
`./buildPackages.sh windows`.
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.

View File

@ -0,0 +1,125 @@
# Eclipse Guide
This document is a guide to configuring Eclipse IDE for developing Progressia.
## Setup
### Downloading project
Although the project may be downloaded manually or using git directly (as described in the
[Build Guide](BuildGuide.md)), it may be more convenient to use Eclipse's EGit. If you
choose not to, skip the following subsection.
#### Using EGit
[EGit](https://www.eclipse.org/egit/) is a git interface for Eclipse. It is currently shipped
with Eclipse IDE.
1. Open Git perspective. (Git perspective is not visible by default. To open it, use
'Window' menu > 'Perspective' > 'Open Perspective' > 'Other' > select Git.)
2. In 'Git Repositories' view, click 'Clone a Git Repository and add the clone to this view'
button.
3. Paste
`https://github.com/OLEGSHA/Progressia.git`
or the appropriate git URI into the 'URI' field and click 'Next'.
4. Review the branches and click 'Next'.
5. Edit the local repository path if necessary and click 'Finish'.
Note: avoid importing the project from the Git Clone Wizard as doing so will fail to specify
Gradle dependencies.
### Importing project
Gradle dependencies need to be imported into the IDE for proper code analysis and launching.
#### Using Buildship plugin for Eclipse
[Buildship](https://projects.eclipse.org/projects/tools.buildship) is an Eclipse plugin
that integrates Gradle into the IDE. This is the recommended method.
1. In 'File' menu, select 'Import...'.
2. In the Import Wizard, select 'Gradle' > 'Existing Gradle Project'. Click 'Next'.
3. In the Gradle Import Wizard, click 'Next' to arrive at directory selection.
4. Select the directory that contains `build.gradle` file in 'Project root directory' field.
5. Click 'Finish' and allow the plugin to import the project.
When using this method, any changes to the `build.gradle` file must be followed by a Gradle
refresh ((Project context menu) > 'Gradle' > 'Refresh Gradle Project').
#### Using Eclipse plugin for Gradle
Gradle features a plugin for Eclipse that can generate project specifications for the IDE.
It is deactivated by default.
1. Enable the Eclipse plugin by uncommenting the `id 'eclipse'` line in `build.gradle`
(note the disappearance of `//`). Please make sure not to accidentally commit this change in git!
```
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'
}
```
2. Run
`./gradlew eclipse`
in the directory that contains `build.gradle`. This command will
generate Eclipse project files.
3. In 'File' menu in the Eclipse IDE, select 'Import...'.
4. In the Import Wizard, select 'General' > 'Existing Projects into Workspace'. Click 'Next'.
5. Select the directory that contains `build.gradle` file in 'Select root directory' field.
6. Click 'Finish' and allow the IDE to import the project.
When using this method, any changes to the `build.gradle` file must be followed by
`./gradlew eclipse` command and a project refresh ((Project context menu) > 'Refresh').
### Creating a Run Configuration
Run configurations are used by Eclipse IDE to specify how a project must be run.
1. In 'Run' menu, select 'Run Configurations...'.
2. In the Run Configurations, select 'Java Application', then click 'New launch configuration'.
3. Specify the project and the name of the new configuration.
4. Put
`ru.windcorp.progressia.client.ProgressiaClientMain`
into 'Main Class' field.
5. In the 'Arguments' tab, put
`${workspace_loc:Progressia}/run`
into 'Working directory:' > 'Other' field. Replace `Progressia` with your name of the project.
Alternatively, specify another location outside of the project's root directory.
6. Click 'Apply' to save changes. Exit Run Configurations.
Step 5 is required to specify that the game must run in some directory other than the project root,
which is the default in Eclipse.
### Applying formatting templates
Windcorp's Progressia repository is formatted with a style defined for Eclipse IDE in
`templates_and_presets/eclipse_ide`.
Please apply these templates to the project to automatically format the source in a similar fashion.
1. In project context menu, click 'Properties'.
2. In 'Java Code Style' > 'Code Templates', check 'Enable project specific settings', then click 'Import' and select
`templates_and_presets/eclipse_ide/CodeTemplates.xml`.
3. In 'Java Code Style' > 'Formatter', check 'Enable project specific settings', then click 'Import' and select
`templates_and_presets/eclipse_ide/FormatterProfile.xml`.
## Common problems
### Buildship plugin fails with a cryptic message
This may be caused by a lack of Java in your system path. Eclipse stores the path to the JVM it
uses in its settings and is thus not affected by the changes to the system path. However, Gradle
searches for Java installations in system path regardless and may fail independently of Eclipse.
__Solution:__ the simplest solution is to reinstall JDK making sure that system path is affected.
See [Build Guide](BuildGuide.md) for details. Another course of action is to manually append the
Java installation directory (specifically its `bin` folder) to the system `PATH` variable.

View File

@ -0,0 +1,44 @@
# Intellij IDEA Guide
This document is a guide to configuring Intellij IDEA for developing Progressia.
## Setup
### Downloading project
Although the project may be downloaded manually or using git directly (as described in the
[Build Guide](BuildGuide.md)), it may be more convenient to use pre-installed Intellij IDEA Git extension. If you choose not to, skip the following subsection.
#### Using Git Extension
[Git extension](https://plugins.jetbrains.com/plugin/13173-git) is a git interface for Intellij IDEA. It is currently shipped with Intellij IDEA.
1. Open Intellij IDEA welcome screen, click the 'Get from VCS' button. Alternatively, use 'File' menu > 'New' > 'Project From Version Control...'.
2. Insert `https://github.com/OLEGSHA/Progressia.git` in the 'URL' field.
3. Change the local repository path, if necessary, and click 'Clone'.
### Creating a Run Configuration
Run configurations are used by Intellij IDEA to specify how a project must be run.
#### Using GUI shortcut
1. In Project Explorer, open `ru.windcorp.progressia.client.ProgressiaClientMain`.
2. Press small green triangle button in code editor window.
3. In the drop-down menu, click 'Modify Run Configuration...'.
4. Append `\run` to the 'Working directory' field. Alternatively, specify another location outside of the project's root directory.
5. Click 'Apply' to save changes.
#### Using 'Add Configuration' menu
1. Click 'Add Configuration...'.
2. In 'Run/Debug Configurations', click 'Add new configuration' with the plus icon.
3. In the drop-down list, select 'Application'.
4. Enter the configuration name .
5. Select a JRE from the drop-down list.
6. Select the module whose classpath should be used to run the application: `Progressia.main`.
7. Enter `ru.windcorp.progressia.client.ProgressiaClientMain` in the 'Main Class' field.
8. Append `\run` to the 'Working directory' field. Alternatively, specify another location outside of the project's root directory.
9. Click 'Apply' to save changes.
Step 8 is required to specify that the game must run in some directory other than the project root, which is the default in Intellij IDEA.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

1
run/.dummy Normal file
View File

@ -0,0 +1 @@
This is a dummy file to make sure run/ directory is stored and created by git.

View File

@ -3,9 +3,11 @@ package kdotjpg.opensimplex2.areagen;
* This file has been modified in the following ways:
* - added a package declaration at line 1;
* - added missing @Override annotations;
* - commented out line 965 due to unused variables.
* - commented out line 967 due to unused variables.
* The original version of this file can be found at
* https://raw.githubusercontent.com/KdotJPG/OpenSimplex2/master/java/areagen/OpenSimplex2S.java
*
* @formatter:off
*/
/**
@ -983,16 +985,3 @@ public class OpenSimplex2S {
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,21 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* 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/>.
*******************************************************************************/
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil;
import java.io.OutputStream;
@ -22,53 +23,53 @@ import java.io.PrintWriter;
import java.io.Writer;
public class CSVWriter {
private String columnSeparator = ";";
private String rowSeparator = "\n";
private boolean shouldAddSeparator = false;
private final PrintWriter parent;
public CSVWriter(PrintWriter output) {
this.parent = output;
}
public CSVWriter(Writer output) {
this(new PrintWriter(output));
}
public CSVWriter(OutputStream output) {
this(new PrintWriter(output));
}
public PrintWriter getParent() {
return parent;
}
public String getColumnSeparator() {
return columnSeparator;
}
public CSVWriter setColumnSeparator(String columnSeparator) {
this.columnSeparator = columnSeparator;
return this;
}
public String getRowSeparator() {
return rowSeparator;
}
public CSVWriter setRowSeparator(String rowSeparator) {
this.rowSeparator = rowSeparator;
return this;
}
public void print(Object object) {
skip();
getParent().print(String.valueOf(object));
}
public void skip() {
if (shouldAddSeparator) {
getParent().print(getColumnSeparator());
@ -76,27 +77,27 @@ public class CSVWriter {
shouldAddSeparator = true;
}
}
public void skip(int amount) {
for (int i = 0; i < amount; ++i) {
skip();
}
}
public void endRow() {
getParent().print(getRowSeparator());
shouldAddSeparator = false;
}
public void endRow(Object object) {
print(object);
endRow();
}
public void flush() {
getParent().flush();
}
public void close() {
getParent().close();
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
/*
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -14,47 +14,57 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
*/
package ru.windcorp.jputil;
import java.util.HashMap;
import java.util.Map;
public class PrimitiveUtil {
private PrimitiveUtil() {}
private PrimitiveUtil() {
}
private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_BOXED = new HashMap<>();
private static final Map<Class<?>, Object> PRIMITIVE_TO_NULL = new HashMap<>();
static {
for (Class<?> boxed : new Class<?>[] {
Boolean.class, Byte.class, Short.class, Character.class,
Integer.class, Long.class, Float.class, Double.class
}) {
for (
Class<?> boxed : new Class<?>[] {
Boolean.class,
Byte.class,
Short.class,
Character.class,
Integer.class,
Long.class,
Float.class,
Double.class
}
) {
try {
PRIMITIVE_TO_BOXED.put((Class<?>) boxed.getField("TYPE").get(null), boxed);
} catch (Exception e) {
e.printStackTrace();
}
}
PRIMITIVE_TO_NULL.put(Boolean.TYPE, Boolean.FALSE);
PRIMITIVE_TO_NULL.put(Byte.TYPE, Byte.valueOf((byte) 0));
PRIMITIVE_TO_NULL.put(Short.TYPE, Short.valueOf((short) 0));
PRIMITIVE_TO_NULL.put(Integer.TYPE, Integer.valueOf(0));
PRIMITIVE_TO_NULL.put(Long.TYPE, Long.valueOf(0));
PRIMITIVE_TO_NULL.put(Float.TYPE, Float.valueOf(Float.NaN));
PRIMITIVE_TO_NULL.put(Double.TYPE, Double.valueOf(Double.NaN));
PRIMITIVE_TO_NULL.put(Character.TYPE, Character.valueOf('\u0000'));
PRIMITIVE_TO_NULL.put(Boolean.TYPE, Boolean.FALSE);
PRIMITIVE_TO_NULL.put(Byte.TYPE, Byte.valueOf((byte) 0));
PRIMITIVE_TO_NULL.put(Short.TYPE, Short.valueOf((short) 0));
PRIMITIVE_TO_NULL.put(Integer.TYPE, Integer.valueOf(0));
PRIMITIVE_TO_NULL.put(Long.TYPE, Long.valueOf(0));
PRIMITIVE_TO_NULL.put(Float.TYPE, Float.valueOf(Float.NaN));
PRIMITIVE_TO_NULL.put(Double.TYPE, Double.valueOf(Double.NaN));
PRIMITIVE_TO_NULL.put(Character.TYPE, Character.valueOf('\u0000'));
}
public static Class<?> getBoxedClass(Class<?> primitiveClass) {
return PRIMITIVE_TO_BOXED.getOrDefault(primitiveClass, primitiveClass);
}
public static Object getPrimitiveNull(Class<?> primitiveClass) {
return PRIMITIVE_TO_NULL.get(primitiveClass);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +1,45 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil;
public class SyntaxException extends Exception {
private static final long serialVersionUID = -4052144233640072750L;
public SyntaxException() {
}
public SyntaxException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public SyntaxException(String message, Throwable cause) {
super(message, cause);
}
public SyntaxException(String message) {
super(message);
}
public SyntaxException(Throwable cause) {
super(cause);
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil;
public class SyntaxException extends Exception {
private static final long serialVersionUID = -4052144233640072750L;
public SyntaxException() {
}
public SyntaxException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public SyntaxException(String message, Throwable cause) {
super(message, cause);
}
public SyntaxException(String message) {
super(message);
}
public SyntaxException(Throwable cause) {
super(cause);
}
}

View File

@ -1,128 +1,132 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.text.CharacterIterator;
public class CharArrayIterator implements CharacterIterator {
private final char[] array;
private int pos;
public CharArrayIterator(char[] array) {
this.array = array;
}
public CharArrayIterator(String src) {
this(src.toCharArray());
}
@Override
public char first() {
pos = 0;
if (array.length != 0) {
return array[pos];
}
return DONE;
}
@Override
public char last() {
pos = array.length;
if (array.length != 0) {
pos -= 1;
return array[pos];
}
return DONE;
}
@Override
public char current() {
if (array.length != 0 && pos < array.length) {
return array[pos];
}
return DONE;
}
@Override
public char next() {
pos += 1;
if (pos >= array.length) {
pos = array.length;
return DONE;
}
return current();
}
@Override
public char previous() {
if (pos == 0) {
return DONE;
}
pos -= 1;
return current();
}
@Override
public char setIndex(int position) {
if (position < 0 || position > array.length) {
throw new IllegalArgumentException("bad position: " + position);
}
pos = position;
if (pos != array.length && array.length != 0) {
return array[pos];
}
return DONE;
}
@Override
public int getBeginIndex() {
return 0;
}
@Override
public int getEndIndex() {
return array.length;
}
@Override
public int getIndex() {
return pos;
}
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// SonarLint: "clone" should not be overridden (java:S2975)
// And I wouldn't have done that if only CharacterIterator had not required exception safety.
// SonarLint: "toString()" and "clone()" methods should not return null (java:S2225)
// The clause is unreachable: CharacterArrayIterator implements Cloneable and superclass is Object.
@SuppressWarnings({"squid:S2975", "squid:S2225"})
@Override
public CharArrayIterator clone() {
try {
return (CharArrayIterator) super.clone();
} catch (CloneNotSupportedException cnse) {
// Impossible
return null;
}
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
import java.text.CharacterIterator;
public class CharArrayIterator implements CharacterIterator {
private final char[] array;
private int pos;
public CharArrayIterator(char[] array) {
this.array = array;
}
public CharArrayIterator(String src) {
this(src.toCharArray());
}
@Override
public char first() {
pos = 0;
if (array.length != 0) {
return array[pos];
}
return DONE;
}
@Override
public char last() {
pos = array.length;
if (array.length != 0) {
pos -= 1;
return array[pos];
}
return DONE;
}
@Override
public char current() {
if (array.length != 0 && pos < array.length) {
return array[pos];
}
return DONE;
}
@Override
public char next() {
pos += 1;
if (pos >= array.length) {
pos = array.length;
return DONE;
}
return current();
}
@Override
public char previous() {
if (pos == 0) {
return DONE;
}
pos -= 1;
return current();
}
@Override
public char setIndex(int position) {
if (position < 0 || position > array.length) {
throw new IllegalArgumentException("bad position: " + position);
}
pos = position;
if (pos != array.length && array.length != 0) {
return array[pos];
}
return DONE;
}
@Override
public int getBeginIndex() {
return 0;
}
@Override
public int getEndIndex() {
return array.length;
}
@Override
public int getIndex() {
return pos;
}
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// SonarLint: "clone" should not be overridden (java:S2975)
// And I wouldn't have done that if only CharacterIterator had not required
// exception safety.
// SonarLint: "toString()" and "clone()" methods should not return null
// (java:S2225)
// The clause is unreachable: CharacterArrayIterator implements Cloneable
// and superclass is Object.
@SuppressWarnings({ "squid:S2975", "squid:S2225" })
@Override
public CharArrayIterator clone() {
try {
return (CharArrayIterator) super.clone();
} catch (CloneNotSupportedException cnse) {
// Impossible
return null;
}
}
}

View File

@ -1,42 +1,43 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.util.function.IntConsumer;
@FunctionalInterface
public interface CharConsumer {
void accept(char c);
public static CharConsumer andThen(CharConsumer first, CharConsumer second) {
return c -> {
first.accept(c);
second.accept(c);
};
}
public static IntConsumer toInt(CharConsumer consumer) {
return i -> consumer.accept((char) i);
}
public static CharConsumer toChar(IntConsumer consumer) {
return consumer::accept;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
import java.util.function.IntConsumer;
@FunctionalInterface
public interface CharConsumer {
void accept(char c);
public static CharConsumer andThen(CharConsumer first, CharConsumer second) {
return c -> {
first.accept(c);
second.accept(c);
};
}
public static IntConsumer toInt(CharConsumer consumer) {
return i -> consumer.accept((char) i);
}
public static CharConsumer toChar(IntConsumer consumer) {
return consumer::accept;
}
}

View File

@ -1,69 +1,70 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.util.Objects;
import ru.windcorp.jputil.ArrayUtil;
/**
* @author Javapony
*
*/
public class CharConsumers {
private CharConsumers() {}
public static CharConsumer fillArray(char[] array, int offset, int length) {
return new ArrayFiller(array, offset, length);
}
public static CharConsumer fillArray(char[] array) {
return fillArray(array, 0, -1);
}
private static class ArrayFiller implements CharConsumer {
final char[] array;
int i;
final int end;
/**
* @param array
* @param offset
* @param length
*/
ArrayFiller(char[] array, int offset, int length) {
this.array = Objects.requireNonNull(array, "array");
this.end = ArrayUtil.checkArrayStartEnd(array, offset, offset + length);
this.i = offset;
}
/**
* @see ru.windcorp.jputil.chars.CharConsumer#accept(char)
*/
@Override
public void accept(char c) {
if (i == end)
throw new ArrayIndexOutOfBoundsException(end);
array[i++] = c;
}
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
import java.util.Objects;
import ru.windcorp.jputil.ArrayUtil;
/**
* @author Javapony
*/
public class CharConsumers {
private CharConsumers() {
}
public static CharConsumer fillArray(char[] array, int offset, int length) {
return new ArrayFiller(array, offset, length);
}
public static CharConsumer fillArray(char[] array) {
return fillArray(array, 0, -1);
}
private static class ArrayFiller implements CharConsumer {
final char[] array;
int i;
final int end;
/**
* @param array
* @param offset
* @param length
*/
ArrayFiller(char[] array, int offset, int length) {
this.array = Objects.requireNonNull(array, "array");
this.end = ArrayUtil.checkArrayStartEnd(array, offset, offset + length);
this.i = offset;
}
/**
* @see ru.windcorp.jputil.chars.CharConsumer#accept(char)
*/
@Override
public void accept(char c) {
if (i == end)
throw new ArrayIndexOutOfBoundsException(end);
array[i++] = c;
}
}
}

View File

@ -1,84 +1,85 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.util.Arrays;
import java.util.function.IntPredicate;
import ru.windcorp.jputil.ArrayUtil;
@FunctionalInterface
public interface CharPredicate {
boolean test(char c);
public static CharPredicate and(CharPredicate first, CharPredicate second) {
return c -> first.test(c) && second.test(c);
}
public static CharPredicate or(CharPredicate first, CharPredicate second) {
return c -> first.test(c) || second.test(c);
}
public static CharPredicate negate(CharPredicate predicate) {
return c -> !predicate.test(c);
}
public static IntPredicate toInt(CharPredicate predicate) {
return i -> predicate.test((char) i);
}
public static CharPredicate toChar(IntPredicate predicate) {
return predicate::test;
}
public static CharPredicate forArray(char... chars) {
if (chars.length == 0) {
return c -> false;
}
if (chars.length == 1) {
return forChar(chars[0]);
}
if (chars.length < 16) {
return c -> ArrayUtil.firstIndexOf(chars, c) >= 0;
} else {
final char[] sorted = Arrays.copyOf(chars, chars.length);
Arrays.sort(sorted);
return c -> Arrays.binarySearch(chars, c) >= 0;
}
}
public static CharPredicate forChar(final char c) {
return given -> given == c;
}
public static CharPredicate forRange(final char minInclusive, final char maxExclusive) {
if (minInclusive > maxExclusive) {
throw new IllegalArgumentException("min > max: " + minInclusive + " > " + maxExclusive);
}
if (minInclusive == maxExclusive) {
return c -> false;
}
return c -> c >= minInclusive && c < maxExclusive;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
import java.util.Arrays;
import java.util.function.IntPredicate;
import ru.windcorp.jputil.ArrayUtil;
@FunctionalInterface
public interface CharPredicate {
boolean test(char c);
public static CharPredicate and(CharPredicate first, CharPredicate second) {
return c -> first.test(c) && second.test(c);
}
public static CharPredicate or(CharPredicate first, CharPredicate second) {
return c -> first.test(c) || second.test(c);
}
public static CharPredicate negate(CharPredicate predicate) {
return c -> !predicate.test(c);
}
public static IntPredicate toInt(CharPredicate predicate) {
return i -> predicate.test((char) i);
}
public static CharPredicate toChar(IntPredicate predicate) {
return predicate::test;
}
public static CharPredicate forArray(char... chars) {
if (chars.length == 0) {
return c -> false;
}
if (chars.length == 1) {
return forChar(chars[0]);
}
if (chars.length < 16) {
return c -> ArrayUtil.firstIndexOf(chars, c) >= 0;
} else {
final char[] sorted = Arrays.copyOf(chars, chars.length);
Arrays.sort(sorted);
return c -> Arrays.binarySearch(chars, c) >= 0;
}
}
public static CharPredicate forChar(final char c) {
return given -> given == c;
}
public static CharPredicate forRange(final char minInclusive, final char maxExclusive) {
if (minInclusive > maxExclusive) {
throw new IllegalArgumentException("min > max: " + minInclusive + " > " + maxExclusive);
}
if (minInclusive == maxExclusive) {
return c -> false;
}
return c -> c >= minInclusive && c < maxExclusive;
}
}

View File

@ -1,35 +1,36 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.util.function.IntSupplier;
@FunctionalInterface
public interface CharSupplier {
char getAsChar();
public static IntSupplier toInt(CharSupplier consumer) {
return consumer::getAsChar;
}
public static CharSupplier toChar(IntSupplier consumer) {
return () -> (char) consumer.getAsInt();
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
import java.util.function.IntSupplier;
@FunctionalInterface
public interface CharSupplier {
char getAsChar();
public static IntSupplier toInt(CharSupplier consumer) {
return consumer::getAsChar;
}
public static CharSupplier toChar(IntSupplier consumer) {
return () -> (char) consumer.getAsInt();
}
}

View File

@ -1,44 +1,45 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
public class EscapeException extends Exception {
private static final long serialVersionUID = -3647188859290365053L;
public EscapeException() {
super();
}
public EscapeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public EscapeException(String message, Throwable cause) {
super(message, cause);
}
public EscapeException(String message) {
super(message);
}
public EscapeException(Throwable cause) {
super(cause);
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
public class EscapeException extends Exception {
private static final long serialVersionUID = -3647188859290365053L;
public EscapeException() {
super();
}
public EscapeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public EscapeException(String message, Throwable cause) {
super(message, cause);
}
public EscapeException(String message) {
super(message);
}
public EscapeException(Throwable cause) {
super(cause);
}
}

View File

@ -1,474 +1,514 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.text.CharacterIterator;
import ru.windcorp.jputil.ArrayUtil;
import ru.windcorp.jputil.chars.reader.CharReader;
import ru.windcorp.jputil.chars.reader.CharReaders;
public class Escaper {
public static class EscaperBuilder {
private char escapeChar = '\\';
private char unicodeEscapeChar = 'u';
private char[] safes = null;
private char[] unsafes = null;
private boolean preferUnicode = false;
private boolean strict = true;
public EscaperBuilder withEscapeChar(char escapeChar) {
this.escapeChar = escapeChar;
return this;
}
public EscaperBuilder withUnicodeEscapeChar(char unicodeEscapeChar) {
this.unicodeEscapeChar = unicodeEscapeChar;
return this;
}
public EscaperBuilder withChars(char[] safes, char[] unsafes) {
this.safes = safes;
this.unsafes = unsafes;
return this;
}
public EscaperBuilder withChars(String safes, String unsafes) {
this.safes = safes.toCharArray();
this.unsafes = unsafes.toCharArray();
return this;
}
public EscaperBuilder withChars(char[] chars) {
this.safes = this.unsafes = chars;
return this;
}
public EscaperBuilder withChars(String chars) {
this.safes = this.unsafes = chars.toCharArray();
return this;
}
public EscaperBuilder withSafes(char[] safes) {
this.safes = safes;
return this;
}
public EscaperBuilder withSafes(String safes) {
this.safes = safes.toCharArray();
return this;
}
public EscaperBuilder withUnsafes(char[] unsafes) {
this.unsafes = unsafes;
return this;
}
public EscaperBuilder withUnsafes(String unsafes) {
this.unsafes = unsafes.toCharArray();
return this;
}
public EscaperBuilder preferUnicode(boolean preferUnicode) {
this.preferUnicode = preferUnicode;
return this;
}
public EscaperBuilder strict(boolean strict) {
this.strict = strict;
return this;
}
public Escaper build() {
return new Escaper(escapeChar, unicodeEscapeChar, safes, unsafes, preferUnicode, strict);
}
}
public static final Escaper JAVA = new Escaper('\\', 'u', "tbnrf'\"".toCharArray(), "\t\b\n\r\f\'\"".toCharArray(), true, true);
private final char escapeChar;
private final char unicodeEscapeChar;
private final char[] safes;
private final char[] unsafes;
private final boolean preferUnicode;
private final boolean strict;
protected Escaper(
char escapeChar, char unicodeEscapeChar,
char[] safes, char[] unsafes,
boolean preferUnicode, boolean strict) {
this.escapeChar = escapeChar;
this.unicodeEscapeChar = unicodeEscapeChar;
this.safes = safes;
this.unsafes = unsafes;
this.preferUnicode = preferUnicode;
this.strict = strict;
int duplicate;
if ((duplicate = ArrayUtil.hasDuplicates(safes)) != -1)
throw new IllegalArgumentException("Duplicate safe character '" + safes[duplicate] + "'");
if ((duplicate = ArrayUtil.hasDuplicates(unsafes)) != -1)
throw new IllegalArgumentException("Duplicate unsafe character '" + unsafes[duplicate] + "'");
for (char c : safes) {
if (c == escapeChar) throw new IllegalArgumentException("Safe characters contain escape chatacter");
if (c == unicodeEscapeChar) throw new IllegalArgumentException("Safe characters contain Unicode escape chatacter");
}
for (char c : unsafes) {
if (c == escapeChar) throw new IllegalArgumentException("Unsafe characters contain escape chatacter (escape character is escaped automatically)");
if (c == unicodeEscapeChar) throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter");
}
}
public static EscaperBuilder create() {
return new EscaperBuilder();
}
/*
* Logic - escape
*/
public void escape(CharReader src, int length, CharPredicate until, CharConsumer output) {
int end;
if (length < 0) end = Integer.MAX_VALUE;
else end = src.getPosition() + length;
while (src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current())))
escape(src.consume(), output);
}
public void escape(char c, CharConsumer output) {
if (c == escapeChar) {
output.accept(escapeChar);
output.accept(escapeChar);
return;
}
int index = ArrayUtil.firstIndexOf(unsafes, c);
if (index >= 0) {
output.accept(escapeChar);
output.accept(safes[index]);
} else {
if (preferUnicode && !isRegular(c)) {
escapeAsHex(c, output);
} else {
output.accept(c);
}
}
}
// SonarLint: Assignments should not be made from within sub-expressions (java:S1121)
// Seems self-evident enough
@SuppressWarnings("squid:S1121")
private void escapeAsHex(char c, CharConsumer output) {
output.accept(escapeChar);
output.accept(unicodeEscapeChar);
output.accept(StringUtil.hexDigit(c >>= (4 * 3)));
output.accept(StringUtil.hexDigit(c >>= (4 * 2)));
output.accept(StringUtil.hexDigit(c >>= (4 * 1)));
output.accept(StringUtil.hexDigit(c >> (4 * 0)));
}
public int getEscapedLength(CharReader src, int length, CharPredicate until) {
int end;
if (length < 0) end = Integer.MAX_VALUE;
else end = src.getPosition() + length;
int result = 0;
while (src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))) {
result += getEscapedLength(src.consume());
}
return result;
}
public int getEscapedLength(char c) {
if (c == escapeChar || ArrayUtil.firstIndexOf(unsafes, c) >= 0)
return 2;
else {
if (preferUnicode && !isRegular(c))
return 6;
else
return 1;
}
}
/*
* Logic - unescape
*/
public void unescape(CharReader src, int length, CharPredicate until, CharConsumer output) throws EscapeException {
int end;
if (length < 0) end = Integer.MAX_VALUE;
else end = src.getPosition() + length;
while (src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))) {
output.accept(unescapeOneSequence(src));
}
}
public char unescapeOneSequence(CharReader src) throws EscapeException {
int resetPos = src.getPosition();
try {
if (src.current() == escapeChar) {
src.next();
if (src.isEnd())
throw new EscapeException("Incomplete escape sequence at the end");
if (src.current() == escapeChar) {
src.next();
return escapeChar;
}
if (src.current() == unicodeEscapeChar) {
src.next();
return (char) (
hexValue(src.consume()) << (4 * 3) |
hexValue(src.consume()) << (4 * 2) |
hexValue(src.consume()) << (4 * 1) |
hexValue(src.consume()) << (4 * 0)
);
}
int index = ArrayUtil.firstIndexOf(safes, src.current());
if (index >= 0) {
src.next();
return unsafes[index];
}
if (strict)
throw new EscapeException("Unknown escape sequence \"" + escapeChar + src.current() + "\"");
else
return src.consume();
} else
return src.consume();
} catch (EscapeException | RuntimeException e) {
src.setPosition(resetPos);
throw e;
}
}
public int getUnescapedLength(CharReader src, int length, CharPredicate until) {
int end;
if (length < 0) end = Integer.MAX_VALUE;
else end = src.getPosition() + length;
int result = 0;
while (src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))) {
skipOneSequence(src);
result++;
}
return result;
}
public void skipOneSequence(CharReader src) {
if (
src.current() == escapeChar
&&
src.next() == unicodeEscapeChar
) {
src.advance(4);
}
src.next();
}
/*
* Utility
*/
public void escape(CharReader src, int length, CharConsumer output) {
escape(src, length, null, output);
}
public void escape(CharReader src, CharPredicate until, CharConsumer output) {
escape(src, -1, until, output);
}
public void escape(CharReader src, CharConsumer output) {
escape(src, -1, null, output);
}
public int getEscapedLength(CharReader src, int length) {
return getEscapedLength(src, length, null);
}
public int getEscapedLength(CharReader src, CharPredicate until) {
return getEscapedLength(src, -1, until);
}
public int getEscapedLength(CharReader src) {
return getEscapedLength(src, -1, null);
}
public char[] escape(CharReader src, int length, CharPredicate until) {
src.mark();
char[] result = new char[getEscapedLength(src, length, until)];
src.reset();
escape(src, length, until, CharConsumers.fillArray(result));
return result;
}
public char[] escape(CharReader src, int length) {
return escape(src, length, (CharPredicate) null);
}
public char[] escape(CharReader src, CharPredicate until) {
return escape(src, -1, until);
}
public char[] escape(CharReader src) {
return escape(src, -1, (CharPredicate) null);
}
public void unescape(CharReader src, int length, CharConsumer output) throws EscapeException {
unescape(src, length, null, output);
}
public void unescape(CharReader src, CharPredicate until, CharConsumer output) throws EscapeException {
unescape(src, -1, until, output);
}
public void unescape(CharReader src, CharConsumer output) throws EscapeException {
unescape(src, -1, null, output);
}
public int getUnescapedLength(CharReader src, int length) {
return getUnescapedLength(src, length, null);
}
public int getUnescapedLength(CharReader src, CharPredicate until) {
return getUnescapedLength(src, -1, until);
}
public int getUnescapedLength(CharReader src) {
return getUnescapedLength(src, -1, null);
}
public char[] unescape(CharReader src, int length, CharPredicate until) throws EscapeException {
src.mark();
char[] result = new char[getUnescapedLength(src, length, until)];
src.reset();
unescape(src, length, until, CharConsumers.fillArray(result));
return result;
}
public char[] unescape(CharReader src, int length) throws EscapeException {
return unescape(src, length, (CharPredicate) null);
}
public char[] unescape(CharReader src, CharPredicate until) throws EscapeException {
return unescape(src, -1, until);
}
public char[] unescape(CharReader src) throws EscapeException {
return unescape(src, -1, (CharPredicate) null);
}
@Deprecated()
public char[] unescape(CharacterIterator src, char until) throws EscapeException {
int index = src.getIndex();
CharReader reader = CharReaders.wrap(src);
char[] result = unescape(reader, -1, CharPredicate.forChar(until));
src.setIndex(index + reader.getPosition());
return result;
}
public String escape(String src) {
StringBuilder result = new StringBuilder(src.length());
escape(CharReaders.wrap(src), (CharConsumer) result::append);
return result.toString();
}
public String unescape(String src) throws EscapeException {
StringBuilder result = new StringBuilder(src.length());
unescape(CharReaders.wrap(src), (CharConsumer) result::append);
return result.toString();
}
/*
* Misc
*/
private static int hexValue(char c) throws EscapeException {
if (c < '0') throw thisIsNotAHexDigit(c);
if (c <= '9') return c - '0';
if (c < 'A') throw thisIsNotAHexDigit(c);
if (c <= 'F') return c - 'A';
if (c < 'a') throw thisIsNotAHexDigit(c);
if (c <= 'f') return c - 'a';
if (c == CharReader.DONE) throw new EscapeException("Incomplete Unicode escape sequence at the end");
throw thisIsNotAHexDigit(c);
}
private static EscapeException thisIsNotAHexDigit(char c) {
return new EscapeException("Invalid hex digit '" + c + "', expected [0-9A-Fa-f]");
}
protected static boolean isRegular(char c) {
return c >= ' ' && c <= '~';
}
/*
* Getters / setters
*/
public char getEscapeChar() {
return escapeChar;
}
public char getUnicodeEscapeChar() {
return unicodeEscapeChar;
}
public char[] getSafes() {
return safes;
}
public char[] getUnsafes() {
return unsafes;
}
public boolean isPreferUnicode() {
return preferUnicode;
}
public boolean isStrict() {
return strict;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
import java.text.CharacterIterator;
import ru.windcorp.jputil.ArrayUtil;
import ru.windcorp.jputil.chars.reader.CharReader;
import ru.windcorp.jputil.chars.reader.CharReaders;
public class Escaper {
public static class EscaperBuilder {
private char escapeChar = '\\';
private char unicodeEscapeChar = 'u';
private char[] safes = null;
private char[] unsafes = null;
private boolean preferUnicode = false;
private boolean strict = true;
public EscaperBuilder withEscapeChar(char escapeChar) {
this.escapeChar = escapeChar;
return this;
}
public EscaperBuilder withUnicodeEscapeChar(char unicodeEscapeChar) {
this.unicodeEscapeChar = unicodeEscapeChar;
return this;
}
public EscaperBuilder withChars(char[] safes, char[] unsafes) {
this.safes = safes;
this.unsafes = unsafes;
return this;
}
public EscaperBuilder withChars(String safes, String unsafes) {
this.safes = safes.toCharArray();
this.unsafes = unsafes.toCharArray();
return this;
}
public EscaperBuilder withChars(char[] chars) {
this.safes = this.unsafes = chars;
return this;
}
public EscaperBuilder withChars(String chars) {
this.safes = this.unsafes = chars.toCharArray();
return this;
}
public EscaperBuilder withSafes(char[] safes) {
this.safes = safes;
return this;
}
public EscaperBuilder withSafes(String safes) {
this.safes = safes.toCharArray();
return this;
}
public EscaperBuilder withUnsafes(char[] unsafes) {
this.unsafes = unsafes;
return this;
}
public EscaperBuilder withUnsafes(String unsafes) {
this.unsafes = unsafes.toCharArray();
return this;
}
public EscaperBuilder preferUnicode(boolean preferUnicode) {
this.preferUnicode = preferUnicode;
return this;
}
public EscaperBuilder strict(boolean strict) {
this.strict = strict;
return this;
}
public Escaper build() {
return new Escaper(escapeChar, unicodeEscapeChar, safes, unsafes, preferUnicode, strict);
}
}
public static final Escaper JAVA = new Escaper(
'\\',
'u',
"tbnrf'\"".toCharArray(),
"\t\b\n\r\f\'\"".toCharArray(),
true,
true
);
private final char escapeChar;
private final char unicodeEscapeChar;
private final char[] safes;
private final char[] unsafes;
private final boolean preferUnicode;
private final boolean strict;
protected Escaper(
char escapeChar,
char unicodeEscapeChar,
char[] safes,
char[] unsafes,
boolean preferUnicode,
boolean strict
) {
this.escapeChar = escapeChar;
this.unicodeEscapeChar = unicodeEscapeChar;
this.safes = safes;
this.unsafes = unsafes;
this.preferUnicode = preferUnicode;
this.strict = strict;
int duplicate;
if ((duplicate = ArrayUtil.hasDuplicates(safes)) != -1)
throw new IllegalArgumentException("Duplicate safe character '" + safes[duplicate] + "'");
if ((duplicate = ArrayUtil.hasDuplicates(unsafes)) != -1)
throw new IllegalArgumentException("Duplicate unsafe character '" + unsafes[duplicate] + "'");
for (char c : safes) {
if (c == escapeChar)
throw new IllegalArgumentException("Safe characters contain escape chatacter");
if (c == unicodeEscapeChar)
throw new IllegalArgumentException("Safe characters contain Unicode escape chatacter");
}
for (char c : unsafes) {
if (c == escapeChar)
throw new IllegalArgumentException(
"Unsafe characters contain escape chatacter (escape character is escaped automatically)"
);
if (c == unicodeEscapeChar)
throw new IllegalArgumentException("Unsafe characters contain Unicode escape chatacter");
}
}
public static EscaperBuilder create() {
return new EscaperBuilder();
}
/*
* Logic - escape
*/
public void escape(CharReader src, int length, CharPredicate until, CharConsumer output) {
int end;
if (length < 0)
end = Integer.MAX_VALUE;
else
end = src.getPosition() + length;
while (
src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))
)
escape(src.consume(), output);
}
public void escape(char c, CharConsumer output) {
if (c == escapeChar) {
output.accept(escapeChar);
output.accept(escapeChar);
return;
}
int index = ArrayUtil.firstIndexOf(unsafes, c);
if (index >= 0) {
output.accept(escapeChar);
output.accept(safes[index]);
} else {
if (preferUnicode && !isRegular(c)) {
escapeAsHex(c, output);
} else {
output.accept(c);
}
}
}
// SonarLint: Assignments should not be made from within sub-expressions
// (java:S1121)
// Seems self-evident enough
@SuppressWarnings("squid:S1121")
private void escapeAsHex(char c, CharConsumer output) {
output.accept(escapeChar);
output.accept(unicodeEscapeChar);
output.accept(StringUtil.hexDigit(c >>= (4 * 3)));
output.accept(StringUtil.hexDigit(c >>= (4 * 2)));
output.accept(StringUtil.hexDigit(c >>= (4 * 1)));
output.accept(StringUtil.hexDigit(c >> (4 * 0)));
}
public int getEscapedLength(CharReader src, int length, CharPredicate until) {
int end;
if (length < 0)
end = Integer.MAX_VALUE;
else
end = src.getPosition() + length;
int result = 0;
while (
src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))
) {
result += getEscapedLength(src.consume());
}
return result;
}
public int getEscapedLength(char c) {
if (c == escapeChar || ArrayUtil.firstIndexOf(unsafes, c) >= 0)
return 2;
else {
if (preferUnicode && !isRegular(c))
return 6;
else
return 1;
}
}
/*
* Logic - unescape
*/
public void unescape(CharReader src, int length, CharPredicate until, CharConsumer output) throws EscapeException {
int end;
if (length < 0)
end = Integer.MAX_VALUE;
else
end = src.getPosition() + length;
while (
src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))
) {
output.accept(unescapeOneSequence(src));
}
}
public char unescapeOneSequence(CharReader src) throws EscapeException {
int resetPos = src.getPosition();
try {
if (src.current() == escapeChar) {
src.next();
if (src.isEnd())
throw new EscapeException("Incomplete escape sequence at the end");
if (src.current() == escapeChar) {
src.next();
return escapeChar;
}
if (src.current() == unicodeEscapeChar) {
src.next();
return (char) (hexValue(src.consume()) << (4 * 3) |
hexValue(src.consume()) << (4 * 2) |
hexValue(src.consume()) << (4 * 1) |
hexValue(src.consume()) << (4 * 0));
}
int index = ArrayUtil.firstIndexOf(safes, src.current());
if (index >= 0) {
src.next();
return unsafes[index];
}
if (strict)
throw new EscapeException("Unknown escape sequence \"" + escapeChar + src.current() + "\"");
else
return src.consume();
} else
return src.consume();
} catch (EscapeException | RuntimeException e) {
src.setPosition(resetPos);
throw e;
}
}
public int getUnescapedLength(CharReader src, int length, CharPredicate until) {
int end;
if (length < 0)
end = Integer.MAX_VALUE;
else
end = src.getPosition() + length;
int result = 0;
while (
src.has() &&
src.getPosition() < end &&
(until == null || !until.test(src.current()))
) {
skipOneSequence(src);
result++;
}
return result;
}
public void skipOneSequence(CharReader src) {
if (
src.current() == escapeChar
&&
src.next() == unicodeEscapeChar
) {
src.advance(4);
}
src.next();
}
/*
* Utility
*/
public void escape(CharReader src, int length, CharConsumer output) {
escape(src, length, null, output);
}
public void escape(CharReader src, CharPredicate until, CharConsumer output) {
escape(src, -1, until, output);
}
public void escape(CharReader src, CharConsumer output) {
escape(src, -1, null, output);
}
public int getEscapedLength(CharReader src, int length) {
return getEscapedLength(src, length, null);
}
public int getEscapedLength(CharReader src, CharPredicate until) {
return getEscapedLength(src, -1, until);
}
public int getEscapedLength(CharReader src) {
return getEscapedLength(src, -1, null);
}
public char[] escape(CharReader src, int length, CharPredicate until) {
src.mark();
char[] result = new char[getEscapedLength(src, length, until)];
src.reset();
escape(src, length, until, CharConsumers.fillArray(result));
return result;
}
public char[] escape(CharReader src, int length) {
return escape(src, length, (CharPredicate) null);
}
public char[] escape(CharReader src, CharPredicate until) {
return escape(src, -1, until);
}
public char[] escape(CharReader src) {
return escape(src, -1, (CharPredicate) null);
}
public void unescape(CharReader src, int length, CharConsumer output) throws EscapeException {
unescape(src, length, null, output);
}
public void unescape(CharReader src, CharPredicate until, CharConsumer output) throws EscapeException {
unescape(src, -1, until, output);
}
public void unescape(CharReader src, CharConsumer output) throws EscapeException {
unescape(src, -1, null, output);
}
public int getUnescapedLength(CharReader src, int length) {
return getUnescapedLength(src, length, null);
}
public int getUnescapedLength(CharReader src, CharPredicate until) {
return getUnescapedLength(src, -1, until);
}
public int getUnescapedLength(CharReader src) {
return getUnescapedLength(src, -1, null);
}
public char[] unescape(CharReader src, int length, CharPredicate until) throws EscapeException {
src.mark();
char[] result = new char[getUnescapedLength(src, length, until)];
src.reset();
unescape(src, length, until, CharConsumers.fillArray(result));
return result;
}
public char[] unescape(CharReader src, int length) throws EscapeException {
return unescape(src, length, (CharPredicate) null);
}
public char[] unescape(CharReader src, CharPredicate until) throws EscapeException {
return unescape(src, -1, until);
}
public char[] unescape(CharReader src) throws EscapeException {
return unescape(src, -1, (CharPredicate) null);
}
@Deprecated()
public char[] unescape(CharacterIterator src, char until) throws EscapeException {
int index = src.getIndex();
CharReader reader = CharReaders.wrap(src);
char[] result = unescape(reader, -1, CharPredicate.forChar(until));
src.setIndex(index + reader.getPosition());
return result;
}
public String escape(String src) {
StringBuilder result = new StringBuilder(src.length());
escape(CharReaders.wrap(src), (CharConsumer) result::append);
return result.toString();
}
public String unescape(String src) throws EscapeException {
StringBuilder result = new StringBuilder(src.length());
unescape(CharReaders.wrap(src), (CharConsumer) result::append);
return result.toString();
}
/*
* Misc
*/
private static int hexValue(char c) throws EscapeException {
if (c < '0')
throw thisIsNotAHexDigit(c);
if (c <= '9')
return c - '0';
if (c < 'A')
throw thisIsNotAHexDigit(c);
if (c <= 'F')
return c - 'A';
if (c < 'a')
throw thisIsNotAHexDigit(c);
if (c <= 'f')
return c - 'a';
if (c == CharReader.DONE)
throw new EscapeException("Incomplete Unicode escape sequence at the end");
throw thisIsNotAHexDigit(c);
}
private static EscapeException thisIsNotAHexDigit(char c) {
return new EscapeException("Invalid hex digit '" + c + "', expected [0-9A-Fa-f]");
}
protected static boolean isRegular(char c) {
return c >= ' ' && c <= '~';
}
/*
* Getters / setters
*/
public char getEscapeChar() {
return escapeChar;
}
public char getUnicodeEscapeChar() {
return unicodeEscapeChar;
}
public char[] getSafes() {
return safes;
}
public char[] getUnsafes() {
return unsafes;
}
public boolean isPreferUnicode() {
return preferUnicode;
}
public boolean isStrict() {
return strict;
}
}

View File

@ -1,17 +1,21 @@
/*
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* 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.
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
import java.text.CharacterIterator;
@ -26,77 +30,81 @@ public class FancyCharacterIterator implements CharacterIterator {
this.data = data;
}
@Override
@Override
public char first() {
return obj.first();
}
@Override
@Override
public char last() {
return obj.last();
}
@Override
@Override
public char setIndex(int p) {
return obj.setIndex(p);
}
@Override
@Override
public char current() {
return obj.current();
}
@Override
@Override
public char next() {
return obj.next();
}
@Override
@Override
public char previous() {
return obj.previous();
}
@Override
@Override
public int getBeginIndex() {
return obj.getBeginIndex();
}
@Override
@Override
public int getEndIndex() {
return obj.getEndIndex();
}
@Override
@Override
public int getIndex() {
return obj.getIndex();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("\"");
sb.append(data);
sb.append("\"\n ");
for (int i = 0; i < obj.getIndex(); ++i) sb.append(' ');
for (int i = 0; i < obj.getIndex(); ++i)
sb.append(' ');
sb.append("^ Here.");
return sb.toString();
}
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// SonarLint: "clone" should not be overridden (java:S2975)
// And I wouldn't have done that if only CharacterIterator had not required exception safety.
// SonarLint: "toString()" and "clone()" methods should not return null (java:S2225)
// The clause is unreachable: CharacterArrayIterator implements Cloneable and superclass is Object.
@SuppressWarnings({"squid:S2975", "squid:S2225"})
@Override
public FancyCharacterIterator clone() {
try {
return (FancyCharacterIterator) super.clone();
} catch (CloneNotSupportedException cnse) {
// Impossible
return null;
}
}
}
// @SuppressWarnings("all") Just STFU, this _is_ terrific
// SonarLint: "clone" should not be overridden (java:S2975)
// And I wouldn't have done that if only CharacterIterator had not required
// exception safety.
// SonarLint: "toString()" and "clone()" methods should not return null
// (java:S2225)
// The clause is unreachable: CharacterArrayIterator implements Cloneable
// and superclass is Object.
@SuppressWarnings({ "squid:S2975", "squid:S2225" })
@Override
public FancyCharacterIterator clone() {
try {
return (FancyCharacterIterator) super.clone();
} catch (CloneNotSupportedException cnse) {
// Impossible
return null;
}
}
}

View File

@ -1,135 +1,138 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
public class IndentedStringBuilder {
private final StringBuilder sb = new StringBuilder();
private int indentLevel = 0;
private boolean indentApplied = false;
private String[] indentCache = new String[16];
private String indent = "";
private final char[] indentFill;
public IndentedStringBuilder(char[] indentFill) {
this.indentFill = indentFill;
}
public IndentedStringBuilder(String indentFill) {
this(indentFill.toCharArray());
}
public IndentedStringBuilder(char indentChar, int length) {
this(StringUtil.sequence(indentChar, length));
}
public IndentedStringBuilder() {
this(new char[] {' '});
}
@Override
public String toString() {
return sb.toString();
}
public int getIndentLevel() {
return indentLevel;
}
public void setIndentLevel(int level) {
this.indentLevel = level;
updateIndent();
}
public char[] getIndentFill() {
return indentFill;
}
protected void updateIndent() {
if (indentLevel < indentCache.length) {
indent = indentCache[indentLevel];
if (indent != null) return;
}
char[] fill = getIndentFill();
char[] array = new char[fill.length * getIndentLevel()];
for (int i = 0; i < array.length; i += fill.length)
System.arraycopy(fill, 0, array, i, fill.length);
indent = new String(array);
if (indentLevel < indentCache.length) {
indentCache[indentLevel] = indent;
}
}
public IndentedStringBuilder indent() {
setIndentLevel(getIndentLevel() + 1);
return this;
}
public IndentedStringBuilder unindent() {
setIndentLevel(getIndentLevel() - 1);
return this;
}
public IndentedStringBuilder append(Object x) {
if (x == null) {
appendRaw("null");
return this;
}
String str = x.toString();
int newLines = StringUtil.count(str, '\n');
if (newLines == 0) {
appendRaw(str);
return this;
}
String[] lines = StringUtil.split(str, '\n', newLines + 1);
appendRaw(lines[0]);
for (int i = 1; i < lines.length; ++i) {
newLine();
appendRaw(lines[i]);
}
return this;
}
public IndentedStringBuilder appendRaw(String str) {
if (str.isEmpty()) return this; // Do not append indent
if (!indentApplied) {
sb.append(indent);
indentApplied = true;
}
sb.append(str);
return this;
}
public IndentedStringBuilder newLine() {
sb.append('\n');
indentApplied = false;
return this;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
public class IndentedStringBuilder {
private final StringBuilder sb = new StringBuilder();
private int indentLevel = 0;
private boolean indentApplied = false;
private String[] indentCache = new String[16];
private String indent = "";
private final char[] indentFill;
public IndentedStringBuilder(char[] indentFill) {
this.indentFill = indentFill;
}
public IndentedStringBuilder(String indentFill) {
this(indentFill.toCharArray());
}
public IndentedStringBuilder(char indentChar, int length) {
this(StringUtil.sequence(indentChar, length));
}
public IndentedStringBuilder() {
this(new char[] { ' ' });
}
@Override
public String toString() {
return sb.toString();
}
public int getIndentLevel() {
return indentLevel;
}
public void setIndentLevel(int level) {
this.indentLevel = level;
updateIndent();
}
public char[] getIndentFill() {
return indentFill;
}
protected void updateIndent() {
if (indentLevel < indentCache.length) {
indent = indentCache[indentLevel];
if (indent != null)
return;
}
char[] fill = getIndentFill();
char[] array = new char[fill.length * getIndentLevel()];
for (int i = 0; i < array.length; i += fill.length)
System.arraycopy(fill, 0, array, i, fill.length);
indent = new String(array);
if (indentLevel < indentCache.length) {
indentCache[indentLevel] = indent;
}
}
public IndentedStringBuilder indent() {
setIndentLevel(getIndentLevel() + 1);
return this;
}
public IndentedStringBuilder unindent() {
setIndentLevel(getIndentLevel() - 1);
return this;
}
public IndentedStringBuilder append(Object x) {
if (x == null) {
appendRaw("null");
return this;
}
String str = x.toString();
int newLines = StringUtil.count(str, '\n');
if (newLines == 0) {
appendRaw(str);
return this;
}
String[] lines = StringUtil.split(str, '\n', newLines + 1);
appendRaw(lines[0]);
for (int i = 1; i < lines.length; ++i) {
newLine();
appendRaw(lines[i]);
}
return this;
}
public IndentedStringBuilder appendRaw(String str) {
if (str.isEmpty())
return this; // Do not append indent
if (!indentApplied) {
sb.append(indent);
indentApplied = true;
}
sb.append(str);
return this;
}
public IndentedStringBuilder newLine() {
sb.append('\n');
indentApplied = false;
return this;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +1,38 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
public class UncheckedEscapeException extends RuntimeException {
private static final long serialVersionUID = 5392628641744570926L;
public UncheckedEscapeException(String message, EscapeException cause) {
super(message, cause);
}
public UncheckedEscapeException(EscapeException cause) {
super(cause);
}
@Override
public synchronized EscapeException getCause() {
return (EscapeException) super.getCause();
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
public class UncheckedEscapeException extends RuntimeException {
private static final long serialVersionUID = 5392628641744570926L;
public UncheckedEscapeException(String message, EscapeException cause) {
super(message, cause);
}
public UncheckedEscapeException(EscapeException cause) {
super(cause);
}
@Override
public synchronized EscapeException getCause() {
return (EscapeException) super.getCause();
}
}

View File

@ -1,139 +1,143 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars;
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class WordReader implements Iterator<String> {
private final Reader reader;
private char[] wordBuffer = new char[1024];
private final CharBuffer inputBuffer;
private String next = null;
private boolean isExhausted = false;
private IOException lastException = null;
public WordReader(Reader src, int bufferSize) {
this.reader = src;
this.inputBuffer = CharBuffer.allocate(bufferSize);
}
public WordReader(Reader src) {
this(src, 2048);
}
public WordReader(char[] array, int offset, int length) {
this.reader = null;
this.inputBuffer = CharBuffer.wrap(Arrays.copyOfRange(array, offset, length + offset));
}
public WordReader(char[] array) {
this.reader = null;
this.inputBuffer = CharBuffer.wrap(array);
}
public WordReader(String str) {
this(str.toCharArray());
}
@Override
public String next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String result = next;
next = null;
return result;
}
@Override
public boolean hasNext() {
if (next != null) {
return true;
}
if (isExhausted) {
return false;
}
int length = 0;
char c;
while (true) {
c = nextChar();
if (isExhausted) break;
if (Character.isWhitespace(c)) {
if (length == 0) continue;
else break;
}
if (wordBuffer.length == length) {
char[] newBuf = new char[wordBuffer.length * 2];
System.arraycopy(wordBuffer, 0, newBuf, 0, wordBuffer.length);
wordBuffer = newBuf;
}
wordBuffer[length++] = c;
}
if (length == 0) {
return false;
}
next = new String(wordBuffer, 0, length);
return true;
}
private char nextChar() {
if (!inputBuffer.hasRemaining()) {
if (reader == null) {
isExhausted = true;
return 0;
}
inputBuffer.rewind();
try {
if (reader.read(inputBuffer) == -1) {
isExhausted = true;
}
} catch (IOException e) {
lastException = e;
isExhausted = true;
return 0;
}
}
return inputBuffer.get();
}
public IOException getLastException() {
return lastException;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars;
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class WordReader implements Iterator<String> {
private final Reader reader;
private char[] wordBuffer = new char[1024];
private final CharBuffer inputBuffer;
private String next = null;
private boolean isExhausted = false;
private IOException lastException = null;
public WordReader(Reader src, int bufferSize) {
this.reader = src;
this.inputBuffer = CharBuffer.allocate(bufferSize);
}
public WordReader(Reader src) {
this(src, 2048);
}
public WordReader(char[] array, int offset, int length) {
this.reader = null;
this.inputBuffer = CharBuffer.wrap(Arrays.copyOfRange(array, offset, length + offset));
}
public WordReader(char[] array) {
this.reader = null;
this.inputBuffer = CharBuffer.wrap(array);
}
public WordReader(String str) {
this(str.toCharArray());
}
@Override
public String next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String result = next;
next = null;
return result;
}
@Override
public boolean hasNext() {
if (next != null) {
return true;
}
if (isExhausted) {
return false;
}
int length = 0;
char c;
while (true) {
c = nextChar();
if (isExhausted)
break;
if (Character.isWhitespace(c)) {
if (length == 0)
continue;
else
break;
}
if (wordBuffer.length == length) {
char[] newBuf = new char[wordBuffer.length * 2];
System.arraycopy(wordBuffer, 0, newBuf, 0, wordBuffer.length);
wordBuffer = newBuf;
}
wordBuffer[length++] = c;
}
if (length == 0) {
return false;
}
next = new String(wordBuffer, 0, length);
return true;
}
private char nextChar() {
if (!inputBuffer.hasRemaining()) {
if (reader == null) {
isExhausted = true;
return 0;
}
inputBuffer.rewind();
try {
if (reader.read(inputBuffer) == -1) {
isExhausted = true;
}
} catch (IOException e) {
lastException = e;
isExhausted = true;
return 0;
}
}
return inputBuffer.get();
}
public IOException getLastException() {
return lastException;
}
}

View File

@ -1,104 +1,108 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
/**
* @author Javapony
*
*/
public abstract class AbstractCharReader implements CharReader {
protected static final int DEFAULT_MARK_STACK_SIZE = 8;
/**
* Current position of this CharReader. The reader maps its input to positions starting from 0.
* Positions that are negative or lower than 0 are invalid. {@link #current()}
* will throw an exception if position is invalid.
*/
protected int position = 0;
private int[] marks = new int[DEFAULT_MARK_STACK_SIZE];
private int nextMark = 0;
protected static int closestGreaterPowerOf2(int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x + 1;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#getPosition()
*/
@Override
public int getPosition() {
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#setPosition(int)
*/
@Override
public int setPosition(int position) {
this.position = position;
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#mark()
*/
@Override
public int mark() {
ensureMarksCapacity();
marks[nextMark++] = position;
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#forget()
*/
@Override
public int forget() {
return marks[--nextMark];
}
private void ensureMarksCapacity() {
if (nextMark < marks.length) return;
int[] newMarks = new int[closestGreaterPowerOf2(nextMark)];
System.arraycopy(marks, 0, newMarks, 0, nextMark);
marks = newMarks;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("\"");
mark();
position = 0;
sb.append(getChars());
reset();
sb.append("\"\n ");
for (int i = 0; i < position; ++i) sb.append(' ');
sb.append("^ (pos " + position + ")");
return sb.toString();
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars.reader;
/**
* @author Javapony
*/
public abstract class AbstractCharReader implements CharReader {
protected static final int DEFAULT_MARK_STACK_SIZE = 8;
/**
* Current position of this CharReader. The reader maps its input to
* positions starting from 0.
* Positions that are negative or lower than 0 are invalid.
* {@link #current()}
* will throw an exception if position is invalid.
*/
protected int position = 0;
private int[] marks = new int[DEFAULT_MARK_STACK_SIZE];
private int nextMark = 0;
protected static int closestGreaterPowerOf2(int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x + 1;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#getPosition()
*/
@Override
public int getPosition() {
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#setPosition(int)
*/
@Override
public int setPosition(int position) {
this.position = position;
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#mark()
*/
@Override
public int mark() {
ensureMarksCapacity();
marks[nextMark++] = position;
return position;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#forget()
*/
@Override
public int forget() {
return marks[--nextMark];
}
private void ensureMarksCapacity() {
if (nextMark < marks.length)
return;
int[] newMarks = new int[closestGreaterPowerOf2(nextMark)];
System.arraycopy(marks, 0, newMarks, 0, nextMark);
marks = newMarks;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("\"");
mark();
position = 0;
sb.append(getChars());
reset();
sb.append("\"\n ");
for (int i = 0; i < position; ++i)
sb.append(' ');
sb.append("^ (pos " + position + ")");
return sb.toString();
}
}

View File

@ -1,59 +1,60 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.util.Objects;
import ru.windcorp.jputil.ArrayUtil;
/**
* @author Javapony
*
*/
public class ArrayCharReader extends AbstractCharReader {
private final char[] array;
private final int offset;
private final int length;
public ArrayCharReader(char[] array, int offset, int length) {
this.array = Objects.requireNonNull(array, "array");
this.length = ArrayUtil.checkArrayOffsetLength(array, offset, length);
this.offset = offset;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#current()
*/
@Override
public char current() {
if (position >= length) return DONE;
if (position < 0)
throw new IllegalStateException("Position " + position + " is invalid");
return array[position + offset];
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
return length - position;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars.reader;
import java.util.Objects;
import ru.windcorp.jputil.ArrayUtil;
/**
* @author Javapony
*/
public class ArrayCharReader extends AbstractCharReader {
private final char[] array;
private final int offset;
private final int length;
public ArrayCharReader(char[] array, int offset, int length) {
this.array = Objects.requireNonNull(array, "array");
this.length = ArrayUtil.checkArrayOffsetLength(array, offset, length);
this.offset = offset;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#current()
*/
@Override
public char current() {
if (position >= length)
return DONE;
if (position < 0)
throw new IllegalStateException("Position " + position + " is invalid");
return array[position + offset];
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
return length - position;
}
}

View File

@ -1,122 +1,128 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
/**
* @author Javapony
*
*/
public abstract class BufferedCharReader extends AbstractCharReader {
protected static final int DEFAULT_BUFFER_SIZE = 256;
/**
* Buffer to store data acquired with {@link #pullChars(char[], int, int)}.
* Contains characters for positions <code>[0; bufferNextIndex)</code>.
*/
private char[] buffer = new char[DEFAULT_BUFFER_SIZE];
/**
* The index of the next character.
*/
private int bufferNextIndex = 0;
/**
* Whether this reader has been buffered completely.
*/
private boolean exhausted = false;
/**
* Acquires the next character.
* @return the character or {@link #DONE} if the end of the reader has been reached
*/
protected abstract char pullChar();
/**
* Acquires next characters and stores them in the array.
*
* @param buffer the output array
* @param offset index of the first character
* @param length maximum amount of characters to be pulled
* @return the amount of characters actually pulled
*/
protected int pullChars(char[] buffer, int offset, int length) {
for (int i = 0; i < length; ++i) {
if ((buffer[offset + i] = pullChar()) == DONE) {
return i;
}
}
return length;
}
private int pullChars(int offset, int length) {
if (exhausted || length == 0) return 0;
int pulled = pullChars(buffer, offset, length);
if (pulled != length) {
exhausted = true;
}
return pulled;
}
@Override
public char current() {
if (getPosition() < 0) {
throw new IllegalStateException("Position " + getPosition() + " is invalid");
}
if (getPosition() >= bufferNextIndex) {
if (exhausted) return DONE;
ensureBufferCapacity();
int needToPull = getPosition() - bufferNextIndex + 1;
assert needToPull <= buffer.length : "buffer size not ensured!";
int pulled = pullChars(bufferNextIndex, needToPull);
bufferNextIndex += pulled;
if (exhausted) return DONE;
}
// TODO test the shit out of current()
return buffer[getPosition()];
}
private void ensureBufferCapacity() {
if (getPosition() < buffer.length) return;
char[] newBuffer = new char[closestGreaterPowerOf2(getPosition())];
System.arraycopy(buffer, 0, newBuffer, 0, bufferNextIndex);
buffer = newBuffer;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
if (exhausted) {
return Math.max(bufferNextIndex - getPosition(), 0);
}
return super.remaining();
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars.reader;
/**
* @author Javapony
*/
public abstract class BufferedCharReader extends AbstractCharReader {
protected static final int DEFAULT_BUFFER_SIZE = 256;
/**
* Buffer to store data acquired with {@link #pullChars(char[], int, int)}.
* Contains characters for positions <code>[0; bufferNextIndex)</code>.
*/
private char[] buffer = new char[DEFAULT_BUFFER_SIZE];
/**
* The index of the next character.
*/
private int bufferNextIndex = 0;
/**
* Whether this reader has been buffered completely.
*/
private boolean exhausted = false;
/**
* Acquires the next character.
*
* @return the character or {@link #DONE} if the end of the reader has been
* reached
*/
protected abstract char pullChar();
/**
* Acquires next characters and stores them in the array.
*
* @param buffer the output array
* @param offset index of the first character
* @param length maximum amount of characters to be pulled
* @return the amount of characters actually pulled
*/
protected int pullChars(char[] buffer, int offset, int length) {
for (int i = 0; i < length; ++i) {
if ((buffer[offset + i] = pullChar()) == DONE) {
return i;
}
}
return length;
}
private int pullChars(int offset, int length) {
if (exhausted || length == 0)
return 0;
int pulled = pullChars(buffer, offset, length);
if (pulled != length) {
exhausted = true;
}
return pulled;
}
@Override
public char current() {
if (getPosition() < 0) {
throw new IllegalStateException("Position " + getPosition() + " is invalid");
}
if (getPosition() >= bufferNextIndex) {
if (exhausted)
return DONE;
ensureBufferCapacity();
int needToPull = getPosition() - bufferNextIndex + 1;
assert needToPull <= buffer.length : "buffer size not ensured!";
int pulled = pullChars(bufferNextIndex, needToPull);
bufferNextIndex += pulled;
if (exhausted)
return DONE;
}
// TODO test the shit out of current()
return buffer[getPosition()];
}
private void ensureBufferCapacity() {
if (getPosition() < buffer.length)
return;
char[] newBuffer = new char[closestGreaterPowerOf2(getPosition())];
System.arraycopy(buffer, 0, newBuffer, 0, bufferNextIndex);
buffer = newBuffer;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
if (exhausted) {
return Math.max(bufferNextIndex - getPosition(), 0);
}
return super.remaining();
}
}

View File

@ -1,270 +1,284 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.io.IOException;
import java.util.Arrays;
import ru.windcorp.jputil.chars.CharPredicate;
import ru.windcorp.jputil.chars.EscapeException;
import ru.windcorp.jputil.chars.Escaper;
/**
* @author Javapony
*
*/
// SonarLint: Constants should not be defined in interfaces (java:S1214)
// DONE is an essential part of the interface
@SuppressWarnings("squid:S1214")
public interface CharReader {
char DONE = '\uFFFF';
char current();
int getPosition();
int setPosition(int position);
default char next() {
return advance(1);
}
default char previous() {
return rollBack(1);
}
default char consume() {
char c = current();
advance(1);
return c;
}
default char advance(int forward) {
setPosition(getPosition() + forward);
return current();
}
default char rollBack(int backward) {
return advance(-backward);
}
default boolean isEnd() {
return current() == DONE;
}
default boolean has() {
return current() != DONE;
}
default boolean is(char c) {
return current() == c;
}
default int getChars(char[] output, int offset, int length) {
for (int i = 0; i < length; ++i) {
if ((output[offset + i] = current()) == DONE) {
return i;
}
next();
}
return length;
}
default int getChars(char[] output) {
return getChars(output, 0, output.length);
}
default char[] getChars(int length) {
char[] result = new char[length];
int from = getChars(result);
if (from != length) Arrays.fill(result, from, length, DONE);
return result;
}
default char[] getChars() {
return getChars(remaining());
}
default String getString(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length && !isEnd(); ++i) sb.append(consume());
return sb.toString();
}
default String getString() {
return getString(Integer.MAX_VALUE);
}
default boolean match(CharSequence seq) {
for (int i = 0; i < seq.length(); ++i) {
if (isEnd()) return false;
if (current() != seq.charAt(i)) return false;
next();
}
return true;
}
default boolean matchOrReset(CharSequence seq) {
mark();
if (match(seq)) {
forget();
return true;
} else {
reset();
return false;
}
}
default boolean match(char[] array) {
for (int i = 0; i < array.length; ++i) {
if (isEnd()) return false;
if (current() != array[i]) return false;
next();
}
return true;
}
default boolean matchOrReset(char[] array) {
mark();
if (match(array)) {
forget();
return true;
} else {
reset();
return false;
}
}
default int skip(CharPredicate condition) {
int i = 0;
while (has() && condition.test(current())) {
i++;
next();
}
return i;
}
default int skipWhitespace() {
return skip(Character::isWhitespace);
}
/**
* Skips to the end of the current line. Both <code>"\n"</code>, <code>"\r"</code>
* and <code>"\r\n"</code> are considered line separators.
* @return the amount of characters in the skipped line
*/
default int skipLine() {
int i = 0;
while (!isEnd()) {
if (current() == '\r') {
if (next() == '\n') {
next();
}
break;
} else if (current() == '\n') {
next();
break;
}
i++;
next();
}
return i;
}
default char[] readWhile(CharPredicate condition) {
return readUntil(CharPredicate.negate(condition));
}
default char[] readUntil(CharPredicate condition) {
mark();
int length = 0;
while (!isEnd() && !condition.test(current())) {
length++;
next();
}
reset();
char[] result = new char[length];
for (int i = 0; i < length; ++i) result[i] = consume();
return result;
}
default char[] readWord() {
skipWhitespace();
return readUntil(Character::isWhitespace);
}
default char[] readWord(Escaper escaper, char quotes) throws EscapeException {
skipWhitespace();
if (current() == quotes) {
return escaper.unescape(this, quotes);
} else {
return readWord();
}
}
default char[] readLine() {
mark();
int length = skipLine();
reset();
char[] result = new char[length];
for (int i = 0; i < result.length; ++i) result[i] = consume();
return result;
}
default int remaining() {
mark();
int result = 0;
while (consume() != DONE) result++;
reset();
return result;
}
int mark();
int forget();
default int reset() {
return setPosition(forget());
}
default IOException getLastException() {
return null;
}
default void resetLastException() {
// Do nothing
}
default boolean hasErrored() {
return getLastException() != null;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars.reader;
import java.io.IOException;
import java.util.Arrays;
import ru.windcorp.jputil.chars.CharPredicate;
import ru.windcorp.jputil.chars.EscapeException;
import ru.windcorp.jputil.chars.Escaper;
/**
* @author Javapony
*/
// SonarLint: Constants should not be defined in interfaces (java:S1214)
// DONE is an essential part of the interface
@SuppressWarnings("squid:S1214")
public interface CharReader {
char DONE = '\uFFFF';
char current();
int getPosition();
int setPosition(int position);
default char next() {
return advance(1);
}
default char previous() {
return rollBack(1);
}
default char consume() {
char c = current();
advance(1);
return c;
}
default char advance(int forward) {
setPosition(getPosition() + forward);
return current();
}
default char rollBack(int backward) {
return advance(-backward);
}
default boolean isEnd() {
return current() == DONE;
}
default boolean has() {
return current() != DONE;
}
default boolean is(char c) {
return current() == c;
}
default int getChars(char[] output, int offset, int length) {
for (int i = 0; i < length; ++i) {
if ((output[offset + i] = current()) == DONE) {
return i;
}
next();
}
return length;
}
default int getChars(char[] output) {
return getChars(output, 0, output.length);
}
default char[] getChars(int length) {
char[] result = new char[length];
int from = getChars(result);
if (from != length)
Arrays.fill(result, from, length, DONE);
return result;
}
default char[] getChars() {
return getChars(remaining());
}
default String getString(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length && !isEnd(); ++i)
sb.append(consume());
return sb.toString();
}
default String getString() {
return getString(Integer.MAX_VALUE);
}
default boolean match(CharSequence seq) {
for (int i = 0; i < seq.length(); ++i) {
if (isEnd())
return false;
if (current() != seq.charAt(i))
return false;
next();
}
return true;
}
default boolean matchOrReset(CharSequence seq) {
mark();
if (match(seq)) {
forget();
return true;
} else {
reset();
return false;
}
}
default boolean match(char[] array) {
for (int i = 0; i < array.length; ++i) {
if (isEnd())
return false;
if (current() != array[i])
return false;
next();
}
return true;
}
default boolean matchOrReset(char[] array) {
mark();
if (match(array)) {
forget();
return true;
} else {
reset();
return false;
}
}
default int skip(CharPredicate condition) {
int i = 0;
while (has() && condition.test(current())) {
i++;
next();
}
return i;
}
default int skipWhitespace() {
return skip(Character::isWhitespace);
}
/**
* Skips to the end of the current line. Both <code>"\n"</code>,
* <code>"\r"</code>
* and <code>"\r\n"</code> are considered line separators.
*
* @return the amount of characters in the skipped line
*/
default int skipLine() {
int i = 0;
while (!isEnd()) {
if (current() == '\r') {
if (next() == '\n') {
next();
}
break;
} else if (current() == '\n') {
next();
break;
}
i++;
next();
}
return i;
}
default char[] readWhile(CharPredicate condition) {
return readUntil(CharPredicate.negate(condition));
}
default char[] readUntil(CharPredicate condition) {
mark();
int length = 0;
while (!isEnd() && !condition.test(current())) {
length++;
next();
}
reset();
char[] result = new char[length];
for (int i = 0; i < length; ++i)
result[i] = consume();
return result;
}
default char[] readWord() {
skipWhitespace();
return readUntil(Character::isWhitespace);
}
default char[] readWord(Escaper escaper, char quotes) throws EscapeException {
skipWhitespace();
if (current() == quotes) {
return escaper.unescape(this, quotes);
} else {
return readWord();
}
}
default char[] readLine() {
mark();
int length = skipLine();
reset();
char[] result = new char[length];
for (int i = 0; i < result.length; ++i)
result[i] = consume();
return result;
}
default int remaining() {
mark();
int result = 0;
while (consume() != DONE)
result++;
reset();
return result;
}
int mark();
int forget();
default int reset() {
return setPosition(forget());
}
default IOException getLastException() {
return null;
}
default void resetLastException() {
// Do nothing
}
default boolean hasErrored() {
return getLastException() != null;
}
}

View File

@ -1,112 +1,113 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.CharacterIterator;
import java.util.function.IntSupplier;
import ru.windcorp.jputil.chars.CharSupplier;
/**
* @author Javapony
*
*/
public class CharReaders {
private CharReaders() {}
public static CharReader wrap(char[] array, int offset, int length) {
return new ArrayCharReader(array, offset, length);
}
public static CharReader wrap(char[] array) {
return wrap(array, 0, array.length);
}
public static CharReader wrap(String str, int offset, int length) {
return new StringCharReader(str, offset, length);
}
public static CharReader wrap(String str) {
return wrap(str, 0, str.length());
}
public static CharReader wrap(CharSupplier supplier) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
try {
return supplier.getAsChar();
} catch (Exception e) {
return DONE;
}
}
};
}
public static CharReader wrap(IntSupplier supplier) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
try {
int i = supplier.getAsInt();
if (i < 0 || i > Character.MAX_VALUE) {
return DONE;
} else {
return (char) i;
}
} catch (Exception e) {
return DONE;
}
}
};
}
public static CharReader wrap(CharacterIterator it) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
char result = it.current();
it.next();
return result;
}
};
}
public static CharReader wrap(Reader reader) {
return new ReaderCharReader(reader);
}
public static CharReader wrap(InputStream is, Charset charset) {
return wrap(new InputStreamReader(is, charset));
}
public static CharReader wrapDefaultCS(InputStream is) {
return wrap(new InputStreamReader(is));
}
public static CharReader wrapUTF8(InputStream is) {
return wrap(new InputStreamReader(is, StandardCharsets.UTF_8));
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars.reader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.CharacterIterator;
import java.util.function.IntSupplier;
import ru.windcorp.jputil.chars.CharSupplier;
/**
* @author Javapony
*/
public class CharReaders {
private CharReaders() {
}
public static CharReader wrap(char[] array, int offset, int length) {
return new ArrayCharReader(array, offset, length);
}
public static CharReader wrap(char[] array) {
return wrap(array, 0, array.length);
}
public static CharReader wrap(String str, int offset, int length) {
return new StringCharReader(str, offset, length);
}
public static CharReader wrap(String str) {
return wrap(str, 0, str.length());
}
public static CharReader wrap(CharSupplier supplier) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
try {
return supplier.getAsChar();
} catch (Exception e) {
return DONE;
}
}
};
}
public static CharReader wrap(IntSupplier supplier) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
try {
int i = supplier.getAsInt();
if (i < 0 || i > Character.MAX_VALUE) {
return DONE;
} else {
return (char) i;
}
} catch (Exception e) {
return DONE;
}
}
};
}
public static CharReader wrap(CharacterIterator it) {
return new BufferedCharReader() {
@Override
protected char pullChar() {
char result = it.current();
it.next();
return result;
}
};
}
public static CharReader wrap(Reader reader) {
return new ReaderCharReader(reader);
}
public static CharReader wrap(InputStream is, Charset charset) {
return wrap(new InputStreamReader(is, charset));
}
public static CharReader wrapDefaultCS(InputStream is) {
return wrap(new InputStreamReader(is));
}
public static CharReader wrapUTF8(InputStream is) {
return wrap(new InputStreamReader(is, StandardCharsets.UTF_8));
}
}

View File

@ -1,70 +1,71 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.io.IOException;
import java.io.Reader;
/**
* @author Javapony
*
*/
public class ReaderCharReader extends BufferedCharReader {
private final Reader src;
private IOException lastException = null;
public ReaderCharReader(Reader src) {
this.src = src;
}
/**
* @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChar()
*/
@Override
protected char pullChar() {
try {
return (char) src.read(); // Handles DONE correctly
} catch (IOException e) {
lastException = e;
return DONE;
}
}
/**
* @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChars(char[], int, int)
*/
@Override
protected int pullChars(char[] buffer, int offset, int length) {
try {
return src.read(buffer, offset, length);
} catch (IOException e) {
lastException = e;
return 0;
}
}
/**
* @return the exception
*/
@Override
public IOException getLastException() {
return lastException;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars.reader;
import java.io.IOException;
import java.io.Reader;
/**
* @author Javapony
*/
public class ReaderCharReader extends BufferedCharReader {
private final Reader src;
private IOException lastException = null;
public ReaderCharReader(Reader src) {
this.src = src;
}
/**
* @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChar()
*/
@Override
protected char pullChar() {
try {
return (char) src.read(); // Handles DONE correctly
} catch (IOException e) {
lastException = e;
return DONE;
}
}
/**
* @see ru.windcorp.jputil.chars.reader.BufferedCharReader#pullChars(char[],
* int, int)
*/
@Override
protected int pullChars(char[] buffer, int offset, int length) {
try {
return src.read(buffer, offset, length);
} catch (IOException e) {
lastException = e;
return 0;
}
}
/**
* @return the exception
*/
@Override
public IOException getLastException() {
return lastException;
}
}

View File

@ -1,65 +1,68 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.chars.reader;
import java.util.Objects;
/**
* @author Javapony
*
*/
public class StringCharReader extends AbstractCharReader {
private final String str;
private final int offset;
private final int length;
public StringCharReader(String str, int offset, int length) {
this.str = Objects.requireNonNull(str, "str");
if (length < 0)
length = str.length();
int end = offset + length;
if (end > str.length() || offset < 0)
throw new IllegalArgumentException("String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")");
this.offset = offset;
this.length = length;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#current()
*/
@Override
public char current() {
if (position >= length) return DONE;
if (position < 0)
throw new IllegalStateException("Position " + position + " is invalid");
return str.charAt(position + offset);
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
return length - position;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.chars.reader;
import java.util.Objects;
/**
* @author Javapony
*/
public class StringCharReader extends AbstractCharReader {
private final String str;
private final int offset;
private final int length;
public StringCharReader(String str, int offset, int length) {
this.str = Objects.requireNonNull(str, "str");
if (length < 0)
length = str.length();
int end = offset + length;
if (end > str.length() || offset < 0)
throw new IllegalArgumentException(
"String contains [0; " + str.length() + "), requested [" + offset + "; " + end + ")"
);
this.offset = offset;
this.length = length;
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#current()
*/
@Override
public char current() {
if (position >= length)
return DONE;
if (position < 0)
throw new IllegalStateException("Position " + position + " is invalid");
return str.charAt(position + offset);
}
/**
* @see ru.windcorp.jputil.chars.reader.CharReader#remaining()
*/
@Override
public int remaining() {
return length - position;
}
}

View File

@ -1,8 +1,26 @@
package ru.windcorp.jputil.functions;
@FunctionalInterface
public interface FloatSupplier {
float getAsFloat();
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.functions;
@FunctionalInterface
public interface FloatSupplier {
float getAsFloat();
}

View File

@ -1,72 +1,76 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
@FunctionalInterface
public interface ThrowingBiConsumer<T, U, E extends Exception> {
@FunctionalInterface
public static interface BiConsumerHandler<T, U, E extends Exception> {
void handle(T t, U u, E e);
}
void accept(T t, U u) throws E;
@SuppressWarnings("unchecked")
default BiConsumer<T, U> withHandler(BiConsumerHandler<? super T, ? super U, ? super E> handler) {
return (t, u) -> {
try {
accept(t, u);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.handle(t, u, (E) e);
}
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
ThrowingBiConsumer<? super T, ? super U, ? extends E> first,
ThrowingBiConsumer<? super T, ? super U, ? extends E> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
BiConsumer<? super T, ? super U> first,
ThrowingBiConsumer<? super T, ? super U, E> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
ThrowingBiConsumer<? super T, ? super U, E> first,
BiConsumer<? super T, ? super U> second) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
@FunctionalInterface
public interface ThrowingBiConsumer<T, U, E extends Exception> {
@FunctionalInterface
public static interface BiConsumerHandler<T, U, E extends Exception> {
void handle(T t, U u, E e);
}
void accept(T t, U u) throws E;
@SuppressWarnings("unchecked")
default BiConsumer<T, U> withHandler(BiConsumerHandler<? super T, ? super U, ? super E> handler) {
return (t, u) -> {
try {
accept(t, u);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.handle(t, u, (E) e);
}
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
ThrowingBiConsumer<? super T, ? super U, ? extends E> first,
ThrowingBiConsumer<? super T, ? super U, ? extends E> second
) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
BiConsumer<? super T, ? super U> first,
ThrowingBiConsumer<? super T, ? super U, E> second
) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
public static <T, U, E extends Exception> ThrowingBiConsumer<T, U, E> concat(
ThrowingBiConsumer<? super T, ? super U, E> first,
BiConsumer<? super T, ? super U> second
) {
return (t, u) -> {
first.accept(t, u);
second.accept(t, u);
};
}
}

View File

@ -1,62 +1,72 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
@SuppressWarnings("unchecked")
default Consumer<T> withHandler(BiConsumer<? super T, ? super E> handler) {
return t -> {
try {
accept(t);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.accept(t, (E) e);
}
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first, ThrowingConsumer<? super T, ? extends E> second) {
return t -> {
first.accept(t);
second.accept(t);
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(Consumer<? super T> first, ThrowingConsumer<? super T, ? extends E> second) {
return t -> {
first.accept(t);
second.accept(t);
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(ThrowingConsumer<? super T, ? extends E> first, Consumer<? super T> second) {
return t -> {
first.accept(t);
second.accept(t);
};
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
@SuppressWarnings("unchecked")
default Consumer<T> withHandler(BiConsumer<? super T, ? super E> handler) {
return t -> {
try {
accept(t);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.accept(t, (E) e);
}
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
ThrowingConsumer<? super T, ? extends E> first,
ThrowingConsumer<? super T, ? extends E> second
) {
return t -> {
first.accept(t);
second.accept(t);
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
Consumer<? super T> first,
ThrowingConsumer<? super T, ? extends E> second
) {
return t -> {
first.accept(t);
second.accept(t);
};
}
public static <T, E extends Exception> ThrowingConsumer<T, E> concat(
ThrowingConsumer<? super T, ? extends E> first,
Consumer<? super T> second
) {
return t -> {
first.accept(t);
second.accept(t);
};
}
}

View File

@ -1,73 +1,81 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
@FunctionalInterface
public interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
@SuppressWarnings("unchecked")
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, Function<? super T, ? extends R> value) {
return t -> {
try {
return apply(t);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
if (handler != null) handler.accept(t, (E) e);
return value == null ? null : value.apply(t);
}
};
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, Supplier<? extends R> value) {
return withHandler(handler, t -> value.get());
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, R value) {
return withHandler(handler, t -> value);
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler) {
return withHandler(handler, (Function<T, R>) null);
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, ? extends E> first,
ThrowingFunction<? super I, ? extends R, ? extends E> second) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
Function<? super T, I> first,
ThrowingFunction<? super I, ? extends R, E> second) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, E> first,
Function<? super I, ? extends R> second) {
return t -> second.apply(first.apply(t));
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.functions;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
@FunctionalInterface
public interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
@SuppressWarnings("unchecked")
default Function<T, R> withHandler(
BiConsumer<? super T, ? super E> handler,
Function<? super T, ? extends R> value
) {
return t -> {
try {
return apply(t);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
if (handler != null)
handler.accept(t, (E) e);
return value == null ? null : value.apply(t);
}
};
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, Supplier<? extends R> value) {
return withHandler(handler, t -> value.get());
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler, R value) {
return withHandler(handler, t -> value);
}
default Function<T, R> withHandler(BiConsumer<? super T, ? super E> handler) {
return withHandler(handler, (Function<T, R>) null);
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, ? extends E> first,
ThrowingFunction<? super I, ? extends R, ? extends E> second
) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
Function<? super T, I> first,
ThrowingFunction<? super I, ? extends R, E> second
) {
return t -> second.apply(first.apply(t));
}
public static <T, R, I, E extends Exception> ThrowingFunction<T, R, E> compose(
ThrowingFunction<? super T, I, E> first,
Function<? super I, ? extends R> second
) {
return t -> second.apply(first.apply(t));
}
}

View File

@ -1,64 +1,65 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingRunnable<E extends Exception> {
void run() throws E;
@SuppressWarnings("unchecked")
default Runnable withHandler(Consumer<? super E> handler) {
return () -> {
try {
run();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.accept((E) e);
}
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(
ThrowingRunnable<? extends E> first,
ThrowingRunnable<? extends E> second
) {
return () -> {
first.run();
second.run();
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(Runnable first, ThrowingRunnable<E> second) {
return () -> {
first.run();
second.run();
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(ThrowingRunnable<E> first, Runnable second) {
return () -> {
first.run();
second.run();
};
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.functions;
import java.util.function.Consumer;
@FunctionalInterface
public interface ThrowingRunnable<E extends Exception> {
void run() throws E;
@SuppressWarnings("unchecked")
default Runnable withHandler(Consumer<? super E> handler) {
return () -> {
try {
run();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
handler.accept((E) e);
}
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(
ThrowingRunnable<? extends E> first,
ThrowingRunnable<? extends E> second
) {
return () -> {
first.run();
second.run();
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(Runnable first, ThrowingRunnable<E> second) {
return () -> {
first.run();
second.run();
};
}
public static <E extends Exception> ThrowingRunnable<E> concat(ThrowingRunnable<E> first, Runnable second) {
return () -> {
first.run();
second.run();
};
}
}

View File

@ -1,50 +1,52 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.functions;
import java.util.function.Consumer;
import java.util.function.Supplier;
@FunctionalInterface
public interface ThrowingSupplier<T, E extends Exception> {
T get() throws E;
@SuppressWarnings("unchecked")
default Supplier<T> withHandler(Consumer<? super E> handler, Supplier<? extends T> value) {
return () -> {
try {
return get();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
if (handler != null) handler.accept((E) e);
return value == null ? null : value.get();
}
};
}
default Supplier<T> withHandler(Consumer<? super E> handler, T value) {
return withHandler(handler, () -> value);
}
default Supplier<T> withHandler(Consumer<? super E> handler) {
return withHandler(handler, (Supplier<T>) null);
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.functions;
import java.util.function.Consumer;
import java.util.function.Supplier;
@FunctionalInterface
public interface ThrowingSupplier<T, E extends Exception> {
T get() throws E;
@SuppressWarnings("unchecked")
default Supplier<T> withHandler(Consumer<? super E> handler, Supplier<? extends T> value) {
return () -> {
try {
return get();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
if (handler != null)
handler.accept((E) e);
return value == null ? null : value.get();
}
};
}
default Supplier<T> withHandler(Consumer<? super E> handler, T value) {
return withHandler(handler, () -> value);
}
default Supplier<T> withHandler(Consumer<? super E> handler) {
return withHandler(handler, (Supplier<T>) null);
}
}

View File

@ -1,47 +1,48 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class ArrayIterator<E> implements Iterator<E> {
private final E[] array;
private int next;
@SafeVarargs
public ArrayIterator(E... array) {
this.array = array;
}
@Override
public boolean hasNext() {
return next < array.length;
}
@Override
public E next() {
try {
return array[next++];
} catch (ArrayIndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class ArrayIterator<E> implements Iterator<E> {
private final E[] array;
private int next;
@SafeVarargs
public ArrayIterator(E... array) {
this.array = array;
}
@Override
public boolean hasNext() {
return next < array.length;
}
@Override
public E next() {
try {
return array[next++];
} catch (ArrayIndexOutOfBoundsException e) {
throw new NoSuchElementException();
}
}
}

View File

@ -1,61 +1,61 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.function.Function;
/**
* @author Javapony
*
*/
public class FunctionIterator<T, E> implements Iterator<E> {
private final Iterator<T> parent;
private final Function<T, E> function;
public FunctionIterator(Iterator<T> parent, Function<T, E> function) {
this.parent = parent;
this.function = function;
}
/**
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
return parent.hasNext();
}
/**
* @see java.util.Iterator#next()
*/
@Override
public E next() {
return function.apply(parent.next());
}
/**
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
parent.remove();
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.function.Function;
/**
* @author Javapony
*/
public class FunctionIterator<T, E> implements Iterator<E> {
private final Iterator<T> parent;
private final Function<T, E> function;
public FunctionIterator(Iterator<T> parent, Function<T, E> function) {
this.parent = parent;
this.function = function;
}
/**
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
return parent.hasNext();
}
/**
* @see java.util.Iterator#next()
*/
@Override
public E next() {
return function.apply(parent.next());
}
/**
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
parent.remove();
}
}

View File

@ -1,60 +1,62 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class PeekingIterator<E> implements Iterator<E> {
private final Iterator<? extends E> source;
private E next = null;
public PeekingIterator(Iterator<? extends E> source) {
this.source = source;
}
@Override
public boolean hasNext() {
return next != null || source.hasNext();
}
public E peek() {
if (next == null) {
if (source.hasNext()) {
next = source.next();
} else {
throw new NoSuchElementException();
}
}
return next;
}
// SonarLint: "Iterator.next()" methods should throw "NoSuchElementException" (java:S2272)
// peek() throws NoSuchElementException as expected
@SuppressWarnings("squid:S2272")
@Override
public E next() {
E element = peek();
next = null;
return element;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class PeekingIterator<E> implements Iterator<E> {
private final Iterator<? extends E> source;
private E next = null;
public PeekingIterator(Iterator<? extends E> source) {
this.source = source;
}
@Override
public boolean hasNext() {
return next != null || source.hasNext();
}
public E peek() {
if (next == null) {
if (source.hasNext()) {
next = source.next();
} else {
throw new NoSuchElementException();
}
}
return next;
}
// SonarLint: "Iterator.next()" methods should throw
// "NoSuchElementException" (java:S2272)
// peek() throws NoSuchElementException as expected
@SuppressWarnings("squid:S2272")
@Override
public E next() {
E element = peek();
next = null;
return element;
}
}

View File

@ -1,67 +1,70 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class RangeIterator<E> implements Iterator<E> {
private final Iterator<E> parent;
private final int from;
private final int amount;
private int nextIndex = 0;
public RangeIterator(Iterator<E> iterator, int from, int amount) {
this.parent = iterator;
this.from = from;
this.amount = amount < 0 ? Integer.MAX_VALUE : amount;
}
public RangeIterator(Iterator<E> iterator, int from) {
this(iterator, from, -1);
}
@Override
public boolean hasNext() {
update();
return nextIndex < from + amount && parent.hasNext();
}
@Override
public E next() {
update();
if (nextIndex >= from + amount) {
throw new NoSuchElementException("RangeIterator about to retrieve element " + nextIndex
+ " which exceeds upper boundary " + (from + amount));
}
E result = parent.next();
nextIndex++;
return result;
}
protected void update() {
while (nextIndex < from && parent.hasNext()) {
parent.next();
nextIndex++;
}
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.iterators;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class RangeIterator<E> implements Iterator<E> {
private final Iterator<E> parent;
private final int from;
private final int amount;
private int nextIndex = 0;
public RangeIterator(Iterator<E> iterator, int from, int amount) {
this.parent = iterator;
this.from = from;
this.amount = amount < 0 ? Integer.MAX_VALUE : amount;
}
public RangeIterator(Iterator<E> iterator, int from) {
this(iterator, from, -1);
}
@Override
public boolean hasNext() {
update();
return nextIndex < from + amount && parent.hasNext();
}
@Override
public E next() {
update();
if (nextIndex >= from + amount) {
throw new NoSuchElementException(
"RangeIterator about to retrieve element " + nextIndex
+ " which exceeds upper boundary " + (from + amount)
);
}
E result = parent.next();
nextIndex++;
return result;
}
protected void update() {
while (nextIndex < from && parent.hasNext()) {
parent.next();
nextIndex++;
}
}
}

View File

@ -1,70 +1,72 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.iterators;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Reiterator<E> implements Iterable<E> {
private class ReiteratorIterator implements Iterator<E> {
int index = 0;
@Override
public boolean hasNext() {
synchronized (source) {
if (index >= data.size()) {
if (!source.hasNext()) {
return false;
} else {
data.add(source.next());
}
}
return true;
}
}
@Override
public E next() {
E result;
synchronized (source) {
if (!hasNext()) throw new NoSuchElementException();
result = data.get(index);
}
index++;
return result;
}
}
private final Iterator<E> source;
private final ArrayList<E> data = new ArrayList<>();
public Reiterator(Iterator<E> source) {
this.source = source;
}
@Override
public Iterator<E> iterator() {
return new ReiteratorIterator();
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.iterators;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class Reiterator<E> implements Iterable<E> {
private class ReiteratorIterator implements Iterator<E> {
int index = 0;
@Override
public boolean hasNext() {
synchronized (source) {
if (index >= data.size()) {
if (!source.hasNext()) {
return false;
} else {
data.add(source.next());
}
}
return true;
}
}
@Override
public E next() {
E result;
synchronized (source) {
if (!hasNext())
throw new NoSuchElementException();
result = data.get(index);
}
index++;
return result;
}
}
private final Iterator<E> source;
private final ArrayList<E> data = new ArrayList<>();
public Reiterator(Iterator<E> source) {
this.source = source;
}
@Override
public Iterator<E> iterator() {
return new ReiteratorIterator();
}
}

View File

@ -1,39 +1,40 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
public abstract class AbstractSelectorOperator implements SelectorOperator {
private final String[] names;
public AbstractSelectorOperator(String[] names) {
this.names = names;
}
@Override
public boolean matchesName(String name) {
for (String n : names) {
if (n.equals(name)) {
return true;
}
}
return false;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
public abstract class AbstractSelectorOperator implements SelectorOperator {
private final String[] names;
public AbstractSelectorOperator(String[] names) {
this.names = names;
}
@Override
public boolean matchesName(String name) {
for (String n : names) {
if (n.equals(name)) {
return true;
}
}
return false;
}
}

View File

@ -1,57 +1,58 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import ru.windcorp.jputil.SyntaxException;
import ru.windcorp.jputil.chars.StringUtil;
public abstract class NamedParameterizedSelector<T> extends NamedSelector<T> {
private final char separator;
private String givenName;
public NamedParameterizedSelector(char separator, String... names) {
super(names);
this.separator = separator;
}
@Override
public Selector<T> derive(String name) throws SyntaxException {
String[] parts = StringUtil.split(name, separator, 2);
if (parts[1] == null) {
return null;
}
if (!matchesName(parts[0])) {
return null;
}
NamedParameterizedSelector<T> selector = deriveImpl(parts[1]);
selector.givenName = name;
return selector;
}
protected abstract NamedParameterizedSelector<T> deriveImpl(String param) throws SyntaxException;
@Override
public String toString() {
return givenName;
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import ru.windcorp.jputil.SyntaxException;
import ru.windcorp.jputil.chars.StringUtil;
public abstract class NamedParameterizedSelector<T> extends NamedSelector<T> {
private final char separator;
private String givenName;
public NamedParameterizedSelector(char separator, String... names) {
super(names);
this.separator = separator;
}
@Override
public Selector<T> derive(String name) throws SyntaxException {
String[] parts = StringUtil.split(name, separator, 2);
if (parts[1] == null) {
return null;
}
if (!matchesName(parts[0])) {
return null;
}
NamedParameterizedSelector<T> selector = deriveImpl(parts[1]);
selector.givenName = name;
return selector;
}
protected abstract NamedParameterizedSelector<T> deriveImpl(String param) throws SyntaxException;
@Override
public String toString() {
return givenName;
}
}

View File

@ -1,50 +1,51 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import ru.windcorp.jputil.SyntaxException;
public abstract class NamedSelector<T> implements Selector<T> {
private final String[] names;
public NamedSelector(String... names) {
this.names = names;
}
public boolean matchesName(String name) {
for (String n : names) {
if (n.equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
@Override
public Selector<T> derive(String name) throws SyntaxException {
return matchesName(name) ? this : null;
}
@Override
public String toString() {
return names[0];
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import ru.windcorp.jputil.SyntaxException;
public abstract class NamedSelector<T> implements Selector<T> {
private final String[] names;
public NamedSelector(String... names) {
this.names = names;
}
public boolean matchesName(String name) {
for (String n : names) {
if (n.equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
@Override
public Selector<T> derive(String name) throws SyntaxException {
return matchesName(name) ? this : null;
}
@Override
public String toString() {
return names[0];
}
}

View File

@ -1,36 +1,37 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorAnd extends AbstractSelectorOperator {
public OperatorAnd(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) && arg2.test(obj));
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorAnd extends AbstractSelectorOperator {
public OperatorAnd(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) && arg2.test(obj));
}
}

View File

@ -1,36 +1,37 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorExclude extends AbstractSelectorOperator {
public OperatorExclude(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) && !arg2.test(obj));
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorExclude extends AbstractSelectorOperator {
public OperatorExclude(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) && !arg2.test(obj));
}
}

View File

@ -1,34 +1,35 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorNot extends AbstractSelectorOperator {
public OperatorNot(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
stack.push(stack.pop().negate());
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorNot extends AbstractSelectorOperator {
public OperatorNot(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
stack.push(stack.pop().negate());
}
}

View File

@ -1,36 +1,37 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorOr extends AbstractSelectorOperator {
public OperatorOr(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) || arg2.test(obj));
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorOr extends AbstractSelectorOperator {
public OperatorOr(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) || arg2.test(obj));
}
}

View File

@ -1,36 +1,37 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorXor extends AbstractSelectorOperator {
public OperatorXor(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) != arg2.test(obj));
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public class OperatorXor extends AbstractSelectorOperator {
public OperatorXor(String... names) {
super(names);
}
@Override
public <T> void process(Deque<Predicate<T>> stack) {
Predicate<T> arg2 = stack.pop();
Predicate<T> arg1 = stack.pop();
stack.push(obj -> arg1.test(obj) != arg2.test(obj));
}
}

View File

@ -1,36 +1,37 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.function.Predicate;
public class PredicateWrapper<T> extends NamedSelector<T> {
private final Predicate<? super T> predicate;
public PredicateWrapper(String name, Predicate<? super T> predicate) {
super(name);
this.predicate = predicate;
}
@Override
public boolean test(T obj) {
return predicate.test(obj);
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.function.Predicate;
public class PredicateWrapper<T> extends NamedSelector<T> {
private final Predicate<? super T> predicate;
public PredicateWrapper(String name, Predicate<? super T> predicate) {
super(name);
this.predicate = predicate;
}
@Override
public boolean test(T obj) {
return predicate.test(obj);
}
}

View File

@ -1,28 +1,29 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.function.Predicate;
import ru.windcorp.jputil.SyntaxException;
public interface Selector<T> extends Predicate<T> {
public Selector<T> derive(String name) throws SyntaxException;
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.function.Predicate;
import ru.windcorp.jputil.SyntaxException;
public interface Selector<T> extends Predicate<T> {
public Selector<T> derive(String name) throws SyntaxException;
}

View File

@ -1,29 +1,30 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public interface SelectorOperator {
public <T> void process(Deque<Predicate<T>> stack);
public boolean matchesName(String name);
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.Deque;
import java.util.function.Predicate;
public interface SelectorOperator {
public <T> void process(Deque<Predicate<T>> stack);
public boolean matchesName(String name);
}

View File

@ -1,176 +1,175 @@
/*******************************************************************************
* JPUtil
* Copyright (C) 2019 Javapony/OLEGSHA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.jputil.selectors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.function.Predicate;
import ru.windcorp.jputil.SyntaxException;
import ru.windcorp.jputil.iterators.PeekingIterator;
public class SelectorSystem<T> {
public static final char EXPRESSION_OPEN = '(';
public static final char EXPRESSION_CLOSE = ')';
private final Collection<Selector<T>> selectors =
Collections.synchronizedCollection(new ArrayList<Selector<T>>());
private final Collection<SelectorOperator> operators =
Collections.synchronizedCollection(new ArrayList<SelectorOperator>());
private String stackPrefix = null;
public Collection<Selector<T>> getSelectors() {
return this.selectors;
}
public Collection<SelectorOperator> getSelectorOperators() {
return this.operators;
}
public String getStackPrefix() {
return stackPrefix;
}
public SelectorSystem<T> setStackPrefix(String stackPrefix) {
this.stackPrefix = stackPrefix;
return this;
}
public SelectorSystem<T> add(Selector<T> selector) {
getSelectors().add(selector);
return this;
}
public SelectorSystem<T> add(SelectorOperator operator) {
getSelectorOperators().add(operator);
return this;
}
public Predicate<T> parse(Iterator<String> tokens) throws SyntaxException {
PeekingIterator<String> peeker = new PeekingIterator<>(tokens);
if (getStackPrefix() != null && peeker.hasNext() && getStackPrefix().equals(peeker.peek())) {
peeker.next();
return parseStack(peeker);
}
Deque<Predicate<T>> stack = new LinkedList<>();
synchronized (getSelectorOperators()) {
synchronized (getSelectors()) {
while (peeker.hasNext()) {
parseToken(stack, peeker);
}
}
}
return compress(stack);
}
private void parseToken(Deque<Predicate<T>> stack, Iterator<String> tokens) throws SyntaxException {
if (!tokens.hasNext()) {
throw new SyntaxException("Not enough tokens");
}
String token = tokens.next();
for (SelectorOperator operator : getSelectorOperators()) {
if (operator.matchesName(token.toLowerCase())) {
parseToken(stack, tokens);
operator.process(stack);
return;
}
}
Selector<T> tmp;
for (Selector<T> selector : getSelectors()) {
if ((tmp = selector.derive(token)) != null) {
stack.push(tmp);
return;
}
}
throw new SyntaxException("Unknown token \"" + token + "\"");
}
public Predicate<T> parseStack(Iterator<String> tokens) throws SyntaxException {
Deque<Predicate<T>> stack = new LinkedList<>();
String token;
synchronized (getSelectorOperators()) {
synchronized (getSelectors()) {
tokenCycle:
while (tokens.hasNext()) {
token = tokens.next();
for (SelectorOperator operator : getSelectorOperators()) {
if (operator.matchesName(token.toLowerCase())) {
operator.process(stack);
continue tokenCycle;
}
}
for (Selector<T> selector : getSelectors()) {
Selector<T> tmp;
if ((tmp = selector.derive(token)) != null) {
stack.push(tmp);
continue tokenCycle;
}
}
throw new SyntaxException("Unknown token \"" + token + "\"");
}
}
}
return compress(stack);
}
private Predicate<T> compress(Deque<Predicate<T>> stack) throws SyntaxException {
if (stack.isEmpty()) {
throw new SyntaxException("Stack is empty");
}
if (stack.size() == 1) {
return stack.pop();
}
return obj -> {
for (Predicate<? super T> predicate : stack) {
if (predicate.test(obj)) {
return true;
}
}
return false;
};
}
}
/*
* JPUtil
* Copyright (C) 2019-2021 OLEGSHA/Javapony and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.jputil.selectors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.function.Predicate;
import ru.windcorp.jputil.SyntaxException;
import ru.windcorp.jputil.iterators.PeekingIterator;
public class SelectorSystem<T> {
public static final char EXPRESSION_OPEN = '(';
public static final char EXPRESSION_CLOSE = ')';
private final Collection<Selector<T>> selectors = Collections.synchronizedCollection(new ArrayList<Selector<T>>());
private final Collection<SelectorOperator> operators = Collections
.synchronizedCollection(new ArrayList<SelectorOperator>());
private String stackPrefix = null;
public Collection<Selector<T>> getSelectors() {
return this.selectors;
}
public Collection<SelectorOperator> getSelectorOperators() {
return this.operators;
}
public String getStackPrefix() {
return stackPrefix;
}
public SelectorSystem<T> setStackPrefix(String stackPrefix) {
this.stackPrefix = stackPrefix;
return this;
}
public SelectorSystem<T> add(Selector<T> selector) {
getSelectors().add(selector);
return this;
}
public SelectorSystem<T> add(SelectorOperator operator) {
getSelectorOperators().add(operator);
return this;
}
public Predicate<T> parse(Iterator<String> tokens) throws SyntaxException {
PeekingIterator<String> peeker = new PeekingIterator<>(tokens);
if (getStackPrefix() != null && peeker.hasNext() && getStackPrefix().equals(peeker.peek())) {
peeker.next();
return parseStack(peeker);
}
Deque<Predicate<T>> stack = new LinkedList<>();
synchronized (getSelectorOperators()) {
synchronized (getSelectors()) {
while (peeker.hasNext()) {
parseToken(stack, peeker);
}
}
}
return compress(stack);
}
private void parseToken(Deque<Predicate<T>> stack, Iterator<String> tokens) throws SyntaxException {
if (!tokens.hasNext()) {
throw new SyntaxException("Not enough tokens");
}
String token = tokens.next();
for (SelectorOperator operator : getSelectorOperators()) {
if (operator.matchesName(token.toLowerCase())) {
parseToken(stack, tokens);
operator.process(stack);
return;
}
}
Selector<T> tmp;
for (Selector<T> selector : getSelectors()) {
if ((tmp = selector.derive(token)) != null) {
stack.push(tmp);
return;
}
}
throw new SyntaxException("Unknown token \"" + token + "\"");
}
public Predicate<T> parseStack(Iterator<String> tokens) throws SyntaxException {
Deque<Predicate<T>> stack = new LinkedList<>();
String token;
synchronized (getSelectorOperators()) {
synchronized (getSelectors()) {
tokenCycle: while (tokens.hasNext()) {
token = tokens.next();
for (SelectorOperator operator : getSelectorOperators()) {
if (operator.matchesName(token.toLowerCase())) {
operator.process(stack);
continue tokenCycle;
}
}
for (Selector<T> selector : getSelectors()) {
Selector<T> tmp;
if ((tmp = selector.derive(token)) != null) {
stack.push(tmp);
continue tokenCycle;
}
}
throw new SyntaxException("Unknown token \"" + token + "\"");
}
}
}
return compress(stack);
}
private Predicate<T> compress(Deque<Predicate<T>> stack) throws SyntaxException {
if (stack.isEmpty()) {
throw new SyntaxException("Stack is empty");
}
if (stack.size() == 1) {
return stack.pop();
}
return obj -> {
for (Predicate<? super T> predicate : stack) {
if (predicate.test(obj)) {
return true;
}
}
return false;
};
}
}

View File

@ -1,22 +1,23 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* 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;
public class Progressia {
}
/*
* 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;
public class Progressia {
}

View File

@ -1,51 +1,52 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* 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;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer;
import ru.windcorp.progressia.common.util.crash.providers.*;
public class ProgressiaLauncher {
public static String[] arguments;
public static void launch(String[] args, Proxy proxy) {
arguments = args.clone();
setupCrashReports();
proxy.initialize();
}
private static void setupCrashReports() {
// Context providers
CrashReports.registerProvider(new OSContextProvider());
CrashReports.registerProvider(new RAMContextProvider());
CrashReports.registerProvider(new JavaVersionContextProvider());
CrashReports.registerProvider(new OpenALContextProvider());
CrashReports.registerProvider(new ArgsContextProvider());
CrashReports.registerProvider(new LanguageContextProvider());
CrashReports.registerProvider(new StackTraceProvider());
// Analyzers
CrashReports.registerAnalyzer(new OutOfMemoryAnalyzer());
Thread.setDefaultUncaughtExceptionHandler((Thread thread, Throwable t)-> {
CrashReports.crash(t, "Uncaught exception in thread %s", thread.getName());
});
}
}
/*
* 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;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer;
import ru.windcorp.progressia.common.util.crash.providers.*;
public class ProgressiaLauncher {
public static String[] arguments;
public static void launch(String[] args, Proxy proxy) {
arguments = args.clone();
setupCrashReports();
proxy.initialize();
}
private static void setupCrashReports() {
// Context providers
CrashReports.registerProvider(new OSContextProvider());
CrashReports.registerProvider(new RAMContextProvider());
CrashReports.registerProvider(new JavaVersionContextProvider());
CrashReports.registerProvider(new OpenALContextProvider());
CrashReports.registerProvider(new ArgsContextProvider());
CrashReports.registerProvider(new LanguageContextProvider());
CrashReports.registerProvider(new ScreenContextProvider());
// Analyzers
CrashReports.registerAnalyzer(new OutOfMemoryAnalyzer());
Thread.setDefaultUncaughtExceptionHandler((Thread thread, Throwable t) -> {
CrashReports.crash(t, "Uncaught exception in thread %s", thread.getName());
});
}
}

View File

@ -1,24 +1,25 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* 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;
public interface Proxy {
void initialize();
}
/*
* 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;
public interface Proxy {
void initialize();
}

View File

@ -1,59 +1,79 @@
package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.DefaultClientCommsListener;
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
import ru.windcorp.progressia.client.graphics.world.Camera;
import ru.windcorp.progressia.client.graphics.world.EntityAnchor;
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
import ru.windcorp.progressia.client.world.WorldRender;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.entity.EntityData;
public class Client {
private final WorldRender world;
private final LocalPlayer localPlayer = new LocalPlayer(this);
private final Camera camera = new Camera((float) Math.toRadians(70));
private final ServerCommsChannel comms;
public Client(WorldData world, ServerCommsChannel comms) {
this.world = new WorldRender(world, this);
this.comms = comms;
comms.addListener(new DefaultClientCommsListener(this));
}
public WorldRender getWorld() {
return world;
}
public LocalPlayer getLocalPlayer() {
return localPlayer;
}
public boolean isReady() {
return localPlayer.hasEntity();
}
public Camera getCamera() {
return camera;
}
public ServerCommsChannel getComms() {
return comms;
}
public void onLocalPlayerEntityChanged(EntityData entity, EntityData lastKnownEntity) {
if (entity == null) {
getCamera().setAnchor(null);
return;
}
getCamera().setAnchor(new EntityAnchor(
getWorld().getEntityRenderable(entity)
));
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.DefaultClientCommsListener;
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
import ru.windcorp.progressia.client.graphics.world.Camera;
import ru.windcorp.progressia.client.graphics.world.EntityAnchor;
import ru.windcorp.progressia.client.graphics.world.LocalPlayer;
import ru.windcorp.progressia.client.world.WorldRender;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.common.world.entity.EntityData;
public class Client {
private final WorldRender world;
private final LocalPlayer localPlayer = new LocalPlayer(this);
private final Camera camera = new Camera((float) Math.toRadians(70));
private final ServerCommsChannel comms;
public Client(WorldData world, ServerCommsChannel comms) {
this.world = new WorldRender(world, this);
this.comms = comms;
comms.addListener(new DefaultClientCommsListener(this));
}
public WorldRender getWorld() {
return world;
}
public LocalPlayer getLocalPlayer() {
return localPlayer;
}
public boolean isReady() {
return localPlayer.hasEntity();
}
public Camera getCamera() {
return camera;
}
public ServerCommsChannel getComms() {
return comms;
}
public void onLocalPlayerEntityChanged(EntityData entity, EntityData lastKnownEntity) {
if (entity == null) {
getCamera().setAnchor(null);
return;
}
getCamera().setAnchor(
new EntityAnchor(
getWorld().getEntityRenderable(entity)
)
);
}
}

View File

@ -1,54 +1,67 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client;
import ru.windcorp.progressia.Proxy;
import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend;
import ru.windcorp.progressia.client.graphics.backend.RenderTaskQueue;
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader;
import ru.windcorp.progressia.client.graphics.font.Typefaces;
import ru.windcorp.progressia.client.graphics.texture.Atlases;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.common.resource.ResourceManager;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.TestContent;
public class ClientProxy implements Proxy {
@Override
public void initialize() {
GraphicsBackend.initialize();
try {
RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init);
RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init);
RenderTaskQueue.waitAndInvoke(() -> Typefaces.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz"))));
} catch (InterruptedException e) {
throw CrashReports.report(e, "ClientProxy failed");
}
TestContent.registerContent();
Atlases.loadAllAtlases();
ServerState.startServer();
ClientState.connectToLocalServer();
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client;
import ru.windcorp.progressia.Proxy;
import ru.windcorp.progressia.client.audio.AudioSystem;
import ru.windcorp.progressia.client.graphics.backend.GraphicsBackend;
import ru.windcorp.progressia.client.graphics.backend.RenderTaskQueue;
import ru.windcorp.progressia.client.graphics.flat.FlatRenderProgram;
import ru.windcorp.progressia.client.graphics.font.GNUUnifontLoader;
import ru.windcorp.progressia.client.graphics.font.Typefaces;
import ru.windcorp.progressia.client.graphics.texture.Atlases;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
import ru.windcorp.progressia.client.localization.Localizer;
import ru.windcorp.progressia.common.resource.ResourceManager;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.TestContent;
import ru.windcorp.progressia.test.TestMusicPlayer;
public class ClientProxy implements Proxy {
@Override
public void initialize() {
GraphicsBackend.initialize();
try {
RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init);
RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init);
RenderTaskQueue.waitAndInvoke(
() -> Typefaces
.setDefault(GNUUnifontLoader.load(ResourceManager.getResource("assets/unifont-13.0.03.hex.gz")))
);
} catch (InterruptedException e) {
throw CrashReports.report(e, "ClientProxy failed");
}
Localizer.getInstance().setLanguage("en-US");
TestContent.registerContent();
Atlases.loadAllAtlases();
AudioSystem.initialize();
ServerState.startServer();
ClientState.connectToLocalServer();
TestMusicPlayer.start();
}
}

View File

@ -1,46 +1,65 @@
package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.LayerTestGUI;
import ru.windcorp.progressia.test.LayerTestUI;
import ru.windcorp.progressia.test.TestContent;
public class ClientState {
private static Client instance;
public static Client getInstance() {
return instance;
}
public static void setInstance(Client instance) {
ClientState.instance = instance;
}
public static void connectToLocalServer() {
WorldData world = new WorldData();
LocalServerCommsChannel channel = new LocalServerCommsChannel(
ServerState.getInstance()
);
Client client = new Client(world, channel);
channel.connect(TestContent.PLAYER_LOGIN);
setInstance(client);
GUI.addBottomLayer(new LayerWorld(client));
GUI.addTopLayer(new LayerTestUI());
GUI.addTopLayer(new LayerTestGUI());
}
private ClientState() {}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.world.LayerWorld;
import ru.windcorp.progressia.common.world.WorldData;
import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.LayerAbout;
import ru.windcorp.progressia.test.LayerTestUI;
import ru.windcorp.progressia.test.TestContent;
public class ClientState {
private static Client instance;
public static Client getInstance() {
return instance;
}
public static void setInstance(Client instance) {
ClientState.instance = instance;
}
public static void connectToLocalServer() {
WorldData world = new WorldData();
LocalServerCommsChannel channel = new LocalServerCommsChannel(
ServerState.getInstance()
);
Client client = new Client(world, channel);
channel.connect(TestContent.PLAYER_LOGIN);
setInstance(client);
GUI.addBottomLayer(new LayerWorld(client));
GUI.addTopLayer(new LayerTestUI());
GUI.addTopLayer(new LayerAbout());
}
private ClientState() {
}
}

View File

@ -1,28 +1,29 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client;
import ru.windcorp.progressia.ProgressiaLauncher;
public class ProgressiaClientMain {
public static void main(String[] args) {
ProgressiaLauncher.launch(args, new ClientProxy());
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client;
import ru.windcorp.progressia.ProgressiaLauncher;
public class ProgressiaClientMain {
public static void main(String[] args) {
ProgressiaLauncher.launch(args, new ClientProxy());
}
}

View File

@ -1,5 +1,23 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio;
public enum AudioFormat {
MONO, STEREO
MONO, STEREO
}

View File

@ -1,3 +1,21 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio;
import org.lwjgl.openal.*;
@ -5,6 +23,7 @@ import ru.windcorp.progressia.client.audio.backend.AudioReader;
import ru.windcorp.progressia.client.audio.backend.Listener;
import ru.windcorp.progressia.client.audio.backend.SoundType;
import ru.windcorp.progressia.client.audio.backend.Speaker;
import ru.windcorp.progressia.common.resource.Resource;
import static org.lwjgl.openal.AL11.*;
import static org.lwjgl.openal.ALC10.*;
@ -22,12 +41,11 @@ public class AudioManager {
private static List<Speaker> soundSpeakers = new ArrayList<>(SOUNDS_NUM);
private static Speaker musicSpeaker;
private static ArrayList<SoundType> soundsBuffer = new ArrayList<>();
public static void initAL() {
String defaultDeviceName = alcGetString(
0,
ALC_DEFAULT_DEVICE_SPECIFIER
0,
ALC_DEFAULT_DEVICE_SPECIFIER
);
device = alcOpenDevice(defaultDeviceName);
@ -57,37 +75,27 @@ public class AudioManager {
lastSoundIndex = 0;
}
speaker = soundSpeakers.get(lastSoundIndex);
} while (speaker.getState()
.equals(Speaker.State.PLAYING_LOOP));
} while (
speaker.getState()
.equals(Speaker.State.PLAYING_LOOP)
);
return speaker;
}
private static SoundType findSoundType(String soundID) throws Exception {
for (SoundType s : soundsBuffer) {
if (s.getId().equals(soundID)) {
return s;
}
}
throw new Exception("ERROR: The selected sound is not loaded or" +
" not exists");
}
public static Speaker initSpeaker(String soundID) {
public static Speaker initSpeaker(SoundType st) {
Speaker speaker = getLastSpeaker();
try {
findSoundType(soundID).initSpeaker(speaker);
} catch (Exception ex)
{
st.initSpeaker(speaker);
} catch (Exception ex) {
throw new RuntimeException();
}
return speaker;
}
public static Speaker initMusicSpeaker(String soundID) {
public static Speaker initMusicSpeaker(SoundType st) {
try {
findSoundType(soundID).initSpeaker(musicSpeaker);
} catch (Exception ex)
{
st.initSpeaker(musicSpeaker);
} catch (Exception ex) {
throw new RuntimeException();
}
return musicSpeaker;
@ -100,12 +108,11 @@ public class AudioManager {
}
}
public static void loadSound(String path, String id, AudioFormat format) {
public static void loadSound(Resource resource, String id, AudioFormat format) {
if (format == AudioFormat.MONO) {
soundsBuffer.add(AudioReader.readAsMono(path, id));
} else
{
soundsBuffer.add(AudioReader.readAsStereo(path, id));
AudioRegistry.getInstance().register(AudioReader.readAsMono(resource, id));
} else {
AudioRegistry.getInstance().register(AudioReader.readAsStereo(resource, id));
}
}
@ -128,8 +135,7 @@ public class AudioManager {
return deviceCapabilities;
}
public static void createBuffers()
{
public static void createBuffers() {
for (int i = 0; i < SOUNDS_NUM; ++i) {
soundSpeakers.add(new Speaker());
}
@ -141,4 +147,4 @@ public class AudioManager {
return alGetString(AL11.AL_VERSION);
}
}
}

View File

@ -0,0 +1,34 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio;
import ru.windcorp.progressia.client.audio.backend.SoundType;
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
public class AudioRegistry extends NamespacedInstanceRegistry<SoundType> {
private static final AudioRegistry INSTANCE = new AudioRegistry();
/**
* @return the instance
*/
public static AudioRegistry getInstance() {
return INSTANCE;
}
}

View File

@ -1,5 +1,25 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio;
import ru.windcorp.progressia.common.resource.ResourceManager;
public class AudioSystem {
static public void initialize() {
AudioManager.initAL();
@ -9,8 +29,10 @@ public class AudioSystem {
}
static void loadAudioData() {
AudioManager.loadSound("assets/sounds/block_destroy_clap.ogg",
"Progressia:BlockDestroy",
AudioFormat.MONO);
AudioManager.loadSound(
ResourceManager.getResource("assets/sounds/block_destroy_clap.ogg"),
"Progressia:BlockDestroy",
AudioFormat.MONO
);
}
}
}

View File

@ -1,70 +1,55 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio;
import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.audio.backend.SoundType;
import ru.windcorp.progressia.client.audio.backend.Speaker;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
public class Music extends Namespaced {
private Vec3 position = new Vec3();
private Vec3 velocity = new Vec3();
private float pitch = 1.0f;
private float gain = 1.0f;
public class Music
extends Sound {
public Music(SoundType soundType, int timeLength, float pitch, float gain) {
super(soundType, timeLength, new Vec3(), new Vec3(), pitch, gain);
}
public Music(SoundType soundType) {
super(soundType);
}
public Music(String id)
{
super(id);
}
public Music(String id, int timeLength, float pitch, float gain) {
super(id, timeLength, new Vec3(), new Vec3(), pitch, gain);
}
public Music(String id,
Vec3 position,
Vec3 velocity,
float pitch,
float gain)
{
this(id);
this.position = position;
this.velocity = velocity;
this.pitch = pitch;
this.gain = gain;
}
public Music(String id) {
super(id);
}
public void play(boolean loop)
{
Speaker speaker = AudioManager.initMusicSpeaker(this.getId());
speaker.setGain(gain);
speaker.setPitch(pitch);
speaker.setPosition(position);
speaker.setVelocity(velocity);
if (loop) {
speaker.playLoop();
} else {
speaker.play();
}
}
public void setGain(float gain) {
this.gain = gain;
}
public void setPitch(float pitch) { this.pitch = pitch; }
public void setVelocity(Vec3 velocity) {
this.velocity = velocity;
}
public Vec3 getPosition() { return position; }
public float getGain() {
return gain;
}
public Vec3 getVelocity() {
return velocity;
}
public float getPitch() {
return pitch;
}
@Override
protected Speaker initSpeaker() {
return AudioManager.initMusicSpeaker(soundType);
}
@Override
public void setPosition(Vec3 position) {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,127 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio;
import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.audio.backend.SoundType;
import ru.windcorp.progressia.client.audio.backend.Speaker;
public class Sound {
protected Vec3 position = new Vec3(0f, 0f, 0f);
protected Vec3 velocity = new Vec3(0f, 0f, 0f);
protected float pitch = 1.0f;
protected float gain = 1.0f;
protected int timeLength = 0;
protected SoundType soundType;
public Sound(SoundType soundType) {
this.soundType = soundType;
}
public Sound(String id) {
this(AudioRegistry.getInstance().get(id));
}
public Sound(
String id,
int timeLength,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
this(id);
this.position = position;
this.velocity = velocity;
this.pitch = pitch;
this.gain = gain;
}
public Sound(
SoundType soundType,
int timeLength,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
this(soundType);
this.position = position;
this.velocity = velocity;
this.pitch = pitch;
this.gain = gain;
}
protected Speaker initSpeaker() {
return AudioManager.initSpeaker(soundType);
}
public void play(boolean loop) {
Speaker speaker = initSpeaker();
speaker.setGain(gain);
speaker.setPitch(pitch);
speaker.setPosition(position);
speaker.setVelocity(velocity);
if (loop) {
speaker.playLoop();
} else {
speaker.play();
}
}
public void setGain(float gain) {
this.gain = gain;
}
public void setPitch(float pitch) {
this.pitch = pitch;
}
public void setPosition(Vec3 position) {
this.position = position;
}
public void setVelocity(Vec3 velocity) {
this.velocity = velocity;
}
public Vec3 getPosition() {
return position;
}
public float getGain() {
return gain;
}
public Vec3 getVelocity() {
return velocity;
}
public float getPitch() {
return pitch;
}
public double getDuration() {
return soundType.getDuration();
}
}

View File

@ -1,78 +0,0 @@
package ru.windcorp.progressia.client.audio;
import glm.vec._3.Vec3;
import ru.windcorp.progressia.client.audio.backend.Speaker;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
public class SoundEffect
extends Namespaced {
private Vec3 position = new Vec3();
private Vec3 velocity = new Vec3();
private float pitch = 1.0f;
private float gain = 1.0f;
public SoundEffect(String id)
{
super(id);
}
public SoundEffect(String id,
Vec3 position,
Vec3 velocity,
float pitch,
float gain)
{
this(id);
this.position = position;
this.velocity = velocity;
this.pitch = pitch;
this.gain = gain;
}
public void play(boolean loop)
{
Speaker speaker = AudioManager.initSpeaker(this.getId());
speaker.setGain(gain);
speaker.setPitch(pitch);
speaker.setPosition(position);
speaker.setVelocity(velocity);
if (loop) {
speaker.playLoop();
} else {
speaker.play();
}
}
public void setGain(float gain) {
this.gain = gain;
}
public void setPitch(float pitch) { this.pitch = pitch; }
public void setPosition(Vec3 position) {
this.position = position;
}
public void setVelocity(Vec3 velocity) {
this.velocity = velocity;
}
public Vec3 getPosition() {
return position;
}
public float getGain() {
return gain;
}
public Vec3 getVelocity() {
return velocity;
}
public float getPitch() {
return pitch;
}
}

View File

@ -1,3 +1,21 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio.backend;
import org.lwjgl.BufferUtils;
@ -11,38 +29,41 @@ import static org.lwjgl.openal.AL10.*;
public class AudioReader {
private AudioReader() {}
private AudioReader() {
}
// TODO fix converting from mono-stereo
private static SoundType readAsSpecified(String path, String id, int format) {
private static SoundType readAsSpecified(Resource resource, String id, int format) {
IntBuffer channelBuffer = BufferUtils.createIntBuffer(1);
IntBuffer rateBuffer = BufferUtils.createIntBuffer(1);
Resource res = ResourceManager.getResource(path);
ShortBuffer rawAudio = decodeVorbis(resource, channelBuffer, rateBuffer);
ShortBuffer rawAudio = decodeVorbis(res, channelBuffer, rateBuffer);
return new SoundType(id, rawAudio, format,
rateBuffer.get(0));
return new SoundType(
id,
rawAudio,
format,
rateBuffer.get(0)
);
}
public static SoundType readAsMono(String path, String id) {
return readAsSpecified(path, id, AL_FORMAT_MONO16);
public static SoundType readAsMono(Resource resource, String id) {
return readAsSpecified(resource, id, AL_FORMAT_MONO16);
}
public static SoundType readAsStereo(String path,String id) {
return readAsSpecified(path, id, AL_FORMAT_STEREO16);
public static SoundType readAsStereo(Resource resource, String id) {
return readAsSpecified(resource, id, AL_FORMAT_STEREO16);
}
private static ShortBuffer decodeVorbis(
Resource dataToDecode,
IntBuffer channelsBuffer,
IntBuffer rateBuffer
Resource dataToDecode,
IntBuffer channelsBuffer,
IntBuffer rateBuffer
) {
return stb_vorbis_decode_memory(
dataToDecode.readAsBytes(),
channelsBuffer,
rateBuffer
dataToDecode.readAsBytes(),
channelsBuffer,
rateBuffer
);
}
}

View File

@ -1,3 +1,21 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio.backend;
import glm.vec._3.Vec3;
@ -12,7 +30,8 @@ public class Listener {
private static final Listener INSTANCE = new Listener();
private Listener() {}
private Listener() {
}
public static Listener getInstance() {
return INSTANCE;
@ -37,7 +56,7 @@ public class Listener {
if (wasInWorld) {
velocity.set(camera.getLastAnchorPosition()).sub(position).div(
(float) GraphicsInterface.getFrameLength()
(float) GraphicsInterface.getFrameLength()
);
} else {
// If !wasInWorld, previous position is nonsence. Assume 0.
@ -72,9 +91,17 @@ public class Listener {
private void applyParams() {
alListener3f(AL_POSITION, position.x, position.y, position.z);
alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);
alListenerfv(AL_ORIENTATION, new float[] {
oriAt.x, oriAt.y, oriAt.z, oriUp.x, oriUp.y, oriUp.z
});
alListenerfv(
AL_ORIENTATION,
new float[] {
oriAt.x,
oriAt.y,
oriAt.z,
oriUp.x,
oriUp.y,
oriUp.z
}
);
}
}

View File

@ -1,8 +1,29 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio.backend;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
import java.nio.ShortBuffer;
import org.lwjgl.openal.AL10;
import static org.lwjgl.openal.AL11.*;
public class SoundType extends Namespaced {
@ -11,9 +32,14 @@ public class SoundType extends Namespaced {
private int sampleRate;
private int format;
private int audioBuffer;
private double duration;
public SoundType(String id, ShortBuffer rawAudio,
int format, int sampleRate) {
public SoundType(
String id,
ShortBuffer rawAudio,
int format,
int sampleRate
) {
super(id);
this.rawAudio = rawAudio;
this.sampleRate = sampleRate;
@ -24,9 +50,14 @@ public class SoundType extends Namespaced {
private void createAudioBuffer() {
this.audioBuffer = alGenBuffers();
alBufferData(audioBuffer, format, rawAudio, sampleRate);
duration = rawAudio.limit() / (double) sampleRate / (format == AL10.AL_FORMAT_STEREO16 ? 2 : 1);
}
public void initSpeaker(Speaker speaker) {
speaker.setAudioData(audioBuffer);
}
}
public double getDuration() {
return duration;
}
}

View File

@ -1,3 +1,21 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.audio.backend;
import glm.vec._3.Vec3;
@ -5,147 +23,146 @@ import static org.lwjgl.openal.AL11.*;
public class Speaker {
public enum State {
NOT_PLAYING,
PLAYING,
PLAYING_LOOP
}
public enum State {
NOT_PLAYING,
PLAYING,
PLAYING_LOOP
}
// Buffers
private int audioData;
private int sourceData;
// Buffers
private int audioData;
private int sourceData;
// Characteristics
private Vec3 position = new Vec3();
private Vec3 velocity = new Vec3();
private float pitch = 1.0f;
private float gain = 1.0f;
private State state = State.NOT_PLAYING;
// Characteristics
private Vec3 position = new Vec3();
private Vec3 velocity = new Vec3();
private float pitch = 1.0f;
private float gain = 1.0f;
private State state = State.NOT_PLAYING;
public Speaker() {
sourceData = alGenSources();
}
public Speaker() {
sourceData = alGenSources();
}
public Speaker(int audioData) {
this();
setAudioData(audioData);
}
public Speaker(int audioData) {
this();
setAudioData(audioData);
}
public Speaker(
int audioData,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
setAudioData(audioData);
setPosition(position);
setVelocity(velocity);
setPitch(pitch);
setGain(gain);
}
public Speaker(
int audioData,
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
setAudioData(audioData);
setPosition(position);
setVelocity(velocity);
setPitch(pitch);
setGain(gain);
}
public Speaker(
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
setPosition(position);
setVelocity(velocity);
setPitch(pitch);
setGain(gain);
}
public Speaker(
Vec3 position,
Vec3 velocity,
float pitch,
float gain
) {
setPosition(position);
setVelocity(velocity);
setPitch(pitch);
setGain(gain);
}
public void play() {
alSourcePlay(sourceData);
state = State.PLAYING;
}
public void play() {
alSourcePlay(sourceData);
state = State.PLAYING;
}
public void playLoop() {
alSourcei(sourceData, AL_LOOPING, AL_TRUE);
alSourcePlay(sourceData);
state = State.PLAYING_LOOP;
}
public void playLoop() {
alSourcei(sourceData, AL_LOOPING, AL_TRUE);
alSourcePlay(sourceData);
state = State.PLAYING_LOOP;
}
public void stop() {
alSourceStop(sourceData);
if (state == State.PLAYING_LOOP) {
alSourcei(sourceData, AL_LOOPING, AL_FALSE);
}
state = State.NOT_PLAYING;
}
public void stop() {
alSourceStop(sourceData);
if (state == State.PLAYING_LOOP) {
alSourcei(sourceData, AL_LOOPING, AL_FALSE);
}
state = State.NOT_PLAYING;
}
public void pause() {
alSourcePause(sourceData);
state = State.NOT_PLAYING;
}
public void pause() {
alSourcePause(sourceData);
state = State.NOT_PLAYING;
}
public boolean isPlaying() {
final int speakerState = alGetSourcei(sourceData, AL_SOURCE_STATE);
if (speakerState == AL_PLAYING) {
return true;
}
else {
state = State.NOT_PLAYING;
return false;
}
}
public boolean isPlaying() {
final int speakerState = alGetSourcei(sourceData, AL_SOURCE_STATE);
if (speakerState == AL_PLAYING) {
return true;
} else {
state = State.NOT_PLAYING;
return false;
}
}
// GETTERS & SETTERS
// GETTERS & SETTERS
public int getAudioData() {
return audioData;
}
public int getAudioData() {
return audioData;
}
public int getSourceData() {
return sourceData;
}
public int getSourceData() {
return sourceData;
}
public void setAudioData(int audioData) {
this.audioData = audioData;
alSourcei(this.sourceData, AL_BUFFER, audioData);
}
public void setAudioData(int audioData) {
stop();
this.audioData = audioData;
alSourcei(this.sourceData, AL_BUFFER, audioData);
}
public void setPosition(Vec3 position) {
this.position = position;
alSource3f(sourceData, AL_POSITION, position.x, position.y, position.z);
}
public void setPosition(Vec3 position) {
this.position = position;
alSource3f(sourceData, AL_POSITION, position.x, position.y, position.z);
}
public Vec3 getPosition() {
return position;
}
public Vec3 getPosition() {
return position;
}
public void setVelocity(Vec3 velocity) {
alSource3f(sourceData, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
this.velocity = velocity;
}
public void setVelocity(Vec3 velocity) {
alSource3f(sourceData, AL_VELOCITY, velocity.x, velocity.y, velocity.z);
this.velocity = velocity;
}
public Vec3 getVelocity() {
return velocity;
}
public Vec3 getVelocity() {
return velocity;
}
public void setPitch(float pitch) {
alSourcef(sourceData, AL_PITCH, pitch);
this.pitch = pitch;
}
public void setPitch(float pitch) {
alSourcef(sourceData, AL_PITCH, pitch);
this.pitch = pitch;
}
public float getPitch() {
return pitch;
}
public float getPitch() {
return pitch;
}
public void setGain(float gain) {
alSourcef(sourceData, AL_GAIN, gain);
this.gain = gain;
}
public void setGain(float gain) {
alSourcef(sourceData, AL_GAIN, gain);
this.gain = gain;
}
public float getGain() {
return gain;
}
public float getGain() {
return gain;
}
public State getState()
{
return state;
}
public State getState() {
return state;
}
}
}

View File

@ -1,46 +1,64 @@
package ru.windcorp.progressia.client.comms;
import java.io.IOException;
import ru.windcorp.progressia.client.Client;
import ru.windcorp.progressia.common.comms.CommsListener;
import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.PacketSetLocalPlayer;
import ru.windcorp.progressia.common.world.PacketAffectWorld;
// TODO refactor with no mercy
public class DefaultClientCommsListener implements CommsListener {
private final Client client;
public DefaultClientCommsListener(Client client) {
this.client = client;
}
@Override
public void onPacketReceived(Packet packet) {
if (packet instanceof PacketAffectWorld) {
((PacketAffectWorld) packet).apply(
getClient().getWorld().getData()
);
} else if (packet instanceof PacketSetLocalPlayer) {
setLocalPlayer((PacketSetLocalPlayer) packet);
}
}
private void setLocalPlayer(PacketSetLocalPlayer packet) {
getClient().getLocalPlayer().setEntityId(packet.getEntityId());
}
@Override
public void onIOError(IOException reason) {
throw CrashReports.report(reason, "An IOException has occurred in communications");
// TODO implement
}
public Client getClient() {
return client;
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms;
import java.io.IOException;
import ru.windcorp.progressia.client.Client;
import ru.windcorp.progressia.common.comms.CommsListener;
import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.PacketSetLocalPlayer;
import ru.windcorp.progressia.common.world.PacketAffectWorld;
// TODO refactor with no mercy
public class DefaultClientCommsListener implements CommsListener {
private final Client client;
public DefaultClientCommsListener(Client client) {
this.client = client;
}
@Override
public void onPacketReceived(Packet packet) {
if (packet instanceof PacketAffectWorld) {
((PacketAffectWorld) packet).apply(
getClient().getWorld().getData()
);
} else if (packet instanceof PacketSetLocalPlayer) {
setLocalPlayer((PacketSetLocalPlayer) packet);
}
}
private void setLocalPlayer(PacketSetLocalPlayer packet) {
getClient().getLocalPlayer().setEntityId(packet.getEntityId());
}
@Override
public void onIOError(IOException reason) {
throw CrashReports.report(reason, "An IOException has occurred in communications");
// TODO implement
}
public Client getClient() {
return client;
}
}

View File

@ -1,7 +1,25 @@
package ru.windcorp.progressia.client.comms;
import ru.windcorp.progressia.common.comms.CommsChannel;
public abstract class ServerCommsChannel extends CommsChannel {
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms;
import ru.windcorp.progressia.common.comms.CommsChannel;
public abstract class ServerCommsChannel extends CommsChannel {
}

View File

@ -1,11 +1,29 @@
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
public abstract class ControlTrigger extends Namespaced {
public ControlTrigger(String id) {
super(id);
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.common.util.namespaces.Namespaced;
public abstract class ControlTrigger extends Namespaced {
public ControlTrigger(String id) {
super(id);
}
}

View File

@ -1,14 +1,32 @@
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.common.comms.controls.PacketControl;
public abstract class ControlTriggerInputBased extends ControlTrigger {
public ControlTriggerInputBased(String id) {
super(id);
}
public abstract PacketControl onInputEvent(InputEvent event);
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.common.comms.controls.PacketControl;
public abstract class ControlTriggerInputBased extends ControlTrigger {
public ControlTriggerInputBased(String id) {
super(id);
}
public abstract PacketControl onInputEvent(InputEvent event);
}

View File

@ -1,48 +1,67 @@
package ru.windcorp.progressia.client.comms.controls;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.common.comms.controls.ControlData;
import ru.windcorp.progressia.common.comms.controls.ControlDataRegistry;
import ru.windcorp.progressia.common.comms.controls.PacketControl;
import ru.windcorp.progressia.common.util.namespaces.NamespacedUtil;
public class ControlTriggerLambda extends ControlTriggerInputBased {
private final String packetId;
private final Predicate<InputEvent> predicate;
private final BiConsumer<InputEvent, ControlData> dataWriter;
public ControlTriggerLambda(
String id,
Predicate<InputEvent> predicate,
BiConsumer<InputEvent, ControlData> dataWriter
) {
super(id);
this.packetId = NamespacedUtil.getId(
NamespacedUtil.getNamespace(id),
"ControlKeyPress" + NamespacedUtil.getName(id)
);
this.predicate = predicate;
this.dataWriter = dataWriter;
}
@Override
public PacketControl onInputEvent(InputEvent event) {
if (!predicate.test(event)) return null;
PacketControl packet = new PacketControl(
packetId,
ControlDataRegistry.getInstance().create(getId())
);
dataWriter.accept(event, packet.getControl());
return packet;
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.controls;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.common.comms.controls.ControlData;
import ru.windcorp.progressia.common.comms.controls.ControlDataRegistry;
import ru.windcorp.progressia.common.comms.controls.PacketControl;
import ru.windcorp.progressia.common.util.namespaces.NamespacedUtil;
public class ControlTriggerLambda extends ControlTriggerInputBased {
private final String packetId;
private final Predicate<InputEvent> predicate;
private final BiConsumer<InputEvent, ControlData> dataWriter;
public ControlTriggerLambda(
String id,
Predicate<InputEvent> predicate,
BiConsumer<InputEvent, ControlData> dataWriter
) {
super(id);
this.packetId = NamespacedUtil.getId(
NamespacedUtil.getNamespace(id),
"ControlKeyPress" + NamespacedUtil.getName(id)
);
this.predicate = predicate;
this.dataWriter = dataWriter;
}
@Override
public PacketControl onInputEvent(InputEvent event) {
if (!predicate.test(event))
return null;
PacketControl packet = new PacketControl(
packetId,
ControlDataRegistry.getInstance().create(getId())
);
dataWriter.accept(event, packet.getControl());
return packet;
}
}

View File

@ -0,0 +1,53 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.controls;
import java.util.function.Consumer;
import java.util.function.Predicate;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.common.comms.controls.PacketControl;
public class ControlTriggerLocalLambda extends ControlTriggerInputBased {
private final Predicate<InputEvent> predicate;
private final Consumer<InputEvent> action;
public ControlTriggerLocalLambda(
String id,
Predicate<InputEvent> predicate,
Consumer<InputEvent> action
) {
super(id);
this.predicate = predicate;
this.action = action;
}
@Override
public PacketControl onInputEvent(InputEvent event) {
if (!predicate.test(event))
return null;
action.accept(event);
return null;
}
}

View File

@ -1,14 +1,31 @@
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
public class ControlTriggerRegistry extends NamespacedInstanceRegistry<ControlTrigger> {
private static final ControlTriggerRegistry INSTANCE =
new ControlTriggerRegistry();
public static ControlTriggerRegistry getInstance() {
return INSTANCE;
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.common.util.namespaces.NamespacedInstanceRegistry;
public class ControlTriggerRegistry extends NamespacedInstanceRegistry<ControlTrigger> {
private static final ControlTriggerRegistry INSTANCE = new ControlTriggerRegistry();
public static ControlTriggerRegistry getInstance() {
return INSTANCE;
}
}

View File

@ -1,3 +1,21 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.controls;
import java.util.function.BiConsumer;
@ -8,145 +26,239 @@ import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.common.comms.controls.ControlData;
public class ControlTriggers {
public static ControlTriggerInputBased of(
String id,
BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent> predicate
String id,
BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent> predicate
) {
return new ControlTriggerLambda(id, predicate, dataWriter);
}
public static ControlTriggerInputBased of(
String id,
Consumer<ControlData> dataWriter,
Predicate<InputEvent> predicate
String id,
Consumer<ControlData> dataWriter,
Predicate<InputEvent> predicate
) {
return of(
id,
(input, control) -> dataWriter.accept(control),
predicate
);
}
public static ControlTriggerInputBased of(
String id,
Predicate<InputEvent> predicate
) {
return of(
id,
(input, control) -> {},
predicate
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
BiConsumer<I, ControlData> dataWriter,
Predicate<I>... predicates
) {
return of(
id,
createCheckedDataWriter(inputType, dataWriter),
createCheckedCompoundPredicate(inputType, predicates)
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
Consumer<ControlData> dataWriter,
Predicate<I>... predicates
) {
return of(
id,
inputType,
(input, control) -> dataWriter.accept(control),
predicates
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
Predicate<I>... predicates
) {
return of(
id,
(input, control) -> {},
createCheckedCompoundPredicate(inputType, predicates)
);
}
@SafeVarargs
public static ControlTriggerInputBased of(
String id,
BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent>... predicates
) {
return of(
id,
InputEvent.class,
dataWriter,
predicates
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Consumer<ControlData> dataWriter,
Predicate<InputEvent>... predicates
) {
return of(
id,
(input, control) -> dataWriter.accept(control),
predicates
);
}
@SafeVarargs
public static ControlTriggerInputBased of(
String id,
Predicate<InputEvent>... predicates
) {
return of(
id,
InputEvent.class,
(input, control) -> {},
predicates
id,
(input, control) -> dataWriter.accept(control),
predicate
);
}
private static
<I extends InputEvent>
BiConsumer<InputEvent, ControlData>
createCheckedDataWriter(
Class<I> inputType,
BiConsumer<I, ControlData> dataWriter
public static ControlTriggerInputBased of(
String id,
Predicate<InputEvent> predicate
) {
return of(
id,
(input, control) -> {
},
predicate
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
BiConsumer<I, ControlData> dataWriter,
Predicate<I>... predicates
) {
return of(
id,
createCheckedDataWriter(inputType, dataWriter),
createCheckedCompoundPredicate(inputType, predicates)
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
Consumer<ControlData> dataWriter,
Predicate<I>... predicates
) {
return of(
id,
inputType,
(input, control) -> dataWriter.accept(control),
predicates
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Class<I> inputType,
Predicate<I>... predicates
) {
return of(
id,
(input, control) -> {
},
createCheckedCompoundPredicate(inputType, predicates)
);
}
@SafeVarargs
public static ControlTriggerInputBased of(
String id,
BiConsumer<InputEvent, ControlData> dataWriter,
Predicate<InputEvent>... predicates
) {
return of(
id,
InputEvent.class,
dataWriter,
predicates
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased of(
String id,
Consumer<ControlData> dataWriter,
Predicate<InputEvent>... predicates
) {
return of(
id,
(input, control) -> dataWriter.accept(control),
predicates
);
}
@SafeVarargs
public static ControlTriggerInputBased of(
String id,
Predicate<InputEvent>... predicates
) {
return of(
id,
InputEvent.class,
(input, control) -> {
},
predicates
);
}
//
//
///
///
//
//
//
//
//
//
//
//
//
public static ControlTriggerInputBased localOf(
String id,
Consumer<InputEvent> action,
Predicate<InputEvent> predicate
) {
return new ControlTriggerLocalLambda(id, predicate, action);
}
public static ControlTriggerInputBased localOf(
String id,
Runnable action,
Predicate<InputEvent> predicate
) {
return localOf(
id,
input -> action.run(),
predicate
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(
String id,
Class<I> inputType,
Consumer<I> action,
Predicate<I>... predicates
) {
return localOf(
id,
createCheckedAction(inputType, action),
createCheckedCompoundPredicate(inputType, predicates)
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(
String id,
Class<I> inputType,
Runnable action,
Predicate<I>... predicates
) {
return localOf(
id,
inputType,
input -> action.run(),
predicates
);
}
@SafeVarargs
public static ControlTriggerInputBased localOf(
String id,
Consumer<InputEvent> action,
Predicate<InputEvent>... predicates
) {
return localOf(
id,
InputEvent.class,
action,
predicates
);
}
@SafeVarargs
public static <I extends InputEvent> ControlTriggerInputBased localOf(
String id,
Runnable action,
Predicate<InputEvent>... predicates
) {
return of(
id,
input -> action.run(),
predicates
);
}
private static <I extends InputEvent> BiConsumer<InputEvent, ControlData> createCheckedDataWriter(
Class<I> inputType,
BiConsumer<I, ControlData> dataWriter
) {
return (inputEvent, control) -> dataWriter.accept(inputType.cast(inputEvent), control);
}
private static
<I extends InputEvent>
Predicate<InputEvent>
createCheckedCompoundPredicate(
Class<I> inputType,
Predicate<I>[] predicates
private static <I extends InputEvent> Consumer<InputEvent> createCheckedAction(
Class<I> inputType,
Consumer<I> action
) {
return inputEvent -> action.accept(inputType.cast(inputEvent));
}
private static <I extends InputEvent> Predicate<InputEvent> createCheckedCompoundPredicate(
Class<I> inputType,
Predicate<I>[] predicates
) {
return new CompoundCastPredicate<>(inputType, predicates);
}
private static class CompoundCastPredicate<I extends InputEvent> implements Predicate<InputEvent> {
private final Class<I> inputType;
private final Predicate<I>[] predicates;
public CompoundCastPredicate(Class<I> inputType, Predicate<I>[] predicates) {
this.inputType = inputType;
this.predicates = predicates;
@ -157,20 +269,21 @@ public class ControlTriggers {
if (!inputType.isInstance(inputEvent)) {
return false;
}
I castEvent = inputType.cast(inputEvent);
for (Predicate<I> predicate : predicates) {
if (!predicate.test(castEvent)) {
return false;
}
}
return true;
}
}
private ControlTriggers() {}
private ControlTriggers() {
}
}

View File

@ -1,33 +1,51 @@
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.client.Client;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
import ru.windcorp.progressia.common.comms.packets.Packet;
public class InputBasedControls {
private final Client client;
private final ControlTriggerInputBased[] controls;
public InputBasedControls(Client client) {
this.client = client;
this.controls = ControlTriggerRegistry.getInstance().values().stream()
.filter(ControlTriggerInputBased.class::isInstance)
.toArray(ControlTriggerInputBased[]::new);
}
public void handleInput(Input input) {
for (ControlTriggerInputBased c : controls) {
Packet packet = c.onInputEvent(input.getEvent());
if (packet != null) {
input.consume();
client.getComms().sendPacket(packet);
break;
}
}
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.controls;
import ru.windcorp.progressia.client.Client;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
import ru.windcorp.progressia.common.comms.packets.Packet;
public class InputBasedControls {
private final Client client;
private final ControlTriggerInputBased[] controls;
public InputBasedControls(Client client) {
this.client = client;
this.controls = ControlTriggerRegistry.getInstance().values().stream()
.filter(ControlTriggerInputBased.class::isInstance)
.toArray(ControlTriggerInputBased[]::new);
}
public void handleInput(Input input) {
for (ControlTriggerInputBased c : controls) {
Packet packet = c.onInputEvent(input.getEvent());
if (packet != null) {
input.consume();
client.getComms().sendPacket(packet);
break;
}
}
}
}

View File

@ -1,41 +1,59 @@
package ru.windcorp.progressia.client.comms.localhost;
import java.io.IOException;
import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.server.comms.ClientPlayer;
public class LocalClient extends ClientPlayer {
private final LocalServerCommsChannel serverComms;
private final String login;
public LocalClient(int id, String login, LocalServerCommsChannel serverComms) {
super(id);
setState(State.CONNECTED);
this.serverComms = serverComms;
this.login = login;
}
@Override
public String getLogin() {
return this.login;
}
@Override
protected void doSendPacket(Packet packet) throws IOException {
this.serverComms.relayPacketToClient(packet);
}
public void relayPacketToServer(Packet packet) {
onPacketReceived(packet);
}
@Override
public void disconnect() {
// Do nothing
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.localhost;
import java.io.IOException;
import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.server.comms.ClientPlayer;
public class LocalClient extends ClientPlayer {
private final LocalServerCommsChannel serverComms;
private final String login;
public LocalClient(int id, String login, LocalServerCommsChannel serverComms) {
super(id);
setState(State.CONNECTED);
this.serverComms = serverComms;
this.login = login;
}
@Override
public String getLogin() {
return this.login;
}
@Override
protected void doSendPacket(Packet packet) throws IOException {
this.serverComms.relayPacketToClient(packet);
}
public void relayPacketToServer(Packet packet) {
onPacketReceived(packet);
}
@Override
public void disconnect() {
// Do nothing
}
}

View File

@ -1,42 +1,60 @@
package ru.windcorp.progressia.client.comms.localhost;
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.server.Server;
public class LocalServerCommsChannel extends ServerCommsChannel {
private LocalClient localClient;
private final Server server;
public LocalServerCommsChannel(Server server) {
this.server = server;
}
public void connect(String login) {
setState(State.CONNECTED);
this.localClient = new LocalClient(
server.getClientManager().grabClientId(),
login,
this
);
server.getClientManager().addClient(localClient);
}
@Override
protected void doSendPacket(Packet packet) {
localClient.relayPacketToServer(packet);
}
public void relayPacketToClient(Packet packet) {
onPacketReceived(packet);
}
@Override
public void disconnect() {
// Do nothing
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.comms.localhost;
import ru.windcorp.progressia.client.comms.ServerCommsChannel;
import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.server.Server;
public class LocalServerCommsChannel extends ServerCommsChannel {
private LocalClient localClient;
private final Server server;
public LocalServerCommsChannel(Server server) {
this.server = server;
}
public void connect(String login) {
setState(State.CONNECTED);
this.localClient = new LocalClient(
server.getClientManager().grabClientId(),
login,
this
);
server.getClientManager().addClient(localClient);
}
@Override
protected void doSendPacket(Packet packet) {
localClient.relayPacketToServer(packet);
}
public void relayPacketToClient(Packet packet) {
onPacketReceived(packet);
}
@Override
public void disconnect() {
// Do nothing
}
}

View File

@ -1,61 +1,62 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client.graphics;
import glm.vec._4.Vec4;
public class Colors {
public static final Vec4
WHITE = toVector(0xFFFFFFFF),
BLACK = toVector(0xFF000000),
GRAY_4 = toVector(0xFF444444),
GRAY = toVector(0xFF888888),
GRAY_A = toVector(0xFFAAAAAA),
DEBUG_RED = toVector(0xFFFF0000),
DEBUG_GREEN = toVector(0xFF00FF00),
DEBUG_BLUE = toVector(0xFF0000FF),
DEBUG_CYAN = toVector(0xFF00FFFF),
DEBUG_MAGENTA = toVector(0xFFFF00FF),
DEBUG_YELLOW = toVector(0xFFFFFF00);
public static Vec4 toVector(int argb) {
return toVector(argb, new Vec4());
}
public static Vec4 multiplyRGB(Vec4 color, float multiplier) {
return color.mul(multiplier, multiplier, multiplier, 1);
}
public static Vec4 multiplyRGB(Vec4 color, float multiplier, Vec4 output) {
if (output == null) output = new Vec4();
return color.mul(multiplier, multiplier, multiplier, 1, output);
}
public static Vec4 toVector(int argb, Vec4 output) {
output.w = ((argb & 0xFF000000) >>> 24) / 256f; // Alpha
output.x = ((argb & 0x00FF0000) >>> 16) / 256f; // Red
output.y = ((argb & 0x0000FF00) >>> 8) / 256f; // Green
output.z = ((argb & 0x000000FF) ) / 256f; // Blue
return output;
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics;
import glm.vec._4.Vec4;
public class Colors {
public static final Vec4 WHITE = toVector(0xFFFFFFFF),
BLACK = toVector(0xFF000000),
GRAY_4 = toVector(0xFF444444),
GRAY = toVector(0xFF888888),
GRAY_A = toVector(0xFFAAAAAA),
DEBUG_RED = toVector(0xFFFF0000),
DEBUG_GREEN = toVector(0xFF00FF00),
DEBUG_BLUE = toVector(0xFF0000FF),
DEBUG_CYAN = toVector(0xFF00FFFF),
DEBUG_MAGENTA = toVector(0xFFFF00FF),
DEBUG_YELLOW = toVector(0xFFFFFF00);
public static Vec4 toVector(int argb) {
return toVector(argb, new Vec4());
}
public static Vec4 multiplyRGB(Vec4 color, float multiplier) {
return color.mul(multiplier, multiplier, multiplier, 1);
}
public static Vec4 multiplyRGB(Vec4 color, float multiplier, Vec4 output) {
if (output == null)
output = new Vec4();
return color.mul(multiplier, multiplier, multiplier, 1, output);
}
public static Vec4 toVector(int argb, Vec4 output) {
output.w = ((argb & 0xFF000000) >>> 24) / (float) 0xFF; // Alpha
output.x = ((argb & 0x00FF0000) >>> 16) / (float) 0xFF; // Red
output.y = ((argb & 0x0000FF00) >>> 8) / (float) 0xFF; // Green
output.z = ((argb & 0x000000FF)) / (float) 0xFF; // Blue
return output;
}
}

View File

@ -1,108 +1,133 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client.graphics;
import java.util.ArrayList;
import java.util.List;
import com.google.common.eventbus.Subscribe;
import ru.windcorp.progressia.client.graphics.input.CursorEvent;
import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.WheelEvent;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
public class GUI {
private static final List<Layer> LAYERS = new ArrayList<>();
private static class ModifiableInput extends Input {
@Override
public void initialize(InputEvent event, Target target) {
super.initialize(event, target);
}
}
private static final ModifiableInput THE_INPUT = new ModifiableInput();
private GUI() {}
public synchronized static void addBottomLayer(Layer layer) {
LAYERS.add(layer);
}
public synchronized static void addTopLayer(Layer layer) {
LAYERS.add(0, layer);
}
public synchronized static void removeLayer(Layer layer) {
LAYERS.remove(layer);
}
public synchronized static void render() {
for (int i = LAYERS.size() - 1; i >= 0; --i) {
LAYERS.get(i).render();
}
}
public static void invalidateEverything() {
LAYERS.forEach(Layer::invalidate);
}
private static void dispatchInputEvent(InputEvent event) {
Input.Target target;
if (event instanceof KeyEvent) {
if (((KeyEvent) event).isMouse()) {
target = Input.Target.HOVERED;
} else {
target = Input.Target.FOCUSED;
}
} else if (event instanceof CursorEvent) {
target = Input.Target.HOVERED;
} else if (event instanceof WheelEvent) {
target = Input.Target.HOVERED;
} else if (event instanceof FrameResizeEvent) {
return;
} else {
target = Input.Target.ALL;
}
THE_INPUT.initialize(event, target);
LAYERS.forEach(l -> l.handleInput(THE_INPUT));
}
public static Object getEventSubscriber() {
return new Object() {
@Subscribe
public void onFrameResized(FrameResizeEvent event) {
GUI.invalidateEverything();
}
@Subscribe
public void onInput(InputEvent event) {
dispatchInputEvent(event);
}
};
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.common.eventbus.Subscribe;
import ru.windcorp.progressia.client.graphics.input.CursorEvent;
import ru.windcorp.progressia.client.graphics.input.FrameResizeEvent;
import ru.windcorp.progressia.client.graphics.input.InputEvent;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
import ru.windcorp.progressia.client.graphics.input.WheelEvent;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
public class GUI {
private static final List<Layer> LAYERS = Collections.synchronizedList(new ArrayList<>());
private static final List<Layer> UNMODIFIABLE_LAYERS = Collections.unmodifiableList(LAYERS);
@FunctionalInterface
private interface LayerStackModification {
void affect(List<Layer> layers);
}
private static final List<LayerStackModification> MODIFICATION_QUEUE = Collections
.synchronizedList(new ArrayList<>());
private static class ModifiableInput extends Input {
@Override
public void initialize(InputEvent event, Target target) {
super.initialize(event, target);
}
}
private static final ModifiableInput THE_INPUT = new ModifiableInput();
private GUI() {
}
public static void addBottomLayer(Layer layer) {
modify(layers -> layers.add(layer));
}
public static void addTopLayer(Layer layer) {
modify(layers -> layers.add(0, layer));
}
public static void removeLayer(Layer layer) {
modify(layers -> layers.remove(layer));
}
private static void modify(LayerStackModification mod) {
MODIFICATION_QUEUE.add(mod);
}
public static List<Layer> getLayers() {
return UNMODIFIABLE_LAYERS;
}
public static void render() {
synchronized (LAYERS) {
MODIFICATION_QUEUE.forEach(action -> action.affect(LAYERS));
MODIFICATION_QUEUE.clear();
for (int i = LAYERS.size() - 1; i >= 0; --i) {
LAYERS.get(i).render();
}
}
}
public static void invalidateEverything() {
LAYERS.forEach(Layer::invalidate);
}
private static void dispatchInputEvent(InputEvent event) {
Input.Target target;
if (event instanceof KeyEvent) {
if (((KeyEvent) event).isMouse()) {
target = Input.Target.HOVERED;
} else {
target = Input.Target.FOCUSED;
}
} else if (event instanceof CursorEvent) {
target = Input.Target.HOVERED;
} else if (event instanceof WheelEvent) {
target = Input.Target.HOVERED;
} else if (event instanceof FrameResizeEvent) {
return;
} else {
target = Input.Target.ALL;
}
THE_INPUT.initialize(event, target);
LAYERS.forEach(l -> l.handleInput(THE_INPUT));
}
public static Object getEventSubscriber() {
return new Object() {
@Subscribe
public void onFrameResized(FrameResizeEvent event) {
GUI.invalidateEverything();
}
@Subscribe
public void onInput(InputEvent event) {
dispatchInputEvent(event);
}
};
}
}

View File

@ -1,81 +1,82 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client.graphics;
import java.util.concurrent.atomic.AtomicBoolean;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
public abstract class Layer {
private final String name;
private boolean hasInitialized = false;
private final AtomicBoolean isValid = new AtomicBoolean(false);
public Layer(String name) {
this.name = name;
}
@Override
public String toString() {
return "Layer " + name;
}
void render() {
GraphicsInterface.startNextLayer();
validate();
if (!hasInitialized) {
initialize();
hasInitialized = true;
}
doRender();
}
void validate() {
if (isValid.compareAndSet(false, true)) {
doValidate();
}
}
public void invalidate() {
isValid.set(false);
}
protected abstract void initialize();
protected abstract void doValidate();
protected abstract void doRender();
protected abstract void handleInput(Input input);
protected int getWidth() {
return GraphicsInterface.getFrameWidth();
}
protected int getHeight() {
return GraphicsInterface.getFrameHeight();
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics;
import java.util.concurrent.atomic.AtomicBoolean;
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.input.bus.Input;
public abstract class Layer {
private final String name;
private boolean hasInitialized = false;
private final AtomicBoolean isValid = new AtomicBoolean(false);
public Layer(String name) {
this.name = name;
}
@Override
public String toString() {
return "Layer " + name;
}
void render() {
GraphicsInterface.startNextLayer();
validate();
if (!hasInitialized) {
initialize();
hasInitialized = true;
}
doRender();
}
void validate() {
if (isValid.compareAndSet(false, true)) {
doValidate();
}
}
public void invalidate() {
isValid.set(false);
}
protected abstract void initialize();
protected abstract void doValidate();
protected abstract void doRender();
protected abstract void handleInput(Input input);
protected int getWidth() {
return GraphicsInterface.getFrameWidth();
}
protected int getHeight() {
return GraphicsInterface.getFrameHeight();
}
}

View File

@ -1,27 +1,46 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.backend;
import java.util.ArrayDeque;
import java.util.Deque;
public class FaceCulling {
private static final Deque<Boolean> STACK = new ArrayDeque<>();
public static void push(boolean useFaceCulling) {
GraphicsBackend.setFaceCulling(useFaceCulling);
STACK.push(Boolean.valueOf(useFaceCulling));
}
public static void pop() {
STACK.pop();
if (STACK.isEmpty()) {
GraphicsBackend.setFaceCulling(false);
} else {
GraphicsBackend.setFaceCulling(STACK.getFirst());
}
}
private FaceCulling() {}
private FaceCulling() {
}
}

View File

@ -1,127 +1,195 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client.graphics.backend;
import static org.lwjgl.opengl.GL11.*;
import glm.vec._2.i.Vec2i;
import static org.lwjgl.glfw.GLFW.*;
public class GraphicsBackend {
private static RenderThread renderThread;
private static long windowHandle;
private static final Vec2i FRAME_SIZE = new Vec2i();
private static double frameLength = 1.0 / 60; // TODO do something about it
private static long framesRendered = 0;
private static double frameStart = Double.NaN;
private static boolean faceCullingEnabled = false;
private GraphicsBackend() {}
public static void initialize() {
startRenderThread();
}
private static void startRenderThread() {
renderThread = new RenderThread();
renderThread.start();
}
public static Thread getRenderThread() {
return renderThread;
}
static void setWindowHandle(long windowHandle) {
GraphicsBackend.windowHandle = windowHandle;
}
public static long getWindowHandle() {
return windowHandle;
}
public static int getFrameWidth() {
return FRAME_SIZE.x;
}
public static int getFrameHeight() {
return FRAME_SIZE.y;
}
public static Vec2i getFrameSize() {
return FRAME_SIZE;
}
static void onFrameResized(long window, int newWidth, int newHeight) {
if (window != windowHandle) return;
InputHandler.handleFrameResize(newWidth, newHeight);
FRAME_SIZE.set(newWidth, newHeight);
glViewport(0, 0, newWidth, newHeight);
}
static void startFrame() {
double now = glfwGetTime();
if (Double.isNaN(frameStart)) {
frameStart = now;
} else {
frameLength = now - frameStart;
frameStart = now;
}
}
static void endFrame() {
framesRendered++;
}
public static double getFrameStart() {
return frameStart;
}
public static double getFrameLength() {
return frameLength;
}
public static long getFramesRendered() {
return framesRendered;
}
public static void startNextLayer() {
glClear(GL_DEPTH_BUFFER_BIT);
}
public static void setFaceCulling(boolean useFaceCulling) {
if (useFaceCulling == faceCullingEnabled) return;
if (useFaceCulling) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
faceCullingEnabled = useFaceCulling;
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.backend;
import glm.vec._2.i.Vec2i;
import org.lwjgl.glfw.GLFWVidMode;
import static org.lwjgl.glfw.GLFW.*;
import static org.lwjgl.opengl.GL11.*;
public class GraphicsBackend {
private static RenderThread renderThread;
private static long windowHandle;
private static final Vec2i FRAME_SIZE = new Vec2i();
private static double frameLength = 1.0 / 60; // TODO do something about it
private static long framesRendered = 0;
private static double frameStart = Double.NaN;
private static boolean faceCullingEnabled = false;
private static boolean isFullscreen = false;
private static boolean vSyncEnabled = false;
private static boolean isGLFWInitialized = false;
private static boolean isOpenGLInitialized = false;
private GraphicsBackend() {
}
public static boolean isGLFWInitialized() {
return isGLFWInitialized;
}
static void setGLFWInitialized(boolean isGLFWInitialized) {
GraphicsBackend.isGLFWInitialized = isGLFWInitialized;
}
public static boolean isOpenGLInitialized() {
return isOpenGLInitialized;
}
static void setOpenGLInitialized(boolean isOpenGLInitialized) {
GraphicsBackend.isOpenGLInitialized = isOpenGLInitialized;
}
public static void initialize() {
startRenderThread();
}
private static void startRenderThread() {
renderThread = new RenderThread();
renderThread.start();
}
public static Thread getRenderThread() {
return renderThread;
}
static void setWindowHandle(long windowHandle) {
GraphicsBackend.windowHandle = windowHandle;
}
public static long getWindowHandle() {
return windowHandle;
}
public static int getFrameWidth() {
return FRAME_SIZE.x;
}
public static int getFrameHeight() {
return FRAME_SIZE.y;
}
public static Vec2i getFrameSize() {
return FRAME_SIZE;
}
static void onFrameResized(long window, int newWidth, int newHeight) {
if (window != windowHandle)
return;
InputHandler.handleFrameResize(newWidth, newHeight);
FRAME_SIZE.set(newWidth, newHeight);
glViewport(0, 0, newWidth, newHeight);
}
static void startFrame() {
double now = glfwGetTime();
if (Double.isNaN(frameStart)) {
frameStart = now;
} else {
frameLength = now - frameStart;
frameStart = now;
}
}
static void endFrame() {
framesRendered++;
}
public static double getFrameStart() {
return frameStart;
}
public static double getFrameLength() {
return frameLength;
}
public static long getFramesRendered() {
return framesRendered;
}
public static void startNextLayer() {
glClear(GL_DEPTH_BUFFER_BIT);
}
public static void setFaceCulling(boolean useFaceCulling) {
if (useFaceCulling == faceCullingEnabled)
return;
if (useFaceCulling) {
glEnable(GL_CULL_FACE);
} else {
glDisable(GL_CULL_FACE);
}
faceCullingEnabled = useFaceCulling;
}
public static boolean isFullscreen() {
return isFullscreen;
}
public static boolean isVSyncEnabled() {
return vSyncEnabled;
}
public static void setFullscreen() {
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowMonitor(
getWindowHandle(),
glfwGetPrimaryMonitor(),
0,
0,
vidmode.width(),
vidmode.height(),
0);
isFullscreen = true;
}
public static void setWindowed() {
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glfwSetWindowMonitor(
getWindowHandle(),
0,
(vidmode.width() - getFrameWidth()) / 2,
(vidmode.height() - getFrameHeight()) / 2,
getFrameWidth(),
getFrameHeight(),
0);
isFullscreen = false;
}
public static void setVSyncEnabled(boolean enable) {
glfwSwapInterval(enable ? 1 : 0);
vSyncEnabled = enable;
}
public static int getRefreshRate() {
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
return vidmode.refreshRate();
}
}

View File

@ -1,74 +1,85 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client.graphics.backend;
import glm.vec._2.i.Vec2i;
public class GraphicsInterface {
private GraphicsInterface() {}
public static Thread getRenderThread() {
return GraphicsBackend.getRenderThread();
}
public static boolean isRenderThread() {
return Thread.currentThread() == getRenderThread();
}
public static int getFrameWidth() {
return GraphicsBackend.getFrameWidth();
}
public static int getFrameHeight() {
return GraphicsBackend.getFrameHeight();
}
public static Vec2i getFrameSize() {
return GraphicsBackend.getFrameSize();
}
public static float getAspectRatio() {
return ((float) getFrameWidth()) / getFrameHeight();
}
public static double getTime() {
return GraphicsBackend.getFrameStart();
}
public static double getFrameLength() {
return GraphicsBackend.getFrameLength();
}
public static double getFPS() {
return 1 / GraphicsBackend.getFrameLength();
}
public static long getFramesRendered() {
return GraphicsBackend.getFramesRendered();
}
public static void subscribeToInputEvents(Object listener) {
InputHandler.register(listener);
}
public static void startNextLayer() {
GraphicsBackend.startNextLayer();
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.backend;
import glm.vec._2.i.Vec2i;
public class GraphicsInterface {
private GraphicsInterface() {
}
public static Thread getRenderThread() {
return GraphicsBackend.getRenderThread();
}
public static boolean isRenderThread() {
return Thread.currentThread() == getRenderThread();
}
public static int getFrameWidth() {
return GraphicsBackend.getFrameWidth();
}
public static int getFrameHeight() {
return GraphicsBackend.getFrameHeight();
}
public static Vec2i getFrameSize() {
return GraphicsBackend.getFrameSize();
}
public static float getAspectRatio() {
return ((float) getFrameWidth()) / getFrameHeight();
}
public static double getTime() {
return GraphicsBackend.getFrameStart();
}
public static double getFrameLength() {
return GraphicsBackend.getFrameLength();
}
public static double getFPS() {
return 1 / GraphicsBackend.getFrameLength();
}
public static long getFramesRendered() {
return GraphicsBackend.getFramesRendered();
}
public static void subscribeToInputEvents(Object listener) {
InputHandler.register(listener);
}
public static void startNextLayer() {
GraphicsBackend.startNextLayer();
}
public static void makeFullscreen(boolean state) {
if (state) {
GraphicsBackend.setFullscreen();
} else {
GraphicsBackend.setWindowed();
}
GraphicsBackend.setVSyncEnabled(GraphicsBackend.isVSyncEnabled());
}
}

View File

@ -1,182 +1,183 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client.graphics.backend;
import org.lwjgl.glfw.GLFW;
import com.google.common.eventbus.EventBus;
import ru.windcorp.progressia.client.graphics.input.*;
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
public class InputHandler {
private static final EventBus INPUT_EVENT_BUS = ReportingEventBus.create("Input");
// KeyEvent
private static class ModifiableKeyEvent extends KeyEvent {
protected ModifiableKeyEvent() {
super(0, 0, 0, 0, Double.NaN);
}
public void initialize(int key, int scancode, int action, int mods) {
this.setTime(GraphicsInterface.getTime());
this.key = key;
this.scancode = scancode;
this.action = action;
this.mods = mods;
}
}
private static final ModifiableKeyEvent THE_KEY_EVENT =
new ModifiableKeyEvent();
static void handleKeyInput(
long window,
int key,
int scancode,
int action,
int mods
) {
if (GraphicsBackend.getWindowHandle() != window) return;
THE_KEY_EVENT.initialize(key, scancode, action, mods);
dispatch(THE_KEY_EVENT);
switch (action) {
case GLFW.GLFW_PRESS:
InputTracker.setKeyState(key, true);
break;
case GLFW.GLFW_RELEASE:
InputTracker.setKeyState(key, false);
break;
}
}
static void handleMouseButtonInput(
long window,
int key,
int action,
int mods
) {
handleKeyInput(window, key, Integer.MAX_VALUE - key, action, mods);
}
// CursorMoveEvent
private static class ModifiableCursorMoveEvent extends CursorMoveEvent {
protected ModifiableCursorMoveEvent() {
super(0, 0, Double.NaN);
}
public void initialize(double x, double y) {
this.setTime(GraphicsInterface.getTime());
getNewPosition().set(x, y);
}
}
private static final ModifiableCursorMoveEvent THE_CURSOR_MOVE_EVENT =
new ModifiableCursorMoveEvent();
static void handleMouseMoveInput(
long window,
double x, double y
) {
if (GraphicsBackend.getWindowHandle() != window) return;
y = GraphicsInterface.getFrameHeight() - y; // Flip y axis
InputTracker.initializeCursorPosition(x, y);
THE_CURSOR_MOVE_EVENT.initialize(x, y);
dispatch(THE_CURSOR_MOVE_EVENT);
InputTracker.getCursorPosition().set(x, y);
}
// ScrollEvent
private static class ModifiableWheelScrollEvent extends WheelScrollEvent {
public ModifiableWheelScrollEvent() {
super(0, 0, Double.NaN);
}
public void initialize(double xOffset, double yOffset) {
this.setTime(GraphicsInterface.getTime());
this.getOffset().set(xOffset, yOffset);
}
}
private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT =
new ModifiableWheelScrollEvent();
static void handleWheelScroll(
long window,
double xoffset,
double yoffset
) {
if (GraphicsBackend.getWindowHandle() != window) return;
THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset);
dispatch(THE_WHEEL_SCROLL_EVENT);
}
// FrameResizeEvent
private static class ModifiableFrameResizeEvent extends FrameResizeEvent {
public ModifiableFrameResizeEvent() {
super(0, 0, Double.NaN);
}
public void initialize(int width, int height) {
this.setTime(GraphicsInterface.getTime());
this.getNewSize().set(width, height);
}
}
private static final ModifiableFrameResizeEvent THE_FRAME_RESIZE_EVENT =
new ModifiableFrameResizeEvent();
/*
* NB: this is NOT a GLFW callback, the raw callback is in GraphicsBackend
*/
static void handleFrameResize(
int width,
int height
) {
THE_FRAME_RESIZE_EVENT.initialize(width, height);
dispatch(THE_FRAME_RESIZE_EVENT);
}
// Misc
private static void dispatch(InputEvent event) {
INPUT_EVENT_BUS.post(event);
}
public static void register(Object listener) {
INPUT_EVENT_BUS.register(listener);
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.backend;
import org.lwjgl.glfw.GLFW;
import com.google.common.eventbus.EventBus;
import ru.windcorp.progressia.client.graphics.input.*;
import ru.windcorp.progressia.common.util.crash.ReportingEventBus;
public class InputHandler {
private static final EventBus INPUT_EVENT_BUS = ReportingEventBus.create("Input");
// KeyEvent
private static class ModifiableKeyEvent extends KeyEvent {
protected ModifiableKeyEvent() {
super(0, 0, 0, 0, Double.NaN);
}
public void initialize(int key, int scancode, int action, int mods) {
this.setTime(GraphicsInterface.getTime());
this.key = key;
this.scancode = scancode;
this.action = action;
this.mods = mods;
}
}
private static final ModifiableKeyEvent THE_KEY_EVENT = new ModifiableKeyEvent();
static void handleKeyInput(
long window,
int key,
int scancode,
int action,
int mods
) {
if (GraphicsBackend.getWindowHandle() != window)
return;
THE_KEY_EVENT.initialize(key, scancode, action, mods);
dispatch(THE_KEY_EVENT);
switch (action) {
case GLFW.GLFW_PRESS:
InputTracker.setKeyState(key, true);
break;
case GLFW.GLFW_RELEASE:
InputTracker.setKeyState(key, false);
break;
}
}
static void handleMouseButtonInput(
long window,
int key,
int action,
int mods
) {
handleKeyInput(window, key, Integer.MAX_VALUE - key, action, mods);
}
// CursorMoveEvent
private static class ModifiableCursorMoveEvent extends CursorMoveEvent {
protected ModifiableCursorMoveEvent() {
super(0, 0, Double.NaN);
}
public void initialize(double x, double y) {
this.setTime(GraphicsInterface.getTime());
getNewPosition().set(x, y);
}
}
private static final ModifiableCursorMoveEvent THE_CURSOR_MOVE_EVENT = new ModifiableCursorMoveEvent();
static void handleMouseMoveInput(
long window,
double x,
double y
) {
if (GraphicsBackend.getWindowHandle() != window)
return;
y = GraphicsInterface.getFrameHeight() - y; // Flip y axis
InputTracker.initializeCursorPosition(x, y);
THE_CURSOR_MOVE_EVENT.initialize(x, y);
dispatch(THE_CURSOR_MOVE_EVENT);
InputTracker.getCursorPosition().set(x, y);
}
// ScrollEvent
private static class ModifiableWheelScrollEvent extends WheelScrollEvent {
public ModifiableWheelScrollEvent() {
super(0, 0, Double.NaN);
}
public void initialize(double xOffset, double yOffset) {
this.setTime(GraphicsInterface.getTime());
this.getOffset().set(xOffset, yOffset);
}
}
private static final ModifiableWheelScrollEvent THE_WHEEL_SCROLL_EVENT = new ModifiableWheelScrollEvent();
static void handleWheelScroll(
long window,
double xoffset,
double yoffset
) {
if (GraphicsBackend.getWindowHandle() != window)
return;
THE_WHEEL_SCROLL_EVENT.initialize(xoffset, yoffset);
dispatch(THE_WHEEL_SCROLL_EVENT);
}
// FrameResizeEvent
private static class ModifiableFrameResizeEvent extends FrameResizeEvent {
public ModifiableFrameResizeEvent() {
super(0, 0, Double.NaN);
}
public void initialize(int width, int height) {
this.setTime(GraphicsInterface.getTime());
this.getNewSize().set(width, height);
}
}
private static final ModifiableFrameResizeEvent THE_FRAME_RESIZE_EVENT = new ModifiableFrameResizeEvent();
/*
* NB: this is NOT a GLFW callback, the raw callback is in GraphicsBackend
*/
static void handleFrameResize(
int width,
int height
) {
THE_FRAME_RESIZE_EVENT.initialize(width, height);
dispatch(THE_FRAME_RESIZE_EVENT);
}
// Misc
private static void dispatch(InputEvent event) {
INPUT_EVENT_BUS.post(event);
}
public static void register(Object listener) {
INPUT_EVENT_BUS.register(listener);
}
}

View File

@ -1,72 +1,75 @@
/*******************************************************************************
* Progressia
* Copyright (C) 2020 Wind Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/
package ru.windcorp.progressia.client.graphics.backend;
import glm.vec._2.d.Vec2d;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.TIntHashSet;
public class InputTracker {
private static final Vec2d CURSOR_POSITION = new Vec2d(
Double.NaN, Double.NaN
);
private static final TIntSet PRESSED_KEYS = new TIntHashSet(256);
private InputTracker() {}
public static double getCursorX() {
return CURSOR_POSITION.x;
}
public static double getCursorY() {
return CURSOR_POSITION.y;
}
public static Vec2d getCursorPosition() {
return CURSOR_POSITION;
}
static void initializeCursorPosition(double x, double y) {
if (Double.isNaN(CURSOR_POSITION.x)) {
CURSOR_POSITION.set(x, y);
}
}
public static boolean isKeyPressed(int glfwCode) {
return PRESSED_KEYS.contains(glfwCode);
}
static void setKeyState(int glfwCode, boolean isPressed) {
if (isPressed) {
PRESSED_KEYS.add(glfwCode);
} else {
PRESSED_KEYS.remove(glfwCode);
}
}
public static TIntSet getPressedKeys() {
return PRESSED_KEYS;
}
static void releaseEverything() {
PRESSED_KEYS.clear();
}
}
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.client.graphics.backend;
import glm.vec._2.d.Vec2d;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.TIntHashSet;
public class InputTracker {
private static final Vec2d CURSOR_POSITION = new Vec2d(
Double.NaN,
Double.NaN
);
private static final TIntSet PRESSED_KEYS = new TIntHashSet(256);
private InputTracker() {
}
public static double getCursorX() {
return CURSOR_POSITION.x;
}
public static double getCursorY() {
return CURSOR_POSITION.y;
}
public static Vec2d getCursorPosition() {
return CURSOR_POSITION;
}
static void initializeCursorPosition(double x, double y) {
if (Double.isNaN(CURSOR_POSITION.x)) {
CURSOR_POSITION.set(x, y);
}
}
public static boolean isKeyPressed(int glfwCode) {
return PRESSED_KEYS.contains(glfwCode);
}
static void setKeyState(int glfwCode, boolean isPressed) {
if (isPressed) {
PRESSED_KEYS.add(glfwCode);
} else {
PRESSED_KEYS.remove(glfwCode);
}
}
public static TIntSet getPressedKeys() {
return PRESSED_KEYS;
}
static void releaseEverything() {
PRESSED_KEYS.clear();
}
}

Some files were not shown because too many files have changed in this diff Show More