2019-11-02 17:23:48 +01:00
/ *
* This file is part of BlueMap , licensed under the MIT License ( MIT ) .
*
* Copyright ( c ) Blue ( Lukas Rieger ) < https : //bluecolored.de>
* Copyright ( c ) contributors
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
* /
package de.bluecolored.bluemap.cli ;
2023-11-18 13:50:13 +01:00
import de.bluecolored.bluemap.common.BlueMapConfiguration ;
2021-04-24 22:11:26 +02:00
import de.bluecolored.bluemap.common.BlueMapService ;
import de.bluecolored.bluemap.common.MissingResourcesException ;
2023-11-18 13:50:13 +01:00
import de.bluecolored.bluemap.common.config.BlueMapConfigManager ;
2022-04-20 22:54:27 +02:00
import de.bluecolored.bluemap.common.config.ConfigurationException ;
2023-07-01 09:44:19 +02:00
import de.bluecolored.bluemap.common.config.CoreConfig ;
2022-04-20 22:54:27 +02:00
import de.bluecolored.bluemap.common.config.WebserverConfig ;
2021-05-02 14:51:42 +02:00
import de.bluecolored.bluemap.common.plugin.RegionFileWatchService ;
2022-06-27 01:13:48 +02:00
import de.bluecolored.bluemap.common.rendermanager.MapUpdateTask ;
import de.bluecolored.bluemap.common.rendermanager.RenderManager ;
import de.bluecolored.bluemap.common.rendermanager.RenderTask ;
2023-02-22 16:19:34 +01:00
import de.bluecolored.bluemap.common.web.* ;
import de.bluecolored.bluemap.common.web.http.HttpRequestHandler ;
2023-02-24 13:55:21 +01:00
import de.bluecolored.bluemap.common.web.http.HttpServer ;
2023-04-30 11:10:42 +02:00
import de.bluecolored.bluemap.core.BlueMap ;
2020-08-25 15:07:42 +02:00
import de.bluecolored.bluemap.core.MinecraftVersion ;
2019-11-02 17:23:48 +01:00
import de.bluecolored.bluemap.core.logger.Logger ;
2021-05-02 14:51:42 +02:00
import de.bluecolored.bluemap.core.map.BmMap ;
2020-09-04 11:41:36 +02:00
import de.bluecolored.bluemap.core.metrics.Metrics ;
2022-08-03 12:54:03 +02:00
import de.bluecolored.bluemap.core.storage.Storage ;
2022-10-14 10:24:19 +02:00
import de.bluecolored.bluemap.core.util.FileHelper ;
2021-03-28 18:56:26 +02:00
import org.apache.commons.cli.* ;
2021-05-02 14:51:42 +02:00
import org.apache.commons.lang3.time.DurationFormatUtils ;
2024-01-23 19:35:25 +01:00
import org.checkerframework.checker.nullness.qual.Nullable ;
2021-03-28 18:56:26 +02:00
2021-04-24 22:11:26 +02:00
import java.io.File ;
import java.io.IOException ;
2023-06-08 23:12:20 +02:00
import java.net.BindException ;
2023-02-22 16:19:34 +01:00
import java.net.InetSocketAddress ;
2023-06-08 23:12:20 +02:00
import java.net.UnknownHostException ;
2022-04-20 22:54:27 +02:00
import java.nio.file.Path ;
2023-06-29 13:37:31 +02:00
import java.time.Instant ;
import java.time.ZoneId ;
import java.time.ZonedDateTime ;
2021-05-02 14:51:42 +02:00
import java.util.* ;
import java.util.concurrent.TimeUnit ;
2024-01-23 19:35:25 +01:00
import java.util.function.Predicate ;
2022-06-27 01:13:48 +02:00
import java.util.regex.Pattern ;
2019-11-02 17:23:48 +01:00
2024-02-01 23:01:42 +01:00
public class BlueMapCLI {
2022-04-20 22:54:27 +02:00
private MinecraftVersion minecraftVersion = MinecraftVersion . LATEST_SUPPORTED ;
2024-02-01 23:01:42 +01:00
private Path configFolder = Path . of ( " config " ) ;
2021-09-19 22:15:50 +02:00
2024-01-23 19:35:25 +01:00
public void renderMaps ( BlueMapService blueMap , boolean watch , boolean forceRender , boolean forceGenerateWebapp ,
@Nullable String mapsToRender ) throws ConfigurationException , IOException , InterruptedException {
2021-09-19 22:15:50 +02:00
//metrics report
2023-11-18 13:50:13 +01:00
if ( blueMap . getConfig ( ) . getCoreConfig ( ) . isMetrics ( ) ) Metrics . sendReportAsync ( " cli " ) ;
2021-09-19 22:15:50 +02:00
2023-11-18 13:50:13 +01:00
if ( blueMap . getConfig ( ) . getWebappConfig ( ) . isEnabled ( ) )
2022-12-13 16:54:31 +01:00
blueMap . createOrUpdateWebApp ( forceGenerateWebapp ) ;
2021-09-19 22:15:50 +02:00
//try load resources
2024-02-01 23:01:42 +01:00
blueMap . getOrLoadResourcePack ( ) ;
2021-09-19 22:15:50 +02:00
//create renderManager
RenderManager renderManager = new RenderManager ( ) ;
//load maps
2024-01-23 19:35:25 +01:00
Predicate < String > mapFilter = mapId - > true ;
if ( mapsToRender ! = null ) {
Set < String > mapsToRenderSet = Set . of ( mapsToRender . split ( " , " ) ) ;
mapFilter = mapsToRenderSet : : contains ;
}
2024-02-01 23:01:42 +01:00
Map < String , BmMap > maps = blueMap . getOrLoadMaps ( mapFilter ) ;
2021-09-19 22:15:50 +02:00
//watcher
List < RegionFileWatchService > regionFileWatchServices = new ArrayList < > ( ) ;
if ( watch ) {
for ( BmMap map : maps . values ( ) ) {
try {
RegionFileWatchService watcher = new RegionFileWatchService ( renderManager , map , true ) ;
watcher . start ( ) ;
regionFileWatchServices . add ( watcher ) ;
} catch ( IOException ex ) {
Logger . global . logError ( " Failed to create file-watcher for map: " + map . getId ( ) +
" (This map might not automatically update) " , ex ) ;
}
}
}
//update all maps
int totalRegions = 0 ;
for ( BmMap map : maps . values ( ) ) {
MapUpdateTask updateTask = new MapUpdateTask ( map , forceRender ) ;
renderManager . scheduleRenderTask ( updateTask ) ;
totalRegions + = updateTask . getRegions ( ) . size ( ) ;
}
Logger . global . logInfo ( " Start updating " + maps . size ( ) + " maps ( " + totalRegions + " regions, ~ " + totalRegions * 1024L + " chunks)... " ) ;
// start rendering
2023-11-18 13:50:13 +01:00
renderManager . start ( blueMap . getConfig ( ) . getCoreConfig ( ) . resolveRenderThreadCount ( ) ) ;
2021-09-19 22:15:50 +02:00
Timer timer = new Timer ( " BlueMap-CLI-Timer " , true ) ;
TimerTask updateInfoTask = new TimerTask ( ) {
@Override
public void run ( ) {
RenderTask task = renderManager . getCurrentRenderTask ( ) ;
if ( task = = null ) return ;
double progress = task . estimateProgress ( ) ;
long etaMs = renderManager . estimateCurrentRenderTaskTimeRemaining ( ) ;
String eta = " " ;
if ( etaMs > 0 ) {
String etrDurationString = DurationFormatUtils . formatDuration ( etaMs , " HH:mm:ss " ) ;
eta = " (ETA: " + etrDurationString + " ) " ;
}
Logger . global . logInfo ( task . getDescription ( ) + " : " + ( Math . round ( progress * 100000 ) / 1000 . 0 ) + " % " + eta ) ;
}
} ;
timer . scheduleAtFixedRate ( updateInfoTask , TimeUnit . SECONDS . toMillis ( 10 ) , TimeUnit . SECONDS . toMillis ( 10 ) ) ;
TimerTask saveTask = new TimerTask ( ) {
@Override
public void run ( ) {
for ( BmMap map : maps . values ( ) ) {
map . save ( ) ;
}
}
} ;
timer . scheduleAtFixedRate ( saveTask , TimeUnit . MINUTES . toMillis ( 2 ) , TimeUnit . MINUTES . toMillis ( 2 ) ) ;
Runnable shutdown = ( ) - > {
Logger . global . logInfo ( " Stopping... " ) ;
updateInfoTask . cancel ( ) ;
saveTask . cancel ( ) ;
renderManager . stop ( ) ;
for ( RegionFileWatchService watcher : regionFileWatchServices ) {
watcher . close ( ) ;
}
regionFileWatchServices . clear ( ) ;
try {
renderManager . awaitShutdown ( ) ;
} catch ( InterruptedException e ) {
Logger . global . logError ( " Unexpected interruption: " , e ) ;
}
Logger . global . logInfo ( " Saving... " ) ;
saveTask . run ( ) ;
Logger . global . logInfo ( " Stopped. " ) ;
} ;
2022-12-13 16:54:31 +01:00
Thread shutdownHook = new Thread ( shutdown , " BlueMap-CLI-ShutdownHook " ) ;
2021-09-19 22:15:50 +02:00
Runtime . getRuntime ( ) . addShutdownHook ( shutdownHook ) ;
// wait until done, then shutdown if not watching
renderManager . awaitIdle ( ) ;
Logger . global . logInfo ( " Your maps are now all up-to-date! " ) ;
if ( watch ) {
updateInfoTask . cancel ( ) ;
Logger . global . logInfo ( " Waiting for changes on the world-files... " ) ;
} else {
Runtime . getRuntime ( ) . removeShutdownHook ( shutdownHook ) ;
shutdown . run ( ) ;
}
}
2021-11-14 14:18:31 +01:00
public void startWebserver ( BlueMapService blueMap , boolean verbose ) throws IOException , ConfigurationException , InterruptedException {
2021-09-19 22:15:50 +02:00
Logger . global . logInfo ( " Starting webserver ... " ) ;
2023-11-18 13:50:13 +01:00
WebserverConfig config = blueMap . getConfig ( ) . getWebserverConfig ( ) ;
2022-10-14 10:24:19 +02:00
FileHelper . createDirectories ( config . getWebroot ( ) ) ;
2022-04-20 22:54:27 +02:00
2022-06-27 01:13:48 +02:00
RoutingRequestHandler routingRequestHandler = new RoutingRequestHandler ( ) ;
// default route
routingRequestHandler . register ( " .* " , new FileRequestHandler ( config . getWebroot ( ) ) ) ;
// map route
2023-11-18 13:50:13 +01:00
for ( var mapConfigEntry : blueMap . getConfig ( ) . getMapConfigs ( ) . entrySet ( ) ) {
2024-02-01 23:01:42 +01:00
Storage storage = blueMap . getOrLoadStorage ( mapConfigEntry . getValue ( ) . getStorage ( ) ) ;
2021-11-14 14:18:31 +01:00
2022-06-27 01:13:48 +02:00
routingRequestHandler . register (
2022-08-08 21:29:16 +02:00
" maps/ " + Pattern . quote ( mapConfigEntry . getKey ( ) ) + " /(.*) " ,
2022-06-27 01:13:48 +02:00
" $1 " ,
2022-08-08 21:29:16 +02:00
new MapRequestHandler ( mapConfigEntry . getKey ( ) , storage )
2022-06-27 01:13:48 +02:00
) ;
2021-11-14 14:18:31 +01:00
}
2023-06-29 13:37:31 +02:00
List < Logger > webLoggerList = new ArrayList < > ( ) ;
2023-07-01 09:44:19 +02:00
if ( verbose ) webLoggerList . add ( Logger . stdOut ( true ) ) ;
2023-06-29 13:37:31 +02:00
if ( config . getLog ( ) . getFile ( ) ! = null ) {
ZonedDateTime zdt = ZonedDateTime . ofInstant ( Instant . now ( ) , ZoneId . systemDefault ( ) ) ;
webLoggerList . add ( Logger . file (
Path . of ( String . format ( config . getLog ( ) . getFile ( ) , zdt ) ) ,
config . getLog ( ) . isAppend ( )
) ) ;
}
2023-02-22 16:19:34 +01:00
HttpRequestHandler handler = new BlueMapResponseModifier ( routingRequestHandler ) ;
2023-06-29 13:37:31 +02:00
handler = new LoggingRequestHandler (
handler ,
config . getLog ( ) . getFormat ( ) ,
Logger . combine ( webLoggerList )
) ;
2023-02-22 16:19:34 +01:00
2023-06-08 23:12:20 +02:00
try {
2023-06-29 13:37:31 +02:00
//noinspection resource
2023-06-08 23:12:20 +02:00
HttpServer webServer = new HttpServer ( handler ) ;
webServer . bind ( new InetSocketAddress (
config . resolveIp ( ) ,
config . getPort ( )
) ) ;
webServer . start ( ) ;
} catch ( UnknownHostException ex ) {
throw new ConfigurationException ( " BlueMap failed to resolve the ip in your webserver-config. \ n " +
" Check if that is correctly configured. " , ex ) ;
} catch ( BindException ex ) {
throw new ConfigurationException ( " BlueMap failed to bind to the configured address. \ n " +
" This usually happens when the configured port ( " + config . getPort ( ) + " ) is already in use by some other program. " , ex ) ;
} catch ( IOException ex ) {
throw new ConfigurationException ( " BlueMap failed to initialize the webserver. \ n " +
" Check your webserver-config if everything is configured correctly. \ n " +
" (Make sure you DON'T use the same port for bluemap that you also use for your minecraft server) " , ex ) ;
}
2021-09-19 22:15:50 +02:00
}
public static void main ( String [ ] args ) {
CommandLineParser parser = new DefaultParser ( ) ;
BlueMapCLI cli = new BlueMapCLI ( ) ;
BlueMapService blueMap = null ;
try {
CommandLine cmd = parser . parse ( BlueMapCLI . createOptions ( ) , args , false ) ;
2023-07-01 09:44:19 +02:00
if ( cmd . hasOption ( " b " ) ) {
Logger . global . clear ( ) ;
Logger . global . put ( Logger . stdOut ( true ) ) ;
}
2021-09-19 22:15:50 +02:00
if ( cmd . hasOption ( " l " ) ) {
2023-07-01 09:44:19 +02:00
Logger . global . put ( Logger . file ( Path . of ( cmd . getOptionValue ( " l " ) ) , cmd . hasOption ( " a " ) ) ) ;
2021-09-19 22:15:50 +02:00
}
//help
if ( cmd . hasOption ( " h " ) ) {
BlueMapCLI . printHelp ( ) ;
return ;
}
2023-04-30 11:10:42 +02:00
//version
if ( cmd . hasOption ( " V " ) ) {
BlueMapCLI . printVersion ( ) ;
return ;
}
2021-09-19 22:15:50 +02:00
//config folder
if ( cmd . hasOption ( " c " ) ) {
2022-04-20 22:54:27 +02:00
cli . configFolder = Path . of ( cmd . getOptionValue ( " c " ) ) ;
2022-10-14 10:24:19 +02:00
FileHelper . createDirectories ( cli . configFolder ) ;
2021-09-19 22:15:50 +02:00
}
//minecraft version
if ( cmd . hasOption ( " v " ) ) {
String versionString = cmd . getOptionValue ( " v " ) ;
try {
2022-04-20 22:54:27 +02:00
cli . minecraftVersion = MinecraftVersion . of ( versionString ) ;
2021-09-19 22:15:50 +02:00
} catch ( IllegalArgumentException e ) {
Logger . global . logWarning ( " Could not determine a version from the provided version-string: ' " + versionString + " ' " ) ;
System . exit ( 1 ) ;
return ;
}
}
2024-02-01 23:01:42 +01:00
BlueMapConfigManager configs = BlueMapConfigManager . builder ( )
. minecraftVersion ( cli . minecraftVersion )
. configRoot ( cli . configFolder )
. usePluginConfig ( false )
. defaultDataFolder ( Path . of ( " data " ) )
. defaultWebroot ( Path . of ( " web " ) )
. build ( ) ;
2023-07-01 09:44:19 +02:00
//apply new file-logger config
CoreConfig coreConfig = configs . getCoreConfig ( ) ;
if ( coreConfig . getLog ( ) . getFile ( ) ! = null ) {
ZonedDateTime zdt = ZonedDateTime . ofInstant ( Instant . now ( ) , ZoneId . systemDefault ( ) ) ;
Logger . global . put ( Logger . file (
Path . of ( String . format ( coreConfig . getLog ( ) . getFile ( ) , zdt ) ) ,
coreConfig . getLog ( ) . isAppend ( )
) ) ;
}
2024-02-01 23:01:42 +01:00
blueMap = new BlueMapService ( configs ) ;
2021-09-19 22:15:50 +02:00
boolean noActions = true ;
if ( cmd . hasOption ( " w " ) ) {
noActions = false ;
cli . startWebserver ( blueMap , cmd . hasOption ( " b " ) ) ;
Thread . sleep ( 1000 ) ; //wait a second to let the webserver start, looks nicer in the log if anything comes after that
}
if ( cmd . hasOption ( " r " ) ) {
noActions = false ;
boolean watch = cmd . hasOption ( " u " ) ;
boolean force = cmd . hasOption ( " f " ) ;
boolean generateWebappFiles = cmd . hasOption ( " g " ) ;
2024-01-23 19:35:25 +01:00
String mapsToRender = cmd . getOptionValue ( " m " , null ) ;
cli . renderMaps ( blueMap , watch , force , generateWebappFiles , mapsToRender ) ;
2021-09-19 22:15:50 +02:00
} else {
if ( cmd . hasOption ( " g " ) ) {
noActions = false ;
blueMap . createOrUpdateWebApp ( true ) ;
}
if ( cmd . hasOption ( " s " ) ) {
noActions = false ;
2022-06-06 22:51:26 +02:00
blueMap . createOrUpdateWebApp ( false ) ;
2021-09-19 22:15:50 +02:00
}
}
// if nothing has been defined to do
if ( noActions ) {
2022-06-06 22:51:26 +02:00
Logger . global . logInfo ( " Generated default config files for you, here: " + cli . configFolder . toAbsolutePath ( ) . normalize ( ) + " \ n " ) ;
2021-09-19 22:15:50 +02:00
//create resourcepacks folder
2022-10-14 10:24:19 +02:00
FileHelper . createDirectories ( cli . configFolder . resolve ( " resourcepacks " ) ) ;
2021-09-19 22:15:50 +02:00
//print help
BlueMapCLI . printHelp ( ) ;
System . exit ( 1 ) ;
}
} catch ( MissingResourcesException e ) {
Logger . global . logWarning ( " BlueMap is missing important resources! " ) ;
Logger . global . logWarning ( " You must accept the required file download in order for BlueMap to work! " ) ;
2022-06-06 22:51:26 +02:00
if ( blueMap ! = null ) {
2023-11-18 13:50:13 +01:00
BlueMapConfiguration configProvider = blueMap . getConfig ( ) ;
if ( configProvider instanceof BlueMapConfigManager ) {
Logger . global . logWarning ( " Please check: " + ( ( BlueMapConfigManager ) configProvider ) . getConfigManager ( ) . findConfigPath ( Path . of ( " core " ) ) . toAbsolutePath ( ) . normalize ( ) ) ;
2022-06-06 22:51:26 +02:00
}
}
2021-09-19 22:15:50 +02:00
System . exit ( 2 ) ;
} catch ( ParseException e ) {
Logger . global . logError ( " Failed to parse provided arguments! " , e ) ;
BlueMapCLI . printHelp ( ) ;
System . exit ( 1 ) ;
2021-11-14 14:18:31 +01:00
} catch ( ConfigurationException e ) {
Logger . global . logWarning ( e . getFormattedExplanation ( ) ) ;
Throwable cause = e . getRootCause ( ) ;
if ( cause ! = null ) {
Logger . global . logError ( " Detailed error: " , e ) ;
}
2021-09-19 22:15:50 +02:00
} catch ( IOException e ) {
Logger . global . logError ( " An IO-error occurred! " , e ) ;
System . exit ( 1 ) ;
} catch ( InterruptedException ex ) {
System . exit ( 1 ) ;
} catch ( RuntimeException e ) {
Logger . global . logError ( " An unexpected error occurred! " , e ) ;
System . exit ( 1 ) ;
}
}
private static Options createOptions ( ) {
Options options = new Options ( ) ;
options . addOption ( " h " , " help " , false , " Displays this message " ) ;
options . addOption (
Option . builder ( " c " )
. longOpt ( " config " )
. hasArg ( )
. argName ( " config-folder " )
. desc ( " Sets path of the folder containing the configuration-files to use (configurations will be generated here if they don't exist) " )
. build ( )
) ;
options . addOption (
Option . builder ( " v " )
. longOpt ( " mc-version " )
. hasArg ( )
2023-04-30 11:10:42 +02:00
. argName ( " mc-version " )
2021-09-19 22:15:50 +02:00
. desc ( " Sets the minecraft-version, used e.g. to load resource-packs correctly. Defaults to the latest compatible version. " )
. build ( )
) ;
options . addOption (
Option . builder ( " l " )
. longOpt ( " log-file " )
. hasArg ( )
. argName ( " file-name " )
. desc ( " Sets a file to save the log to. If not specified, no log will be saved. " )
. build ( )
) ;
options . addOption ( " a " , " append " , false , " Causes log save file to be appended rather than replaced. " ) ;
options . addOption ( " w " , " webserver " , false , " Starts the web-server, configured in the 'webserver.conf' file " ) ;
options . addOption ( " b " , " verbose " , false , " Causes the web-server to log requests to the console " ) ;
2022-06-06 22:51:26 +02:00
options . addOption ( " g " , " generate-webapp " , false , " Generates the files for the web-app to the folder configured in the 'webapp.conf' file " ) ;
options . addOption ( " s " , " generate-websettings " , false , " Updates the settings.json for the web-app " ) ;
2021-09-19 22:15:50 +02:00
options . addOption ( " r " , " render " , false , " Renders the maps configured in the 'render.conf' file " ) ;
options . addOption ( " f " , " force-render " , false , " Forces rendering everything, instead of only rendering chunks that have been modified since the last render " ) ;
2024-01-23 19:35:25 +01:00
options . addOption ( " m " , " maps " , true , " A comma-separated list of map-id's that should be rendered. Example: 'world,nether' " ) ;
2021-09-19 22:15:50 +02:00
options . addOption ( " u " , " watch " , false , " Watches for file-changes after rendering and updates the map " ) ;
2023-04-30 11:10:42 +02:00
options . addOption ( " V " , " version " , false , " Print the current BlueMap version " ) ;
2021-09-19 22:15:50 +02:00
return options ;
}
private static void printHelp ( ) {
HelpFormatter formatter = new HelpFormatter ( ) ;
2024-02-01 23:01:42 +01:00
String command = getCliCommand ( ) ;
@SuppressWarnings ( " StringBufferReplaceableByString " )
StringBuilder footer = new StringBuilder ( ) ;
footer . append ( " Examples: \ n \ n " ) ;
footer . append ( command ) . append ( " -c './config/' \ n " ) ;
footer . append ( " Generates the default/example configurations in a folder named 'config' if they are not already present \ n \ n " ) ;
footer . append ( command ) . append ( " -r \ n " ) ;
footer . append ( " Render the configured maps \ n \ n " ) ;
footer . append ( command ) . append ( " -w \ n " ) ;
footer . append ( " Start only the webserver without doing anything else \ n \ n " ) ;
footer . append ( command ) . append ( " -ru \ n " ) ;
footer . append ( " Render the configured maps and then keeps watching the world-files and updates the map once something changed. \ n \ n " ) ;
formatter . printHelp ( command + " [options] " , " \ nOptions: " , createOptions ( ) , " \ n " + footer ) ;
}
private static String getCliCommand ( ) {
2021-09-19 22:15:50 +02:00
String filename = " bluemap-cli.jar " ;
try {
File file = new File ( BlueMapCLI . class . getProtectionDomain ( )
. getCodeSource ( )
. getLocation ( )
. getPath ( ) ) ;
if ( file . isFile ( ) ) {
try {
2022-05-28 21:55:41 +02:00
filename = " . " + File . separator + new File ( " " ) . getCanonicalFile ( ) . toPath ( ) . relativize ( file . toPath ( ) ) ;
2021-09-19 22:15:50 +02:00
} catch ( IllegalArgumentException ex ) {
filename = file . getAbsolutePath ( ) ;
}
}
} catch ( IOException ignore ) { }
2024-02-01 23:01:42 +01:00
return " java -jar " + filename ;
2021-09-19 22:15:50 +02:00
}
2023-04-30 11:10:42 +02:00
private static void printVersion ( ) {
2023-06-08 22:01:31 +02:00
System . out . printf ( " %s \ n%s \ n " , BlueMap . VERSION , BlueMap . GIT_HASH ) ;
2023-04-30 11:10:42 +02:00
}
2019-11-02 17:23:48 +01:00
}