diff --git a/DynmapCore/build.gradle b/DynmapCore/build.gradle index 9fa007713..d77442c56 100644 --- a/DynmapCore/build.gradle +++ b/DynmapCore/build.gradle @@ -19,13 +19,9 @@ dependencies { implementation 'org.yaml:snakeyaml:1.23' // DON'T UPDATE - NEWER ONE TRIPS ON WINDOWS ENCODED FILES implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20180219.1' implementation 'org.postgresql:postgresql:42.2.18' - implementation 'io.github.linktosriram.s3lite:core:0.0.2-SNAPSHOT' - implementation 'io.github.linktosriram.s3lite:api:0.0.2-SNAPSHOT' - implementation 'io.github.linktosriram.s3lite:http-client-url-connection:0.0.2-SNAPSHOT' - implementation 'io.github.linktosriram.s3lite:http-client-spi:0.0.2-SNAPSHOT' - implementation 'io.github.linktosriram.s3lite:util:0.0.2-SNAPSHOT' - implementation 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.1' - implementation 'com.sun.xml.bind:jaxb-impl:3.0.0' + + // MinIO S3 client (replaces s3lite) - using older version to avoid Java 22 bytecode + implementation 'io.minio:minio:8.5.7' } processResources { @@ -60,14 +56,31 @@ shadowJar { include(dependency('org.eclipse.jetty::')) include(dependency('org.eclipse.jetty.orbit:javax.servlet:')) include(dependency('org.postgresql:postgresql:')) - include(dependency('io.github.linktosriram.s3lite:core:')) - include(dependency('io.github.linktosriram.s3lite:api:')) - include(dependency('io.github.linktosriram.s3lite:http-client-url-connection:')) - include(dependency('io.github.linktosriram.s3lite:http-client-spi:')) - include(dependency('io.github.linktosriram.s3lite:util:')) - include(dependency('jakarta.xml.bind::')) - include(dependency('com.sun.xml.bind::')) + include(dependency('io.minio:minio:')) include(dependency(':DynmapCoreAPI')) + + // MinIO dependencies + include(dependency('com.google.guava:guava:')) + include(dependency('com.google.guava:failureaccess:')) + include(dependency('com.google.guava:listenablefuture:')) + include(dependency('com.carrotsearch.thirdparty:simple-xml-safe:')) + include(dependency('com.squareup.okhttp3:okhttp:')) + include(dependency('com.squareup.okio:okio:')) + include(dependency('com.squareup.okio:okio-jvm:')) + include(dependency('com.fasterxml.jackson.core:jackson-annotations:')) + include(dependency('com.fasterxml.jackson.core:jackson-core:')) + include(dependency('com.fasterxml.jackson.core:jackson-databind:')) + include(dependency('org.bouncycastle:bcprov-jdk18on:')) + include(dependency('org.apache.commons:commons-compress:')) + include(dependency('commons-codec:commons-codec:')) + include(dependency('org.xerial.snappy:snappy-java:')) + include(dependency('org.jetbrains.kotlin:kotlin-stdlib:')) + include(dependency('org.jetbrains.kotlin:kotlin-stdlib-common:')) + include(dependency('org.jetbrains.kotlin:kotlin-stdlib-jdk7:')) + include(dependency('org.jetbrains.kotlin:kotlin-stdlib-jdk8:')) + include(dependency('commons-io:commons-io:')) + include(dependency('org.apache.commons:commons-lang3:')) + exclude("META-INF/maven/**") exclude("META-INF/services/**") } @@ -77,8 +90,15 @@ shadowJar { relocate('org.owasp.html', 'org.dynmap.org.owasp.html') relocate('javax.servlet', 'org.dynmap.javax.servlet' ) relocate('org.postgresql', 'org.dynmap.org.postgresql') - relocate('io.github.linktosriram.s3lite', 'org.dynmap.s3lite') - + + // MinIO and dependencies relocations + relocate('io.minio', 'org.dynmap.minio') + relocate('okhttp3', 'org.dynmap.okhttp3') + relocate('okio', 'org.dynmap.okio') + relocate('com.fasterxml.jackson', 'org.dynmap.jackson') + relocate('com.google.common', 'org.dynmap.guava') + relocate('kotlin', 'org.dynmap.kotlin') + destinationDirectory = file '../target' archiveClassifier = '' } diff --git a/DynmapCore/src/main/java/org/dynmap/storage/aws_s3/AWSS3MapStorage.java b/DynmapCore/src/main/java/org/dynmap/storage/aws_s3/AWSS3MapStorage.java index 577ed2fc2..a0326b656 100644 --- a/DynmapCore/src/main/java/org/dynmap/storage/aws_s3/AWSS3MapStorage.java +++ b/DynmapCore/src/main/java/org/dynmap/storage/aws_s3/AWSS3MapStorage.java @@ -1,7 +1,5 @@ package org.dynmap.storage.aws_s3; -import java.io.IOException; -import java.net.URI; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -11,6 +9,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicInteger; import org.dynmap.DynmapCore; import org.dynmap.DynmapWorld; @@ -28,127 +28,161 @@ import org.dynmap.utils.BufferInputStream; import org.dynmap.utils.BufferOutputStream; -import io.github.linktosriram.s3lite.api.client.S3Client; -import io.github.linktosriram.s3lite.api.exception.NoSuchKeyException; -import io.github.linktosriram.s3lite.api.exception.S3Exception; -import io.github.linktosriram.s3lite.api.region.Region; -import io.github.linktosriram.s3lite.api.request.DeleteObjectRequest; -import io.github.linktosriram.s3lite.api.request.GetObjectRequest; -import io.github.linktosriram.s3lite.api.request.ListObjectsV2Request; -import io.github.linktosriram.s3lite.api.request.PutObjectRequest; -import io.github.linktosriram.s3lite.api.response.GetObjectResponse; -import io.github.linktosriram.s3lite.api.response.ListObjectsV2Response; -import io.github.linktosriram.s3lite.api.response.ResponseBytes; -import io.github.linktosriram.s3lite.api.response.S3Object; -import io.github.linktosriram.s3lite.core.auth.AwsBasicCredentials; -import io.github.linktosriram.s3lite.core.client.DefaultS3ClientBuilder; -import io.github.linktosriram.s3lite.http.spi.request.RequestBody; -import io.github.linktosriram.s3lite.http.urlconnection.URLConnectionSdkHttpClient; +import io.minio.BucketExistsArgs; +import io.minio.GetObjectArgs; +import io.minio.ListObjectsArgs; +import io.minio.MinioClient; +import io.minio.PutObjectArgs; +import io.minio.RemoveObjectArgs; +import io.minio.Result; +import io.minio.StatObjectArgs; +import io.minio.errors.ErrorResponseException; +import io.minio.messages.Item; public class AWSS3MapStorage extends MapStorage { public class StorageTile extends MapStorageTile { private final String baseKey; private final String uri; - + StorageTile(DynmapWorld world, MapType map, int x, int y, int zoom, ImageVariant var) { super(world, map, x, y, zoom, var); - + String baseURI; if (zoom > 0) { - baseURI = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y; - } - else { - baseURI = map.getPrefix() + var.variantSuffix + "/"+ (x >> 5) + "_" + (y >> 5) + "/" + x + "_" + y; + baseURI = map.getPrefix() + var.variantSuffix + "/" + (x >> 5) + "_" + (y >> 5) + "/" + + "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz".substring(0, zoom) + "_" + x + "_" + y; + } else { + baseURI = map.getPrefix() + var.variantSuffix + "/" + (x >> 5) + "_" + (y >> 5) + "/" + x + "_" + y; } uri = baseURI + "." + map.getImageFormat().getFileExt(); baseKey = AWSS3MapStorage.this.prefix + "tiles/" + world.getName() + "/" + uri; } + @Override public boolean exists() { - boolean exists = false; - S3Client s3 = null; - try { - s3 = getConnection(); - ListObjectsV2Request req = ListObjectsV2Request.builder().bucketName(bucketname).prefix(baseKey).maxKeys(1).build(); - ListObjectsV2Response rslt = s3.listObjectsV2(req); - if ((rslt != null) && (rslt.getKeyCount() > 0)) - exists = true; - } catch (S3Exception x) { - if (!x.getCode().equals("SignatureDoesNotMatch")) { // S3 behavior when no object match.... - Log.severe("AWS Exception", x); - } - } catch (StorageShutdownException x) { - - } finally { - releaseConnection(s3); - } + // Check if the operation should be skipped + if (shouldSkipOperation()) { + return false; // Assume the file does not exist during backoff + } + + boolean exists = false; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + minioClient.statObject(StatObjectArgs.builder().bucket(bucketname).object(baseKey).build()); + exists = true; + recordSuccess(); // Record success + } catch (ErrorResponseException x) { + if ("NoSuchKey".equals(x.errorResponse().code())) { + // File not found is a normal case, not an error + recordSuccess(); + } else { + recordError(x, "exists check"); + } + } catch (Exception x) { + recordError(x, "exists check"); + } finally { + releaseConnection(minioClient); + } return exists; } @Override public boolean matchesHashCode(long hash) { - return false; + return false; } @Override public TileRead read() { - S3Client s3 = null; - try { - s3 = getConnection(); - GetObjectRequest req = GetObjectRequest.builder().bucketName(bucketname).key(baseKey).build(); - ResponseBytes obj = s3.getObjectAsBytes(req); - if (obj != null) { - GetObjectResponse rsp = obj.getResponse(); - TileRead tr = new TileRead(); - byte[] buf = obj.getBytes(); - if (buf == null) { return null; } - tr.image = new BufferInputStream(buf); - tr.format = ImageEncoding.fromContentType(rsp.getContentType()); - Map meta = rsp.getMetadata(); - String v = meta.get("x-dynmap-hash"); - if (v != null) { - tr.hashCode = Long.parseLong(v, 16); - } - v = meta.get("x-dynmap-ts"); - if (v != null) { - tr.lastModified = Long.parseLong(v); + // Check if the operation should be skipped + if (shouldSkipOperation()) { + return null; // Return null during backoff to indicate read failure + } + + MinioClient minioClient = null; + try { + minioClient = getConnection(); + try (java.io.InputStream stream = minioClient + .getObject(GetObjectArgs.builder().bucket(bucketname).object(baseKey).build())) { + byte[] buf = stream.readAllBytes(); + if (buf != null && buf.length > 0) { + TileRead tr = new TileRead(); + tr.image = new BufferInputStream(buf); + tr.format = map.getImageFormat().getEncoding(); // Use map's format since MinIO doesn't return + // content-type metadata easily + + // Try to get metadata for hash and timestamp + try { + io.minio.StatObjectResponse stat = minioClient + .statObject(StatObjectArgs.builder().bucket(bucketname).object(baseKey).build()); + Map meta = stat.userMetadata(); + if (meta != null) { + String v = meta.get("x-dynmap-hash"); + if (v != null) { + tr.hashCode = Long.parseLong(v, 16); + } + v = meta.get("x-dynmap-ts"); + if (v != null) { + tr.lastModified = Long.parseLong(v); + } + } + } catch (Exception metaEx) { + // Ignore metadata errors + } + recordSuccess(); // Record success + return tr; } - return tr; - } - } catch (NoSuchKeyException nskx) { - return null; // Nominal case if it doesn't exist - } catch (S3Exception x) { - Log.severe("AWS Exception", x); - } catch (StorageShutdownException x) { - } finally { - releaseConnection(s3); - } - return null; + } + recordSuccess(); // Even if the file is empty, count as success + } catch (ErrorResponseException x) { + if ("NoSuchKey".equals(x.errorResponse().code())) { + recordSuccess(); // File not found is a normal case + return null; // Nominal case if it doesn't exist + } + recordError(x, "read"); + } catch (Exception x) { + recordError(x, "read"); + } finally { + releaseConnection(minioClient); + } + return null; } @Override public boolean write(long hash, BufferOutputStream encImage, long timestamp) { - boolean done = false; - S3Client s3 = null; - try { - s3 = getConnection(); - if (encImage == null) { // Delete? - DeleteObjectRequest req = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build(); - s3.deleteObject(req); - } - else { - PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType(map.getImageFormat().getEncoding().getContentType()) - .addMetadata("x-dynmap-hash", Long.toHexString(hash)).addMetadata("x-dynmap-ts", Long.toString(timestamp)).build(); - s3.putObject(req, RequestBody.fromBytes(encImage.buf)); - } - done = true; - } catch (S3Exception x) { - Log.severe("AWS Exception", x); - } catch (StorageShutdownException x) { - } finally { - releaseConnection(s3); - } + // Check if the operation should be skipped + if (shouldSkipOperation()) { + return false; // Skip write operation during backoff + } + + boolean done = false; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + if (encImage == null) { // Delete? + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketname).object(baseKey).build()); + } else { + Map metadata = new java.util.HashMap<>(); + metadata.put("x-dynmap-hash", Long.toHexString(hash)); + metadata.put("x-dynmap-ts", Long.toString(timestamp)); + + java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(encImage.buf); + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketname) + .object(baseKey) + .stream(inputStream, encImage.buf.length, -1) + .contentType(map.getImageFormat().getEncoding().getContentType()) + .userMetadata(metadata) + .build()); + } + done = true; + recordSuccess(); // Record success + } catch (Exception x) { + recordError(x, "write"); + } finally { + releaseConnection(minioClient); + } // Signal update for zoom out if (zoom == 0) { world.enqueueZoomOutUpdate(this); @@ -177,32 +211,34 @@ public void releaseReadLock() { @Override public void cleanup() { } - + @Override public String getURI() { return uri; } - + @Override public void enqueueZoomOutUpdate() { world.enqueueZoomOutUpdate(this); } + @Override public MapStorageTile getZoomOutTile() { int xx, yy; int step = 1 << zoom; - if(x >= 0) - xx = x - (x % (2*step)); + if (x >= 0) + xx = x - (x % (2 * step)); else - xx = x + (x % (2*step)); + xx = x + (x % (2 * step)); yy = -y; - if(yy >= 0) - yy = yy - (yy % (2*step)); + if (yy >= 0) + yy = yy - (yy % (2 * step)); else - yy = yy + (yy % (2*step)); + yy = yy + (yy % (2 * step)); yy = -yy; - return new StorageTile(world, map, xx, yy, zoom+1, var); + return new StorageTile(world, map, xx, yy, zoom + 1, var); } + @Override public boolean equals(Object o) { if (o instanceof StorageTile) { @@ -211,26 +247,38 @@ public boolean equals(Object o) { } return false; } + @Override public int hashCode() { return baseKey.hashCode(); } + @Override public String toString() { return baseKey; } } - + private String bucketname; - private Region region; + private String endpoint; private String access_key_id; private String secret_access_key; private String prefix; + private boolean path_style_access; private int POOLSIZE = 4; private int cpoolCount = 0; - private S3Client[] cpool = new S3Client[POOLSIZE]; - + private MinioClient[] cpool = new MinioClient[POOLSIZE]; + + // Error handling and backoff mechanism + private final AtomicLong lastErrorTime = new AtomicLong(0); + private final AtomicInteger consecutiveErrors = new AtomicInteger(0); + private final AtomicLong lastErrorLogTime = new AtomicLong(0); + private static final long MIN_BACKOFF_MS = 1000; // Minimum backoff time: 1 second + private static final long MAX_BACKOFF_MS = 300000; // Maximum backoff time: 5 minutes + private static final int MAX_CONSECUTIVE_ERRORS = 10; // Maximum consecutive errors + private static final long ERROR_LOG_INTERVAL_MS = 60000; // Error log interval: 1 minute + public AWSS3MapStorage() { } @@ -240,75 +288,79 @@ public boolean init(DynmapCore core) { return false; } if (!core.isInternalWebServerDisabled) { - Log.severe("AWS S3 storage is not supported option with internal web server: set disable-webserver: true in configuration.txt"); + Log.severe( + "AWS S3 storage is not supported option with internal web server: set disable-webserver: true in configuration.txt"); return false; } if (core.isLoginSupportEnabled()) { - Log.severe("AWS S3 storage is not supported option with loegin support enabled: set login-enabled: false in configuration.txt"); - return false; + Log.severe( + "AWS S3 storage is not supported option with loegin support enabled: set login-enabled: false in configuration.txt"); + return false; } // Get our settings bucketname = core.configuration.getString("storage/bucketname", "dynmap"); access_key_id = core.configuration.getString("storage/aws_access_key_id", System.getenv("AWS_ACCESS_KEY_ID")); - secret_access_key = core.configuration.getString("storage/aws_secret_access_key", System.getenv("AWS_SECRET_ACCESS_KEY")); + secret_access_key = core.configuration.getString("storage/aws_secret_access_key", + System.getenv("AWS_SECRET_ACCESS_KEY")); prefix = core.configuration.getString("storage/prefix", ""); + path_style_access = core.configuration.getBoolean("storage/path_style_access", false); - // Either use a custom region, or one of the default AWS regions + // Either use a custom endpoint, or one of the default AWS regions String region_name = core.configuration.getString("storage/region", "us-east-1"); String region_endpoint = core.configuration.getString("storage/override_endpoint", ""); if (region_endpoint.length() > 0) { - region = Region.of(region_name, URI.create(region_endpoint)); + endpoint = region_endpoint; } else { - region = Region.fromString(region_name); + // Use AWS S3 endpoint format + if ("us-east-1".equals(region_name)) { + endpoint = "https://s3.amazonaws.com"; + } else { + endpoint = "https://s3." + region_name + ".amazonaws.com"; + } } - if ((prefix.length() > 0) && (prefix.charAt(prefix.length()-1) != '/')) { - prefix += '/'; + Log.info("Using AWS S3 storage: web site at S3 bucket " + bucketname + " with endpoint " + endpoint + " (" + + (path_style_access ? "path-style" : "virtual-hosted-style") + " access)"); + + if ((prefix.length() > 0) && (prefix.charAt(prefix.length() - 1) != '/')) { + prefix += '/'; } - // Now creste the access client for the S3 service - Log.info("Using AWS S3 storage: web site at S3 bucket " + bucketname + " in region " + region); - S3Client s3 = null; + // Now create the access client for the S3 service + MinioClient minioClient = null; try { - s3 = getConnection(); - if (s3 == null) { - Log.severe("Error creating S3 access client"); - return false; + minioClient = getConnection(); + if (minioClient == null) { + Log.severe("Error creating MinIO S3 access client"); + return false; + } + // Make sure bucket exists + boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketname).build()); + if (!bucketExists) { + Log.severe("Error: cannot find or access S3 bucket: " + bucketname); + return false; } - // Make sure bucket exists (do list) - ListObjectsV2Request listreq = ListObjectsV2Request.builder() - .bucketName(bucketname) - .maxKeys(1) - .prefix(prefix) - .build(); - ListObjectsV2Response rslt = s3.listObjectsV2(listreq); - if (rslt == null) { - Log.severe("Error: cannot find or access S3 bucket"); - return false; - } - rslt.getContents(); - } catch (S3Exception s3x) { - Log.severe("AWS Exception", s3x); - return false; - } catch (StorageShutdownException x) { - return false; + } catch (Exception ex) { + Log.severe("AWS Exception", ex); + return false; } finally { - releaseConnection(s3); + releaseConnection(minioClient); } return true; } - + @Override public MapStorageTile getTile(DynmapWorld world, MapType map, int x, int y, int zoom, ImageVariant var) { return new StorageTile(world, map, x, y, zoom, var); } - + @Override public MapStorageTile getTile(DynmapWorld world, String uri) { String[] suri = uri.split("/"); - if (suri.length < 2) return null; + if (suri.length < 2) + return null; String mname = suri[0]; // Map URI - might include variant MapType mt = null; ImageVariant imgvar = null; @@ -323,11 +375,11 @@ public MapStorageTile getTile(DynmapWorld world, String uri) { } } } - if (mt == null) { // Not found? + if (mt == null) { // Not found? return null; } // Now, take the last section and parse out coordinates and zoom - String fname = suri[suri.length-1]; + String fname = suri[suri.length - 1]; String[] coord = fname.split("[_\\.]"); if (coord.length < 3) { // 3 or 4 return null; @@ -339,8 +391,7 @@ public MapStorageTile getTile(DynmapWorld world, String uri) { zoom = coord[0].length(); x = Integer.parseInt(coord[1]); y = Integer.parseInt(coord[2]); - } - else { + } else { x = Integer.parseInt(coord[0]); y = Integer.parseInt(coord[1]); } @@ -350,91 +401,76 @@ public MapStorageTile getTile(DynmapWorld world, String uri) { } } - - private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb, MapStorageBaseTileEnumCB cbBase, - MapStorageTileSearchEndCB cbEnd) { - String basekey = prefix + "tiles/" + world.getName() + "/" + map.getPrefix() + var.variantSuffix + "/"; - ListObjectsV2Request req = ListObjectsV2Request.builder().bucketName(bucketname).prefix(basekey).maxKeys(1000).build(); - boolean done = false; - S3Client s3 = null; - try { - s3 = getConnection(); - while (!done) { - ListObjectsV2Response result = s3.listObjectsV2(req); - List objects = result.getContents(); - for (S3Object os : objects) { - String key = os.getKey(); - key = key.substring(basekey.length()); // Strip off base - // Parse the extension - String ext = null; - int extoff = key.lastIndexOf('.'); - if (extoff >= 0) { - ext = key.substring(extoff+1); - key = key.substring(0, extoff); - } - // If not valid image extension, ignore - ImageEncoding fmt = ImageEncoding.fromExt(ext); - if (fmt == null) { - continue; - } - // See if zoom tile: figure out zoom level - int zoom = 0; - if (key.startsWith("z")) { - while (key.startsWith("z")) { - key = key.substring(1); - zoom++; - } - if (key.startsWith("_")) { - key = key.substring(1); - } - } - // Split remainder to get coords - String[] coord = key.split("_"); - if (coord.length == 2) { // Must be 2 to be a tile - try { - int x = Integer.parseInt(coord[0]); - int y = Integer.parseInt(coord[1]); - // Invoke callback - MapStorageTile t = new StorageTile(world, map, x, y, zoom, var); - if(cb != null) - cb.tileFound(t, fmt); - if(cbBase != null && t.zoom == 0) - cbBase.tileFound(t, fmt); - t.cleanup(); - } catch (NumberFormatException nfx) { - } - } - } - if (result.isTruncated()) { // If more, build continuiation request - req = ListObjectsV2Request.builder().bucketName(bucketname) - .prefix(basekey).delimiter("").maxKeys(1000).continuationToken(result.getContinuationToken()).encodingType("url").requestPayer("requester").build(); - } - else { // Else, we're done - done = true; - } - } - } catch (S3Exception x) { - if (!x.getCode().equals("SignatureDoesNotMatch")) { // S3 behavior when no object match.... - Log.severe("AWS Exception", x); - Log.severe("req=" + req); - } - } catch (StorageShutdownException x) { + private void processEnumMapTiles(DynmapWorld world, MapType map, ImageVariant var, MapStorageTileEnumCB cb, + MapStorageBaseTileEnumCB cbBase, + MapStorageTileSearchEndCB cbEnd) { + String basekey = prefix + "tiles/" + world.getName() + "/" + map.getPrefix() + var.variantSuffix + "/"; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + Iterable> results = minioClient + .listObjects(ListObjectsArgs.builder().bucket(bucketname).prefix(basekey).build()); + for (Result result : results) { + Item item = result.get(); + String key = item.objectName(); + key = key.substring(basekey.length()); // Strip off base + // Parse the extension + String ext = null; + int extoff = key.lastIndexOf('.'); + if (extoff >= 0) { + ext = key.substring(extoff + 1); + key = key.substring(0, extoff); + } + // If not valid image extension, ignore + ImageEncoding fmt = ImageEncoding.fromExt(ext); + if (fmt == null) { + continue; + } + // See if zoom tile: figure out zoom level + int zoom = 0; + if (key.startsWith("z")) { + while (key.startsWith("z")) { + key = key.substring(1); + zoom++; + } + if (key.startsWith("_")) { + key = key.substring(1); + } + } + // Split remainder to get coords + String[] coord = key.split("_"); + if (coord.length == 2) { // Must be 2 to be a tile + try { + int x = Integer.parseInt(coord[0]); + int y = Integer.parseInt(coord[1]); + // Invoke callback + MapStorageTile t = new StorageTile(world, map, x, y, zoom, var); + if (cb != null) + cb.tileFound(t, fmt); + if (cbBase != null && t.zoom == 0) + cbBase.tileFound(t, fmt); + t.cleanup(); + } catch (NumberFormatException nfx) { + } + } + } + } catch (Exception x) { + Log.severe("AWS Exception", x); } finally { - releaseConnection(s3); + releaseConnection(minioClient); } - if(cbEnd != null) { + if (cbEnd != null) { cbEnd.searchEnded(); } } - + @Override public void enumMapTiles(DynmapWorld world, MapType map, MapStorageTileEnumCB cb) { List mtlist; if (map != null) { mtlist = Collections.singletonList(map); - } - else { // Else, add all directories under world directory (for maps) + } else { // Else, add all directories under world directory (for maps) mtlist = new ArrayList(world.maps); } for (MapType mt : mtlist) { @@ -446,13 +482,13 @@ public void enumMapTiles(DynmapWorld world, MapType map, MapStorageTileEnumCB cb } @Override - public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, MapStorageTileSearchEndCB cbEnd) { + public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileEnumCB cbBase, + MapStorageTileSearchEndCB cbEnd) { List mtlist; if (map != null) { mtlist = Collections.singletonList(map); - } - else { // Else, add all directories under world directory (for maps) + } else { // Else, add all directories under world directory (for maps) mtlist = new ArrayList(world.maps); } for (MapType mt : mtlist) { @@ -464,36 +500,21 @@ public void enumMapBaseTiles(DynmapWorld world, MapType map, MapStorageBaseTileE } private void processPurgeMapTiles(DynmapWorld world, MapType map, ImageVariant var) { - String basekey = prefix + "tiles/" + world.getName() + "/" + map.getPrefix() + var.variantSuffix + "/"; - ListObjectsV2Request req = ListObjectsV2Request.builder().bucketName(bucketname).prefix(basekey).delimiter("").maxKeys(1000).encodingType("url").requestPayer("requester").build(); - S3Client s3 = null; - try { - s3 = getConnection(); - boolean done = false; - while (!done) { - ListObjectsV2Response result = s3.listObjectsV2(req); - List objects = result.getContents(); - for (S3Object os : objects) { - String key = os.getKey(); - DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(key).build(); - s3.deleteObject(delreq); - } - if (result.isTruncated()) { // If more, build continuiation request - req = ListObjectsV2Request.builder().bucketName(bucketname) - .prefix(basekey).delimiter("").maxKeys(1000).continuationToken(result.getContinuationToken()).encodingType("url").requestPayer("requester").build(); - } - else { // Else, we're done - done = true; - } - } - } catch (S3Exception x) { - if (!x.getCode().equals("SignatureDoesNotMatch")) { // S3 behavior when no object match.... - Log.severe("AWS Exception", x); - Log.severe("req=" + req); - } - } catch (StorageShutdownException x) { + String basekey = prefix + "tiles/" + world.getName() + "/" + map.getPrefix() + var.variantSuffix + "/"; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + Iterable> results = minioClient + .listObjects(ListObjectsArgs.builder().bucket(bucketname).prefix(basekey).build()); + for (Result result : results) { + Item item = result.get(); + String key = item.objectName(); + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketname).object(key).build()); + } + } catch (Exception x) { + Log.severe("AWS Exception", x); } finally { - releaseConnection(s3); + releaseConnection(minioClient); } } @@ -503,8 +524,7 @@ public void purgeMapTiles(DynmapWorld world, MapType map) { if (map != null) { mtlist = Collections.singletonList(map); - } - else { // Else, add all directories under world directory (for maps) + } else { // Else, add all directories under world directory (for maps) mtlist = new ArrayList(world.maps); } for (MapType mt : mtlist) { @@ -518,117 +538,123 @@ public void purgeMapTiles(DynmapWorld world, MapType map) { @Override public boolean setPlayerFaceImage(String playername, FaceType facetype, BufferOutputStream encImage) { - boolean done = false; - String baseKey = prefix + "tiles/faces/" + facetype.id + "/" + playername + ".png"; - S3Client s3 = null; - try { - s3 = getConnection(); - if (encImage == null) { // Delete? - DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build(); - s3.deleteObject(delreq); - } - else { - PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType("image/png").build(); - s3.putObject(req, RequestBody.fromBytes(encImage.buf)); - } - done = true; - } catch (S3Exception x) { - Log.severe("AWS Exception", x); - } catch (StorageShutdownException x) { - } finally { - releaseConnection(s3); - } + boolean done = false; + String baseKey = prefix + "tiles/faces/" + facetype.id + "/" + playername + ".png"; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + if (encImage == null) { // Delete? + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketname).object(baseKey).build()); + } else { + java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(encImage.buf); + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketname) + .object(baseKey) + .stream(inputStream, encImage.buf.length, -1) + .contentType("image/png") + .build()); + } + done = true; + } catch (Exception x) { + Log.severe("AWS Exception", x); + } finally { + releaseConnection(minioClient); + } return done; } @Override public BufferInputStream getPlayerFaceImage(String playername, FaceType facetype) { - return null; + return null; } - + @Override public boolean hasPlayerFaceImage(String playername, FaceType facetype) { - String baseKey = prefix + "tiles/faces/" + facetype.id + "/" + playername + ".png"; - boolean exists = false; - S3Client s3 = null; - try { - s3 = getConnection(); - ListObjectsV2Request req = ListObjectsV2Request.builder().bucketName(bucketname).prefix(baseKey).maxKeys(1).build(); - ListObjectsV2Response rslt = s3.listObjectsV2(req); - if ((rslt != null) && (rslt.getKeyCount() > 0)) - exists = true; - } catch (S3Exception x) { - if (!x.getCode().equals("SignatureDoesNotMatch")) { // S3 behavior when no object match.... - Log.severe("AWS Exception", x); - } - } catch (StorageShutdownException x) { - } finally { - releaseConnection(s3); - } + String baseKey = prefix + "tiles/faces/" + facetype.id + "/" + playername + ".png"; + boolean exists = false; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + minioClient.statObject(StatObjectArgs.builder().bucket(bucketname).object(baseKey).build()); + exists = true; + } catch (ErrorResponseException x) { + if (!"NoSuchKey".equals(x.errorResponse().code())) { + Log.severe("AWS Exception", x); + } + } catch (Exception x) { + Log.severe("AWS Exception", x); + } finally { + releaseConnection(minioClient); + } return exists; } @Override public boolean setMarkerImage(String markerid, BufferOutputStream encImage) { - boolean done = false; - String baseKey = prefix + "tiles/_markers_/" + markerid + ".png"; - S3Client s3 = null; - try { - s3 = getConnection(); - if (encImage == null) { // Delete? - DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build(); - s3.deleteObject(delreq); - } - else { - PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType("image/png").build(); - s3.putObject(req, RequestBody.fromBytes(encImage.buf)); - } - done = true; - } catch (S3Exception x) { - Log.severe("AWS Exception", x); - } catch (StorageShutdownException x) { - } finally { - releaseConnection(s3); - } + boolean done = false; + String baseKey = prefix + "tiles/_markers_/" + markerid + ".png"; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + if (encImage == null) { // Delete? + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketname).object(baseKey).build()); + } else { + java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(encImage.buf); + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketname) + .object(baseKey) + .stream(inputStream, encImage.buf.length, -1) + .contentType("image/png") + .build()); + } + done = true; + } catch (Exception x) { + Log.severe("AWS Exception", x); + } finally { + releaseConnection(minioClient); + } return done; } @Override public BufferInputStream getMarkerImage(String markerid) { - return null; + return null; } @Override public boolean setMarkerFile(String world, String content) { - boolean done = false; - String baseKey = prefix + "tiles/_markers_/marker_" + world + ".json"; - S3Client s3 = null; - try { - s3 = getConnection(); - if (content == null) { // Delete? - DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build(); - s3.deleteObject(delreq); - } - else { - PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType("application/json").build(); - s3.putObject(req, RequestBody.fromBytes(content.getBytes(StandardCharsets.UTF_8))); - } - done = true; - } catch (S3Exception x) { - Log.severe("AWS Exception", x); - } catch (StorageShutdownException x) { - } finally { - releaseConnection(s3); - } + boolean done = false; + String baseKey = prefix + "tiles/_markers_/marker_" + world + ".json"; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + if (content == null) { // Delete? + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketname).object(baseKey).build()); + } else { + byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8); + java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(contentBytes); + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketname) + .object(baseKey) + .stream(inputStream, contentBytes.length, -1) + .contentType("application/json") + .build()); + } + done = true; + } catch (Exception x) { + Log.severe("AWS Exception", x); + } finally { + releaseConnection(minioClient); + } return done; } @Override public String getMarkerFile(String world) { - return null; + return null; } - + @Override // For external web server only public String getMarkersURI(boolean login_enabled) { @@ -640,17 +666,21 @@ public String getMarkersURI(boolean login_enabled) { public String getTilesURI(boolean login_enabled) { return "tiles/"; } - + /** - * URI to use for loading configuration JSON files (for external web server only) + * URI to use for loading configuration JSON files (for external web server + * only) + * * @param login_enabled - selects based on login security enabled * @return URI */ public String getConfigurationJSONURI(boolean login_enabled) { return "standalone/dynmap_config.json?_={timestamp}"; } + /** * URI to use for loading update JSON files (for external web server only) + * * @param login_enabled - selects based on login security enabled * @return URI */ @@ -661,7 +691,7 @@ public String getUpdateJSONURI(boolean login_enabled) { @Override public void addPaths(StringBuilder sb, DynmapCore core) { String p = core.getTilesFolder().getAbsolutePath(); - if(!p.endsWith("/")) + if (!p.endsWith("/")) p += "/"; sb.append("$tilespath = \'"); sb.append(WebAuthManager.esc(p)); @@ -669,101 +699,101 @@ public void addPaths(StringBuilder sb, DynmapCore core) { sb.append("$markerspath = \'"); sb.append(WebAuthManager.esc(p)); sb.append("\';\n"); - + // Need to call base to add webpath super.addPaths(sb, core); } - @Override public BufferInputStream getStandaloneFile(String fileid) { - return null; + return null; } - // Cache to avoid rewriting same standalong file repeatedly private ConcurrentHashMap standalone_cache = new ConcurrentHashMap(); - + @Override public boolean setStandaloneFile(String fileid, BufferOutputStream content) { - return setStaticWebFile("standalone/" + fileid, content); + return setStaticWebFile("standalone/" + fileid, content); } + // Test if storage needs static web files public boolean needsStaticWebFiles() { - return true; + return true; } + /** * Set static web file content - * @param fileid - file path + * + * @param fileid - file path * @param content - content for file * @return true if successful */ public boolean setStaticWebFile(String fileid, BufferOutputStream content) { - - boolean done = false; - String baseKey = prefix + fileid; - S3Client s3 = null; - try { - s3 = getConnection(); - byte[] cacheval = standalone_cache.get(fileid); - - if (content == null) { // Delete? - if ((cacheval != null) && (cacheval.length == 0)) { // Delete cached? - return true; - } - DeleteObjectRequest delreq = DeleteObjectRequest.builder().bucketName(bucketname).key(baseKey).build(); - s3.deleteObject(delreq); - standalone_cache.put(fileid, new byte[0]); // Mark in cache - } - else { - byte[] digest = content.buf; - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(content.buf); - digest = md.digest(); - } catch (NoSuchAlgorithmException nsax) { - - } - // If cached and same, just return - if (Arrays.equals(digest, cacheval)) { - return true; - } - String ct = "text/plain"; - if (fileid.endsWith(".json")) { - ct = "application/json"; - } - else if (fileid.endsWith(".php")) { - ct = "application/x-httpd-php"; - } - else if (fileid.endsWith(".html")) { - ct = "text/html"; - } - else if (fileid.endsWith(".css")) { - ct = "text/css"; - } - else if (fileid.endsWith(".js")) { - ct = "application/x-javascript"; - } - PutObjectRequest req = PutObjectRequest.builder().bucketName(bucketname).key(baseKey).contentType(ct).build(); - s3.putObject(req, RequestBody.fromBytes(content.buf)); - standalone_cache.put(fileid, digest); - } - done = true; - } catch (S3Exception x) { - Log.severe("AWS Exception", x); - } catch (StorageShutdownException x) { - } finally { - releaseConnection(s3); - } + + boolean done = false; + String baseKey = prefix + fileid; + MinioClient minioClient = null; + try { + minioClient = getConnection(); + byte[] cacheval = standalone_cache.get(fileid); + + if (content == null) { // Delete? + if ((cacheval != null) && (cacheval.length == 0)) { // Delete cached? + return true; + } + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketname).object(baseKey).build()); + standalone_cache.put(fileid, new byte[0]); // Mark in cache + } else { + byte[] digest = content.buf; + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(content.buf); + digest = md.digest(); + } catch (NoSuchAlgorithmException nsax) { + + } + // If cached and same, just return + if (Arrays.equals(digest, cacheval)) { + return true; + } + String ct = "text/plain"; + if (fileid.endsWith(".json")) { + ct = "application/json"; + } else if (fileid.endsWith(".php")) { + ct = "application/x-httpd-php"; + } else if (fileid.endsWith(".html")) { + ct = "text/html"; + } else if (fileid.endsWith(".css")) { + ct = "text/css"; + } else if (fileid.endsWith(".js")) { + ct = "application/x-javascript"; + } + java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(content.buf); + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketname) + .object(baseKey) + .stream(inputStream, content.buf.length, -1) + .contentType(ct) + .build()); + standalone_cache.put(fileid, digest); + } + done = true; + } catch (Exception x) { + Log.severe("AWS Exception", x); + } finally { + releaseConnection(minioClient); + } return done; } - private S3Client getConnection() throws S3Exception, StorageShutdownException { - S3Client c = null; - if (isShutdown) throw new StorageShutdownException(); + private MinioClient getConnection() throws MapStorage.StorageShutdownException { + MinioClient c = null; + if (isShutdown) + throw new MapStorage.StorageShutdownException(); synchronized (cpool) { while (c == null) { - for (int i = 0; i < cpool.length; i++) { // See if available connection + for (int i = 0; i < cpool.length; i++) { // See if available connection if (cpool[i] != null) { // Found one c = cpool[i]; cpool[i] = null; @@ -771,19 +801,29 @@ private S3Client getConnection() throws S3Exception, StorageShutdownException { } } if (c == null) { - if (cpoolCount < POOLSIZE) { // Still more we can have - c = new DefaultS3ClientBuilder() - .credentialsProvider(() -> AwsBasicCredentials.create(access_key_id, secret_access_key)) - .region(region) - .httpClient(URLConnectionSdkHttpClient.create()) - .build(); - if (c == null) { - Log.severe("Error creating S3 access client"); - return null; + if (cpoolCount < POOLSIZE) { // Still more we can have + try { + MinioClient.Builder builder = MinioClient.builder() + .endpoint(endpoint) + .credentials(access_key_id, secret_access_key); + + // 设置路径样式访问 + if (path_style_access) { + // MinIO 客户端通过 endpoint 自动处理路径样式访问 + // 不需要额外配置 + } + + c = builder.build(); + if (c == null) { + Log.severe("Error creating MinIO S3 access client"); + return null; + } + cpoolCount++; + } catch (Exception e) { + Log.severe("Error creating MinIO S3 access client", e); + return null; } - cpoolCount++; - } - else { + } else { try { cpool.wait(); } catch (InterruptedException e) { @@ -795,26 +835,148 @@ private S3Client getConnection() throws S3Exception, StorageShutdownException { } return c; } - - private void releaseConnection(S3Client c) { - if (c == null) return; + + private void releaseConnection(MinioClient c) { + if (c == null) + return; synchronized (cpool) { for (int i = 0; i < POOLSIZE; i++) { if (cpool[i] == null) { cpool[i] = c; - c = null; // Mark it recovered (no close needed + c = null; // Mark it recovered (no close needed) cpool.notifyAll(); break; } } - if (c != null) { // If broken, just toss it - try { - c.close(); - } catch (IOException e) { - } - cpoolCount--; // And reduce count + if (c != null) { // If broken, just toss it + cpoolCount--; // And reduce count cpool.notifyAll(); } } } + + /** + * Checks if the operation should be skipped (based on backoff mechanism) + * + * @return true if the operation should be skipped + */ + private boolean shouldSkipOperation() { + long currentTime = System.currentTimeMillis(); + long lastError = lastErrorTime.get(); + int errors = consecutiveErrors.get(); + + if (errors == 0) { + return false; // No errors, execute normally + } + + if (errors >= MAX_CONSECUTIVE_ERRORS) { + // Maximum error count reached, log warning and skip + long lastLogTime = lastErrorLogTime.get(); + if (currentTime - lastLogTime > ERROR_LOG_INTERVAL_MS) { + if (lastErrorLogTime.compareAndSet(lastLogTime, currentTime)) { + Log.warning("AWS S3 operations suspended due to " + errors + " consecutive errors. " + + "Please check your S3 credentials and configuration. " + + "Next retry in " + (MAX_BACKOFF_MS / 1000) + " seconds."); + } + } + + // Check if it's time to retry + if (currentTime - lastError < MAX_BACKOFF_MS) { + return true; // Still within maximum backoff time, skip operation + } else { + // Reset error count, allow retry + consecutiveErrors.set(0); + return false; + } + } + + // Calculate backoff time (exponential backoff) + long backoffTime = Math.min(MIN_BACKOFF_MS * (1L << Math.min(errors - 1, 10)), MAX_BACKOFF_MS); + + if (currentTime - lastError < backoffTime) { + return true; // Still within backoff time, skip operation + } + + return false; // Operation can be executed + } + + /** + * Record operation success + */ + private void recordSuccess() { + consecutiveErrors.set(0); + } + + /** + * Record operation failure + * + * @param exception Exception information + * @param operation Operation name + */ + private void recordError(Exception exception, String operation) { + long currentTime = System.currentTimeMillis(); + lastErrorTime.set(currentTime); + int errors = consecutiveErrors.incrementAndGet(); + + // Determine if it's an authentication/permission error + boolean isAuthError = isAuthenticationError(exception); + + // Control log frequency + long lastLogTime = lastErrorLogTime.get(); + boolean shouldLog = false; + + if (isAuthError) { + // Authentication errors: log immediately for the first time, then once per minute + shouldLog = (errors == 1) || (currentTime - lastLogTime > ERROR_LOG_INTERVAL_MS); + } else { + // Other errors: log immediately for the first 3 times, then once per minute + shouldLog = (errors <= 3) || (currentTime - lastLogTime > ERROR_LOG_INTERVAL_MS); + } + + if (shouldLog && lastErrorLogTime.compareAndSet(lastLogTime, currentTime)) { + if (isAuthError) { + Log.severe("AWS S3 " + operation + " failed (attempt " + errors + "): " + + "Authentication/Authorization error. Please check your AWS credentials and bucket permissions. " + + + "Error: " + exception.getMessage()); + if (errors >= 3) { + Log.severe("Subsequent S3 authentication errors will be logged less frequently to avoid log spam."); + } + } else { + Log.severe("AWS S3 " + operation + " failed (attempt " + errors + "): " + exception.getMessage()); + if (errors > 3) { + Log.severe("S3 operations will be retried with exponential backoff. Current backoff: " + + Math.min(MIN_BACKOFF_MS * (1L << Math.min(errors - 1, 10)), MAX_BACKOFF_MS) / 1000 + + " seconds"); + } + } + } + } + + /** + * Determine if it's an authentication/permission related error + */ + private boolean isAuthenticationError(Exception exception) { + if (exception instanceof ErrorResponseException) { + ErrorResponseException ere = (ErrorResponseException) exception; + String errorCode = ere.errorResponse().code(); + return "AccessDenied".equals(errorCode) || + "InvalidAccessKeyId".equals(errorCode) || + "SignatureDoesNotMatch".equals(errorCode) || + "TokenRefreshRequired".equals(errorCode) || + "ExpiredToken".equals(errorCode); + } + + String message = exception.getMessage(); + if (message != null) { + message = message.toLowerCase(); + return message.contains("access denied") || + message.contains("invalid access key") || + message.contains("signature does not match") || + message.contains("expired token") || + message.contains("unauthorized"); + } + + return false; + } } diff --git a/fabric-1.14.4/src/main/resources/configuration.txt b/fabric-1.14.4/src/main/resources/configuration.txt index e0334afaf..cdaebd0a2 100644 --- a/fabric-1.14.4/src/main/resources/configuration.txt +++ b/fabric-1.14.4/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -403,7 +404,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.15.2/src/main/resources/configuration.txt b/fabric-1.15.2/src/main/resources/configuration.txt index e0334afaf..cdaebd0a2 100644 --- a/fabric-1.15.2/src/main/resources/configuration.txt +++ b/fabric-1.15.2/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -403,7 +404,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.16.4/src/main/resources/configuration.txt b/fabric-1.16.4/src/main/resources/configuration.txt index c8205d76e..bf31ce161 100644 --- a/fabric-1.16.4/src/main/resources/configuration.txt +++ b/fabric-1.16.4/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.17.1/src/main/resources/configuration.txt b/fabric-1.17.1/src/main/resources/configuration.txt index c8205d76e..bf31ce161 100644 --- a/fabric-1.17.1/src/main/resources/configuration.txt +++ b/fabric-1.17.1/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.18.2/src/main/resources/configuration.txt b/fabric-1.18.2/src/main/resources/configuration.txt index b1f4d7470..75884cc49 100644 --- a/fabric-1.18.2/src/main/resources/configuration.txt +++ b/fabric-1.18.2/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -409,7 +410,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.19.4/src/main/resources/configuration.txt b/fabric-1.19.4/src/main/resources/configuration.txt index c17b0b96e..248444c59 100644 --- a/fabric-1.19.4/src/main/resources/configuration.txt +++ b/fabric-1.19.4/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -409,7 +410,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.20.6/src/main/resources/configuration.txt b/fabric-1.20.6/src/main/resources/configuration.txt index bb8b456ca..1d79d665c 100644 --- a/fabric-1.20.6/src/main/resources/configuration.txt +++ b/fabric-1.20.6/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -146,7 +147,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -179,12 +180,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -196,7 +197,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -211,7 +212,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -408,7 +409,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.21.1/src/main/resources/configuration.txt b/fabric-1.21.1/src/main/resources/configuration.txt index bb8b456ca..1d79d665c 100644 --- a/fabric-1.21.1/src/main/resources/configuration.txt +++ b/fabric-1.21.1/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -146,7 +147,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -179,12 +180,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -196,7 +197,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -211,7 +212,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -408,7 +409,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.21.3/src/main/resources/configuration.txt b/fabric-1.21.3/src/main/resources/configuration.txt index bb8b456ca..1d79d665c 100644 --- a/fabric-1.21.3/src/main/resources/configuration.txt +++ b/fabric-1.21.3/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -146,7 +147,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -179,12 +180,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -196,7 +197,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -211,7 +212,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -408,7 +409,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/fabric-1.21/src/main/resources/configuration.txt b/fabric-1.21/src/main/resources/configuration.txt index bb8b456ca..1d79d665c 100644 --- a/fabric-1.21/src/main/resources/configuration.txt +++ b/fabric-1.21/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -146,7 +147,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -179,12 +180,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -196,7 +197,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -211,7 +212,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -408,7 +409,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/forge-1.12.2/build.gradle b/forge-1.12.2/build.gradle index 786601949..48c236ee7 100644 --- a/forge-1.12.2/build.gradle +++ b/forge-1.12.2/build.gradle @@ -31,15 +31,6 @@ dependencies { implementation 'org.yaml:snakeyaml:1.23' // DON'T UPDATE - NEWER ONE TRIPS ON WINDOWS ENCODED FILES implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20180219.1' implementation 'org.postgresql:postgresql:42.2.18' - implementation 'io.github.linktosriram.s3lite:core:0.0.2-SNAPSHOT' - implementation 'io.github.linktosriram.s3lite:api:0.0.2-SNAPSHOT' - implementation 'io.github.linktosriram.s3lite:http-client-url-connection:0.0.2-SNAPSHOT' - implementation 'io.github.linktosriram.s3lite:http-client-spi:0.0.2-SNAPSHOT' - implementation 'io.github.linktosriram.s3lite:util:0.0.2-SNAPSHOT' - implementation 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.1' - implementation 'com.sun.xml.bind:jaxb-impl:3.0.0' - implementation 'com.googlecode.json-simple:json-simple:1.1.1' - implementation 'org.yaml:snakeyaml:1.23' implementation 'org.spongepowered:spongeapi:7.0.0' } @@ -94,13 +85,6 @@ shadowJar { include(dependency('org.eclipse.jetty::')) include(dependency('org.eclipse.jetty.orbit:javax.servlet:')) include(dependency('org.postgresql:postgresql:')) - include(dependency('io.github.linktosriram.s3lite:core:')) - include(dependency('io.github.linktosriram.s3lite:api:')) - include(dependency('io.github.linktosriram.s3lite:http-client-url-connection:')) - include(dependency('io.github.linktosriram.s3lite:http-client-spi:')) - include(dependency('io.github.linktosriram.s3lite:util:')) - include(dependency('jakarta.xml.bind::')) - include(dependency('com.sun.xml.bind::')) exclude("META-INF/maven/**") exclude("META-INF/services/**") } @@ -110,7 +94,6 @@ shadowJar { relocate('org.owasp.html', 'org.dynmap.org.owasp.html') relocate('javax.servlet', 'org.dynmap.javax.servlet' ) relocate('org.postgresql', 'org.dynmap.org.postgresql') - relocate('io.github.linktosriram.s3lite', 'org.dynmap.s3lite') archiveName = "Dynmap-${parent.version}-forge-1.12.2.jar" destinationDir = file '../target' manifest { diff --git a/forge-1.14.4/src/main/resources/configuration.txt b/forge-1.14.4/src/main/resources/configuration.txt index 4c2fbf504..bf31ce161 100644 --- a/forge-1.14.4/src/main/resources/configuration.txt +++ b/forge-1.14.4/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." @@ -482,7 +483,7 @@ soft-ref-cache: true #enterexitUseTitle: true # Set true if new enter messages should supercede pending exit messages (vs being queued in order), default false #enterReplacesExits: true - + # Published public URL for Dynmap server (allows users to use 'dynmap url' command to get public URL usable to access server # If not set, 'dynmap url' will not return anything. URL should be fully qualified (e.g. https://mc.westeroscraft.com/) #publicURL: http://my.greatserver.com/dynmap diff --git a/forge-1.15.2/src/main/resources/configuration.txt b/forge-1.15.2/src/main/resources/configuration.txt index 4c2fbf504..bf31ce161 100644 --- a/forge-1.15.2/src/main/resources/configuration.txt +++ b/forge-1.15.2/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." @@ -482,7 +483,7 @@ soft-ref-cache: true #enterexitUseTitle: true # Set true if new enter messages should supercede pending exit messages (vs being queued in order), default false #enterReplacesExits: true - + # Published public URL for Dynmap server (allows users to use 'dynmap url' command to get public URL usable to access server # If not set, 'dynmap url' will not return anything. URL should be fully qualified (e.g. https://mc.westeroscraft.com/) #publicURL: http://my.greatserver.com/dynmap diff --git a/forge-1.16.5/src/main/resources/configuration.txt b/forge-1.16.5/src/main/resources/configuration.txt index 38174f817..dc6aecae5 100644 --- a/forge-1.16.5/src/main/resources/configuration.txt +++ b/forge-1.16.5/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/forge-1.17.1/src/main/resources/configuration.txt b/forge-1.17.1/src/main/resources/configuration.txt index 9257fbaae..dc6aecae5 100644 --- a/forge-1.17.1/src/main/resources/configuration.txt +++ b/forge-1.17.1/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." @@ -482,7 +483,7 @@ soft-ref-cache: true #enterexitUseTitle: true # Set true if new enter messages should supercede pending exit messages (vs being queued in order), default false #enterReplacesExits: true - + # Published public URL for Dynmap server (allows users to use 'dynmap url' command to get public URL usable to access server # If not set, 'dynmap url' will not return anything. URL should be fully qualified (e.g. https://mc.westeroscraft.com/) #publicURL: http://my.greatserver.com/dynmap diff --git a/forge-1.18.2/src/main/resources/configuration.txt b/forge-1.18.2/src/main/resources/configuration.txt index 38174f817..dc6aecae5 100644 --- a/forge-1.18.2/src/main/resources/configuration.txt +++ b/forge-1.18.2/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/forge-1.19.3/src/main/resources/configuration.txt b/forge-1.19.3/src/main/resources/configuration.txt index 38174f817..dc6aecae5 100644 --- a/forge-1.19.3/src/main/resources/configuration.txt +++ b/forge-1.19.3/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/forge-1.20.6/src/main/resources/configuration.txt b/forge-1.20.6/src/main/resources/configuration.txt index 38174f817..dc6aecae5 100644 --- a/forge-1.20.6/src/main/resources/configuration.txt +++ b/forge-1.20.6/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/forge-1.21.3/src/main/resources/configuration.txt b/forge-1.21.3/src/main/resources/configuration.txt index 38174f817..dc6aecae5 100644 --- a/forge-1.21.3/src/main/resources/configuration.txt +++ b/forge-1.21.3/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/forge-1.21/src/main/resources/configuration.txt b/forge-1.21/src/main/resources/configuration.txt index 38174f817..dc6aecae5 100644 --- a/forge-1.21/src/main/resources/configuration.txt +++ b/forge-1.21/src/main/resources/configuration.txt @@ -45,13 +45,14 @@ storage: #bucketname: "dynmap-bucket-name" #region: us-east-1 #aws_access_key_id: "" - #aws_secret_access_key: "" + #aws_secret_access_key: "" #prefix: "" #override_endpoint: "" + #path_style_access: false components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) Show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -411,7 +412,7 @@ grayplayerswhenhidden: true trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + joinmessage: "%playername% joined" quitmessage: "%playername% quit" spammessage: "You may only chat once every %interval% seconds." diff --git a/gradle.properties b/gradle.properties index 1f4688034..4bea71991 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,4 @@ org.gradle.jvmargs=-Xmx4G -org.gradle.daemon=false -org.gradle.parallel=false +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.java.home=C:\\Users\\nmg_w\\.jdks\\temurin-21.0.7 diff --git a/spigot/src/main/resources/configuration.txt b/spigot/src/main/resources/configuration.txt index 84a2acb3a..c4f606174 100644 --- a/spigot/src/main/resources/configuration.txt +++ b/spigot/src/main/resources/configuration.txt @@ -48,10 +48,11 @@ storage: #aws_access_key_id: "" #aws_secret_access_key: "" #override_endpoint: "" - + #path_style_access: false + components: - class: org.dynmap.ClientConfigurationComponent - + # Remember to change the following class to org.dynmap.JsonFileClientUpdateComponent when using an external web server. - class: org.dynmap.InternalClientUpdateComponent sendhealth: true @@ -79,7 +80,7 @@ components: # hideifshadow: 4 # # Optional - make player hidden when they are under cover (#=sky light level,0=underground,15=open to sky) # hideifundercover: 14 - # # (Optional) if true, players that are crouching/sneaking will be hidden + # # (Optional) if true, players that are crouching/sneaking will be hidden hideifsneaking: false # optional, if true, players that are in spectator mode will be hidden hideifspectator: false @@ -112,12 +113,12 @@ components: # chatlengthlimit: 256 # hide-if-invisiblity-potion: true # hidenames: false - + - class: org.dynmap.SimpleWebChatComponent allowchat: true # If true, web UI users can supply name for chat using 'playername' URL parameter. 'trustclientname' must also be set true. allowurlname: false - + # Note: this component is needed for the dmarker commands, and for the Marker API to be available to other plugins - class: org.dynmap.MarkersComponent type: markers @@ -147,7 +148,7 @@ components: # (optional) show world border (vanilla 1.8+) showworldborder: true worldborderlabel: "Border" - + - class: org.dynmap.ClientComponent type: chat allowurlname: false @@ -180,12 +181,12 @@ components: layerprio: 0 # Optional - label for player marker layer (default is 'Players') label: "Players" - + #- class: org.dynmap.ClientComponent # type: digitalclock - class: org.dynmap.ClientComponent type: link - + - class: org.dynmap.ClientComponent type: timeofdayclock showdigitalclock: true @@ -197,7 +198,7 @@ components: hidey: false show-mcr: false show-chunk: false - + # Note: more than one logo component can be defined #- class: org.dynmap.ClientComponent # type: logo @@ -212,7 +213,7 @@ components: # timeout: 1800 # in seconds (1800 seconds = 30 minutes) # redirecturl: inactive.html # #showmessage: 'You were inactive for too long.' - + #- class: org.dynmap.TestComponent # stuff: "This is some configuration-value" @@ -274,7 +275,7 @@ use-brightness-table: true block-alias: # "minecraft:quartz_ore": "stone" # "diamond_ore": "coal_ore" - + # Default image format for HDMaps (png, jpg, jpg-q75, jpg-q80, jpg-q85, jpg-q90, jpg-q95, jpg-q100, webp, webp-q75, webp-q80, webp-q85, webp-q90, webp-q95, webp-q100, webp-l), # Note: any webp format requires the presence of the 'webp command line tools' (cwebp, dwebp) (https://developers.google.com/speed/webp/download) # @@ -409,7 +410,7 @@ grayplayerswhenhidden: true # That is, anyone with first listed permission goes before anyone with second, etc, with users with none of the nodes going last player-sort-permission-nodes: - bukkit.command.op - + # Set sidebaropened: 'true' to pin menu sidebar opened permanently, 'pinned' to default the sidebar to pinned, but allow it to unpin #sidebaropened: true @@ -423,7 +424,7 @@ player-sort-permission-nodes: trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" - + # Join/quit message format for web chat: set to "" to disable notice on web UI joinmessage: "%playername% joined" quitmessage: "%playername% quit"