Update 1.0.11

- potentially fix color cache error
- added /imagemap cleanup command
- added /imagemap debuginfo command
This commit is contained in:
SydMontague 2023-05-01 11:05:42 +02:00
parent 67ed74b006
commit b70a163c3c
23 changed files with 2050 additions and 1902 deletions

24
.github/FUNDING.yml vendored
View File

@ -1,13 +1,13 @@
# These are supported funding model platforms # These are supported funding model platforms
custom: ["paypal.me/sydmontague"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] custom: ["paypal.me/sydmontague"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
# github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
# patreon: # Replace with a single Patreon username # patreon: # Replace with a single Patreon username
# open_collective: # Replace with a single Open Collective username # open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username # ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
# liberapay: # Replace with a single Liberapay username # liberapay: # Replace with a single Liberapay username
# issuehunt: # Replace with a single IssueHunt username # issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username # otechie: # Replace with a single Otechie username

View File

@ -1,33 +1,33 @@
# This workflow will build a Java project with Maven # This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven name: Java CI with Maven
on: on:
push: push:
branches: [ master ] branches: [ master ]
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up JDK 1.8 - name: Set up JDK 1.8
uses: actions/setup-java@v1 uses: actions/setup-java@v1
with: with:
java-version: 1.8 java-version: 1.8
- name: Build with Maven - name: Build with Maven
run: | run: |
mkdir -p ~/.m2 mkdir -p ~/.m2
echo "<settings><servers><server><id>github</id><username>${{ github.actor }}</username><password>${{ github.token }}</password></server></servers></settings>" > ~/.m2/settings.xml echo "<settings><servers><server><id>github</id><username>${{ github.actor }}</username><password>${{ github.token }}</password></server></servers></settings>" > ~/.m2/settings.xml
mvn -B package --file pom.xml mvn -B package --file pom.xml
- uses: actions/upload-artifact@v1 - uses: actions/upload-artifact@v1
with: with:
name: Package name: Package
path: target/ImageMaps.jar path: target/ImageMaps.jar
- name: Publish to GitHub Packages Apache Maven - name: Publish to GitHub Packages Apache Maven
run: mvn deploy run: mvn deploy
env: env:
GITHUB_TOKEN: ${{ github.token }} # GITHUB_TOKEN is the default env for the password GITHUB_TOKEN: ${{ github.token }} # GITHUB_TOKEN is the default env for the password

42
LICENSE
View File

@ -1,21 +1,21 @@
MIT License MIT License
Copyright (c) 2020 SydMontague Copyright (c) 2020 SydMontague
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.

196
README.MD
View File

@ -1,99 +1,99 @@
# ImageMaps # ImageMaps
ImageMaps is a plugin for Bukkit Minecraft servers that enables you to place custom images in your world ImageMaps is a plugin for Bukkit Minecraft servers that enables you to place custom images in your world
by rendering them onto maps and placing them in item frames. by rendering them onto maps and placing them in item frames.
This can be used to create info graphics, custom paintings and even the appearance of custom textures. This can be used to create info graphics, custom paintings and even the appearance of custom textures.
![Example Screenshot](./screenshot.png) ![Example Screenshot](./screenshot.png)
## Installation ## Installation
You will need a Server that implements Bukkit 1.13 or newer and the Spigot-API. Some features are only available in newer You will need a Server that implements Bukkit 1.13 or newer and the Spigot-API. Some features are only available in newer
releases. Make sure to use the latest release of your server software before reporting issues. releases. Make sure to use the latest release of your server software before reporting issues.
Put the plugin into your servers `plugins` folder and start it up. A folder for the plugin will be created Put the plugin into your servers `plugins` folder and start it up. A folder for the plugin will be created
automatically. You can place your images in the `images` folder inside it. automatically. You can place your images in the `images` folder inside it.
### Upgrading from versions &lt; 1.0.0 ### Upgrading from versions &lt; 1.0.0
The plugin should convert your maps.yml automatically. It will attempt to create a backup before doing so, The plugin should convert your maps.yml automatically. It will attempt to create a backup before doing so,
but it is recommended to do one manually as well. but it is recommended to do one manually as well.
## Usage ## Usage
In order for you use place images they must be present in the `images` folder. You can either put them In order for you use place images they must be present in the `images` folder. You can either put them
there via FTP or just copying it, or by using the plugin's download command, allowing you to access there via FTP or just copying it, or by using the plugin's download command, allowing you to access
images from the Internet. images from the Internet.
To place images just run the `/imagemap place` command and right click the block that should be the To place images just run the `/imagemap place` command and right click the block that should be the
upper left corner of the image (based on your perspective). upper left corner of the image (based on your perspective).
Images will by default split into 128x128 pixel sub-images to fit on a map. The image may be scaled via Images will by default split into 128x128 pixel sub-images to fit on a map. The image may be scaled via
command parameters, however **it is recommended to prepare correctly scaled images**. command parameters, however **it is recommended to prepare correctly scaled images**.
The color palette of Minecraft maps is very limited, requiring the plugin/Bukkit to convert the input image. The color palette of Minecraft maps is very limited, requiring the plugin/Bukkit to convert the input image.
This will result in your images looking different ingame than the source. The available color table can be This will result in your images looking different ingame than the source. The available color table can be
found here: https://minecraft.gamepedia.com/Map_item_format#Color_table found here: https://minecraft.gamepedia.com/Map_item_format#Color_table
![Example of color conversion](./colorConversion.png) ![Example of color conversion](./colorConversion.png)
The invisible and fixed (-> can't be modified) item frame properties are only available in 1.16+. You can modify them for any item frame The invisible and fixed (-> can't be modified) item frame properties are only available in 1.16+. You can modify them for any item frame
by using a configurable (default a wooden hoe) items. Right click to toggle visibility and Shift+Right click to by using a configurable (default a wooden hoe) items. Right click to toggle visibility and Shift+Right click to
toggle the fixed state. toggle the fixed state.
### Commands ### Commands
* /imagemap place &lt;filename> [frameInvisible] [frameFixed] [frameGlowing] [size] * /imagemap place &lt;filename> [frameInvisible] [frameFixed] [frameGlowing] [size]
* Starts the placement process * Starts the placement process
* frameInvisible and frameFixed are only available on 1.16+ * frameInvisible and frameFixed are only available on 1.16+
* frameGlowing is only available on 1.17+ * frameGlowing is only available on 1.17+
* /imagemap download &lt;filename> &lt;sourceURL> * /imagemap download &lt;filename> &lt;sourceURL>
* downloads an image from the given URL into the `images` folder * downloads an image from the given URL into the `images` folder
* /imagemap delete &lt;filename> * /imagemap delete &lt;filename>
* deletes an image from the `images` folder * deletes an image from the `images` folder
* /imagemap info &lt;filename> * /imagemap info &lt;filename>
* prints info, such as resolution and expected size * prints info, such as resolution and expected size
* /imagemap reload &lt;filename> * /imagemap reload &lt;filename>
* reloads an image, to be used when the image file changed * reloads an image, to be used when the image file changed
* /imagemap list [page] * /imagemap list [page]
* lists all images in the `images` folder * lists all images in the `images` folder
* /imagemap help [command] * /imagemap help [command]
* prints help for commands * prints help for commands
### Permissions ### Permissions
`imagemaps.*` - grants access to all permissions `imagemaps.*` - grants access to all permissions
`imagemaps.place` - grants access to /imagemap place command `imagemaps.place` - grants access to /imagemap place command
`imagemaps.download` - grants access to /imagemap download command `imagemaps.download` - grants access to /imagemap download command
`imagemaps.delete` - grants access to /imagemap delete command `imagemaps.delete` - grants access to /imagemap delete command
`imagemaps.info` - grants access to /imagemap info command `imagemaps.info` - grants access to /imagemap info command
`imagemaps.list` - grants access to /imagemap list command `imagemaps.list` - grants access to /imagemap list command
`imagemaps.reload` - grants access to /imagemap reload command `imagemaps.reload` - grants access to /imagemap reload command
`imagemaps.help` - grants access to /imagemap help command `imagemaps.help` - grants access to /imagemap help command
`imagemaps.toggleFixed` - allows to toggle the "fixed" state of frames with a wooden hoe `imagemaps.toggleFixed` - allows to toggle the "fixed" state of frames with a wooden hoe
`imagemaps.toggleVisible` - allows to toggle the "visible" state of frames with a wooden hoe `imagemaps.toggleVisible` - allows to toggle the "visible" state of frames with a wooden hoe
All permissions are default true for OPs. All permissions are default true for OPs.
## Maven ## Maven
You will need to [configure your environment to access GitHub repositories](https://docs.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-apache-maven-for-use-with-github-packages). You will need to [configure your environment to access GitHub repositories](https://docs.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-apache-maven-for-use-with-github-packages).
``` ```
<repository> <repository>
<id>github</id> <id>github</id>
<name>ImageMaps repository</name> <name>ImageMaps repository</name>
<url>https://maven.pkg.github.com/SydMontague/ImageMaps</url> <url>https://maven.pkg.github.com/SydMontague/ImageMaps</url>
</repository> </repository>
``` ```
``` ```
<dependency> <dependency>
<groupId>net.craftcitizen</groupId> <groupId>net.craftcitizen</groupId>
<artifactId>imagemaps</artifactId> <artifactId>imagemaps</artifactId>
<version>1.0.1</version> <version>1.0.1</version>
</dependency> </dependency>
``` ```
## Contact ## Contact
* Discord: SydMontague#8056 * Discord: SydMontague#8056
* directly on GitHub * directly on GitHub
* E-Mail: sydmontague@web.de * E-Mail: sydmontague@web.de
* Spigot: https://www.spigotmc.org/members/sydmontague.37699/ * Spigot: https://www.spigotmc.org/members/sydmontague.37699/
This plugin has been developed for the [CraftCitizen](https://craftcitizen.net) survival Minecraft server. This plugin has been developed for the [CraftCitizen](https://craftcitizen.net) survival Minecraft server.

228
pom.xml
View File

@ -1,115 +1,115 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>net.craftcitizen</groupId> <groupId>net.craftcitizen</groupId>
<artifactId>imagemaps</artifactId> <artifactId>imagemaps</artifactId>
<version>1.0.10</version> <version>1.0.11</version>
<name>ImageMaps</name> <name>ImageMaps</name>
<description>Render Images onto maps!</description> <description>Render Images onto maps!</description>
<distributionManagement> <distributionManagement>
<repository> <repository>
<id>github</id> <id>github</id>
<name>GitHub ImageMaps Packages</name> <name>GitHub ImageMaps Packages</name>
<url>https://maven.pkg.github.com/SydMontague/ImageMaps</url> <url>https://maven.pkg.github.com/SydMontague/ImageMaps</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>
<repositories> <repositories>
<repository> <repository>
<id>spigot-repo</id> <id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url> <url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository> </repository>
<repository> <repository>
<id>github</id> <id>github</id>
<name>GitHub CLCore Packages</name> <name>GitHub CLCore Packages</name>
<url>https://maven.pkg.github.com/SydMontague/CLCore</url> <url>https://maven.pkg.github.com/SydMontague/CLCore</url>
</repository> </repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.17.1-R0.1-SNAPSHOT</version> <version>1.17.1-R0.1-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>de.craftlancer</groupId> <groupId>de.craftlancer</groupId>
<artifactId>clcore</artifactId> <artifactId>clcore</artifactId>
<version>0.4.0-SNAPSHOT</version> <version>0.4.0-SNAPSHOT</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<artifactId>*</artifactId> <artifactId>*</artifactId>
<groupId>*</groupId> <groupId>*</groupId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<resources> <resources>
<resource> <resource>
<directory>${basedir}/src/main/resources</directory> <directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
</resources> </resources>
<finalName>${project.name}</finalName> <finalName>${project.name}</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version> <version>3.2.4</version>
<configuration> <configuration>
<filters> <filters>
<filter> <filter>
<artifact>de.craftlancer:clcore</artifact> <artifact>de.craftlancer:clcore</artifact>
<includes> <includes>
<include>de/craftlancer/core/command/*</include> <include>de/craftlancer/core/command/*</include>
<include>de/craftlancer/core/util/*</include> <include>de/craftlancer/core/util/*</include>
<include>de/craftlancer/core/LambdaRunnable*</include> <include>de/craftlancer/core/LambdaRunnable*</include>
<include>de/craftlancer/core/Utils*</include> <include>de/craftlancer/core/Utils*</include>
<include>de/craftlancer/core/SemanticVersion*</include> <include>de/craftlancer/core/SemanticVersion*</include>
</includes> </includes>
</filter> </filter>
</filters> </filters>
<artifactSet> <artifactSet>
<includes> <includes>
<include>de.craftlancer:clcore</include> <include>de.craftlancer:clcore</include>
</includes> </includes>
</artifactSet> </artifactSet>
<relocations> <relocations>
<relocation> <relocation>
<pattern>de.craftlancer.core</pattern> <pattern>de.craftlancer.core</pattern>
<shadedPattern>net.craftcitizen.imagemaps.clcore</shadedPattern> <shadedPattern>net.craftcitizen.imagemaps.clcore</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>shade</goal> <goal>shade</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<source>1.8</source> <source>1.8</source>
<target>1.8</target> <target>1.8</target>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@ -1,91 +1,92 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs; import org.bukkit.configuration.serialization.SerializableAs;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@SerializableAs("ImageMaps.Map") @SerializableAs("ImageMaps.Map")
public class ImageMap implements ConfigurationSerializable { public class ImageMap implements ConfigurationSerializable {
private String filename; private String filename;
private int x; private int x;
private int y; private int y;
private double scale; private double scale;
public ImageMap(String filename, int x, int y, double scale) { public ImageMap(String filename, int x, int y, double scale) {
this.filename = filename; this.filename = filename;
this.x = x; this.x = x;
this.y = y; this.y = y;
this.scale = scale; this.scale = scale;
} }
public ImageMap(Map<?, ?> map) { public ImageMap(Map<?, ?> map) {
this.filename = map.get("image").toString(); this.filename = map.get("image").toString();
this.x = (Integer) map.get("x"); this.x = (Integer) map.get("x");
this.y = (Integer) map.get("y"); this.y = (Integer) map.get("y");
this.scale = (Double) map.get("scale"); this.scale = (Double) map.get("scale");
} }
@Override @Override
public Map<String, Object> serialize() { public Map<String, Object> serialize() {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("image", filename); map.put("image", filename);
map.put("x", x); map.put("x", x);
map.put("y", y); map.put("y", y);
map.put("scale", scale); map.put("scale", scale);
return map; return map;
} }
public String getFilename() { public String getFilename() {
return filename; return filename;
} }
public int getX() { public int getX() {
return x; return x;
} }
public int getY() { public int getY() {
return y; return y;
} }
public double getScale() { public double getScale() {
return scale; return scale;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((filename == null) ? 0 : filename.hashCode()); result = prime * result + ((filename == null) ? 0 : filename.hashCode());
long temp; long temp;
temp = Double.doubleToLongBits(scale); temp = Double.doubleToLongBits(scale);
result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + x; result = prime * result + x;
result = prime * result + y; result = prime * result + y;
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (!(obj instanceof ImageMap)) if (!(obj instanceof ImageMap))
return false; return false;
ImageMap other = (ImageMap) obj; ImageMap other = (ImageMap) obj;
if (filename == null) { if (filename == null) {
if (other.filename != null) if (other.filename != null)
return false; return false;
} else if (!filename.equals(other.filename)) }
return false; else if (!filename.equals(other.filename))
if (Double.doubleToLongBits(scale) != Double.doubleToLongBits(other.scale)) return false;
return false; if (Double.doubleToLongBits(scale) != Double.doubleToLongBits(other.scale))
if (x != other.x) return false;
return false; if (x != other.x)
if (y != other.y) return false;
return false; if (y != other.y)
return true; return false;
} return true;
} }
}

View File

@ -0,0 +1,37 @@
package net.craftcitizen.imagemaps;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil;
public class ImageMapCleanupCommand extends ImageMapSubCommand {
public ImageMapCleanupCommand(ImageMaps plugin) {
super("imagemaps.admin", plugin, true);
}
@Override
protected String execute(CommandSender sender, Command cmd, String label, String[] args) {
if (!checkSender(sender)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command.");
return null;
}
int removedMaps = getPlugin().cleanupMaps();
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"Removed " + removedMaps + " invalid images/maps.");
return null;
}
@Override
public void help(CommandSender sender) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"Removes maps with invalid IDs or missing image files.");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING,
"This action is not reverseable. It is recommended to create a backup of your maps.yml first!");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap cleanup");
}
}

View File

@ -1,16 +1,18 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.command.CommandHandler; import de.craftlancer.core.command.CommandHandler;
public class ImageMapCommandHandler extends CommandHandler { public class ImageMapCommandHandler extends CommandHandler {
public ImageMapCommandHandler(ImageMaps plugin) { public ImageMapCommandHandler(ImageMaps plugin) {
super(plugin); super(plugin);
registerSubCommand("download", new ImageMapDownloadCommand(plugin)); registerSubCommand("download", new ImageMapDownloadCommand(plugin));
registerSubCommand("delete", new ImageMapDeleteCommand(plugin)); registerSubCommand("delete", new ImageMapDeleteCommand(plugin));
registerSubCommand("place", new ImageMapPlaceCommand(plugin)); registerSubCommand("place", new ImageMapPlaceCommand(plugin));
registerSubCommand("info", new ImageMapInfoCommand(plugin)); registerSubCommand("info", new ImageMapInfoCommand(plugin));
registerSubCommand("list", new ImageMapListCommand(plugin)); registerSubCommand("list", new ImageMapListCommand(plugin));
registerSubCommand("reload", new ImageMapReloadCommand(plugin)); registerSubCommand("reload", new ImageMapReloadCommand(plugin));
registerSubCommand("help", new ImageMapHelpCommand(plugin, getCommands()), "?"); registerSubCommand("cleanup", new ImageMapCleanupCommand(plugin));
} registerSubCommand("debuginfo", new ImageMapDebugInfoCommand(plugin));
} registerSubCommand("help", new ImageMapHelpCommand(plugin, getCommands()), "?");
}
}

View File

@ -0,0 +1,39 @@
package net.craftcitizen.imagemaps;
import javax.imageio.ImageIO;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil;
public class ImageMapDebugInfoCommand extends ImageMapSubCommand {
public ImageMapDebugInfoCommand(ImageMaps plugin) {
super("imagemaps.admin", plugin, true);
}
@Override
protected String execute(CommandSender sender, Command cmd, String label, String[] args) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"ImageMaps Version " + getPlugin().getDescription().getVersion());
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "OS: " + System.getProperty("os.name"));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "ImageIO Params:");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"Formats: " + String.join(", ", ImageIO.getReaderFormatNames()));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"Suffixes: " + String.join(", ", ImageIO.getReaderFileSuffixes()));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"MIME: " + String.join(", ", ImageIO.getReaderMIMETypes()));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"Uses Cache: " + Boolean.toString(ImageIO.getUseCache()));
return null;
}
@Override
public void help(CommandSender sender) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Prints some debug output.");
}
}

View File

@ -1,64 +1,65 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.Utils; import de.craftlancer.core.Utils;
import de.craftlancer.core.util.MessageLevel; import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil; import de.craftlancer.core.util.MessageUtil;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.io.File; import java.io.File;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class ImageMapDeleteCommand extends ImageMapSubCommand { public class ImageMapDeleteCommand extends ImageMapSubCommand {
public ImageMapDeleteCommand(ImageMaps plugin) { public ImageMapDeleteCommand(ImageMaps plugin) {
super("imagemaps.delete", plugin, true); super("imagemaps.delete", plugin, true);
} }
@Override @Override
protected String execute(CommandSender sender, Command cmd, String label, String[] args) { protected String execute(CommandSender sender, Command cmd, String label, String[] args) {
if (!checkSender(sender)) { if (!checkSender(sender)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command.");
return null; return null;
} }
if (args.length < 2) { if (args.length < 2) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name.");
return null; return null;
} }
String filename = args[1]; String filename = args[1];
if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) { if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Filename contains illegal character."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Filename contains illegal character.");
return null; return null;
} }
if (!getPlugin().hasImage(filename)) { if (!getPlugin().hasImage(filename)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "No image with this name exists."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "No image with this name exists.");
return null; return null;
} }
if (getPlugin().deleteImage(filename)) { if (getPlugin().deleteImage(filename)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "File deleted."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "File deleted.");
} else { }
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Failed to delete file."); else {
} MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Failed to delete file.");
return null; }
} return null;
}
@Override
public void help(CommandSender sender) { @Override
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Deletes an image."); public void help(CommandSender sender) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap delete <filename>"); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Deletes an image.");
} MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap delete <filename>");
}
@Override
protected List<String> onTabComplete(CommandSender sender, String[] args) { @Override
if (args.length == 2) protected List<String> onTabComplete(CommandSender sender, String[] args) {
return Utils.getMatches(args[1], new File(plugin.getDataFolder(), "images").list()); if (args.length == 2)
return Utils.getMatches(args[1], new File(plugin.getDataFolder(), "images").list());
return Collections.emptyList();
} return Collections.emptyList();
} }
}

View File

@ -1,114 +1,122 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.LambdaRunnable; import de.craftlancer.core.LambdaRunnable;
import de.craftlancer.core.util.MessageLevel; import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil; import de.craftlancer.core.util.MessageUtil;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
public class ImageMapDownloadCommand extends ImageMapSubCommand { public class ImageMapDownloadCommand extends ImageMapSubCommand {
public ImageMapDownloadCommand(ImageMaps plugin) { public ImageMapDownloadCommand(ImageMaps plugin) {
super("imagemaps.download", plugin, true); super("imagemaps.download", plugin, true);
} }
@Override @Override
protected String execute(CommandSender sender, Command cmd, String label, String[] args) { protected String execute(CommandSender sender, Command cmd, String label, String[] args) {
if (!checkSender(sender)) { if (!checkSender(sender)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command.");
return null; return null;
} }
if (args.length < 3) { if (args.length < 3) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name and a download link."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING,
return null; "You must specify a file name and a download link.");
} return null;
}
String filename = args[1];
String url = args[2]; String filename = args[1];
String url = args[2];
if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Filename contains illegal character."); if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) {
return null; MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Filename contains illegal character.");
} return null;
}
new LambdaRunnable(() -> download(sender, url, filename)).runTaskAsynchronously(plugin);
return null; new LambdaRunnable(() -> download(sender, url, filename)).runTaskAsynchronously(plugin);
} return null;
}
private void download(CommandSender sender, String input, String filename) {
try { private void download(CommandSender sender, String input, String filename) {
URL srcURL = new URL(input); try {
URL srcURL = new URL(input);
if (!srcURL.getProtocol().startsWith("http")) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Download URL is not valid."); if (!srcURL.getProtocol().startsWith("http")) {
return; MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Download URL is not valid.");
} return;
}
URLConnection connection = srcURL.openConnection();
URLConnection connection = srcURL.openConnection();
if (!(connection instanceof HttpURLConnection)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Download URL is not valid."); if (!(connection instanceof HttpURLConnection)) {
return; MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Download URL is not valid.");
} return;
}
connection.setRequestProperty("User-Agent", "ImageMaps/0");
connection.setRequestProperty("User-Agent", "ImageMaps/0");
if (((HttpURLConnection) connection).getResponseCode() != 200) {
MessageUtil.sendMessage(getPlugin(), if (((HttpURLConnection) connection).getResponseCode() != 200) {
sender, MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING,
MessageLevel.WARNING, String.format("Download failed, HTTP Error code %d.",
String.format("Download failed, HTTP Error code %d.", ((HttpURLConnection) connection).getResponseCode())); ((HttpURLConnection) connection).getResponseCode()));
return; return;
} }
String mimeType = connection.getHeaderField("Content-type"); String mimeType = connection.getHeaderField("Content-type");
if (!(mimeType.startsWith("image/"))) { if (!(mimeType.startsWith("image/"))) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, String.format("Download is a %s file, not image.", mimeType)); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING,
return; String.format("Download is a %s file, not image.", mimeType));
} return;
}
try (InputStream str = connection.getInputStream()) {
BufferedImage image = ImageIO.read(str); try (InputStream str = connection.getInputStream()) {
if (image == null) { BufferedImage image = ImageIO.read(str);
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Downloaded file is not an image!"); if (image == null) {
return; MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING,
} "Downloaded file is not an image!");
return;
File outFile = new File(plugin.getDataFolder(), "images" + File.separatorChar + filename); }
boolean fileExisted = outFile.exists();
ImageIO.write(image, "PNG", outFile); File outFile = new File(plugin.getDataFolder(), "images" + File.separatorChar + filename);
boolean fileExisted = outFile.exists();
if (fileExisted) { ImageIO.write(image, "PNG", outFile);
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "File already exists, overwriting!");
getPlugin().reloadImage(filename); if (fileExisted) {
} MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING,
} catch (IllegalArgumentException ex) { "File already exists, overwriting!");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Received no data"); getPlugin().reloadImage(filename);
return; }
} }
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Download complete."); catch (IllegalArgumentException ex) {
} catch (MalformedURLException ex) { MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Received no data");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Malformatted URL"); return;
} catch (IOException ex) { }
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.ERROR, "An IO Exception happened, see server log"); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Download complete.");
ex.printStackTrace(); }
} catch (MalformedURLException ex) {
} MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Malformatted URL");
}
@Override catch (IOException ex) {
public void help(CommandSender sender) { MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.ERROR,
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Downloads an image from an URL."); "An IO Exception happened, see server log");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap download <filename> <sourceURL>"); ex.printStackTrace();
} }
} }
@Override
public void help(CommandSender sender) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Downloads an image from an URL.");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO,
"Usage: /imagemap download <filename> <sourceURL>");
}
}

View File

@ -1,58 +1,67 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.command.HelpCommand; import de.craftlancer.core.command.HelpCommand;
import de.craftlancer.core.command.SubCommand; import de.craftlancer.core.command.SubCommand;
import de.craftlancer.core.util.MessageLevel; import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil; import de.craftlancer.core.util.MessageUtil;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.util.Map; import java.util.Map;
public class ImageMapHelpCommand extends HelpCommand { public class ImageMapHelpCommand extends HelpCommand {
public ImageMapHelpCommand(Plugin plugin, Map<String, SubCommand> map) { public ImageMapHelpCommand(Plugin plugin, Map<String, SubCommand> map) {
super("imagemaps.help", plugin, map); super("imagemaps.help", plugin, map);
} }
@Override @Override
public void help(CommandSender sender) { public void help(CommandSender sender) {
if (((ImageMaps) getPlugin()).isGlowingSupported()) { if (((ImageMaps) getPlugin()).isGlowingSupported()) {
MessageUtil.sendMessage(getPlugin(), MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
sender, buildMessage("/imagemap place <filename> [frameInvisible] [frameFixed] [frameGlowing] [size]",
MessageLevel.NORMAL, " - starts image placement"));
buildMessage("/imagemap place <filename> [frameInvisible] [frameFixed] [frameGlowing] [size]", " - starts image placement")); }
} else if (((ImageMaps) getPlugin()).isInvisibilitySupported()) { else if (((ImageMaps) getPlugin()).isInvisibilitySupported()) {
MessageUtil.sendMessage(getPlugin(), MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
sender, buildMessage("/imagemap place <filename> [frameInvisible] [frameFixed] [size]",
MessageLevel.NORMAL, " - starts image placement"));
buildMessage("/imagemap place <filename> [frameInvisible] [frameFixed] [size]", " - starts image placement")); }
} else { else {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, buildMessage("/imagemap place <filename> [size]", " - starts image placement")); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
} buildMessage("/imagemap place <filename> [size]", " - starts image placement"));
}
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, buildMessage("/imagemap download <filename> <sourceURL>", " - downloads an image"));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, buildMessage("/imagemap delete <filename>", " - deletes an image")); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, buildMessage("/imagemap info <filename>", " - displays image info")); buildMessage("/imagemap download <filename> <sourceURL>", " - downloads an image"));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, buildMessage("/imagemap reload <filename>", " - reloads an image from disk")); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, buildMessage("/imagemap list [page]", " - lists all files in the images folder")); buildMessage("/imagemap delete <filename>", " - deletes an image"));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, buildMessage("/imagemap help [command]", " - shows help")); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
} buildMessage("/imagemap info <filename>", " - displays image info"));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
private static BaseComponent buildMessage(String str1, String str2) { buildMessage("/imagemap reload <filename>", " - reloads an image from disk"));
BaseComponent combined = new TextComponent(); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
buildMessage("/imagemap cleanup", " - removes invalid maps from plugin"));
BaseComponent comp1 = new TextComponent(str1); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
comp1.setColor(ChatColor.WHITE); buildMessage("/imagemap list [page]", " - lists all files in the images folder"));
BaseComponent comp2 = new TextComponent(str2); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
comp2.setColor(ChatColor.GRAY); buildMessage("/imagemap help [command]", " - shows help"));
}
combined.addExtra(comp1);
combined.addExtra(comp2); private static BaseComponent buildMessage(String str1, String str2) {
BaseComponent combined = new TextComponent();
return combined;
} BaseComponent comp1 = new TextComponent(str1);
} comp1.setColor(ChatColor.WHITE);
BaseComponent comp2 = new TextComponent(str2);
comp2.setColor(ChatColor.GRAY);
combined.addExtra(comp1);
combined.addExtra(comp2);
return combined;
}
}

View File

@ -1,84 +1,89 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.Utils; import de.craftlancer.core.Utils;
import de.craftlancer.core.util.MessageLevel; import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil; import de.craftlancer.core.util.MessageUtil;
import de.craftlancer.core.util.Tuple; import de.craftlancer.core.util.Tuple;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class ImageMapInfoCommand extends ImageMapSubCommand { public class ImageMapInfoCommand extends ImageMapSubCommand {
public ImageMapInfoCommand(ImageMaps plugin) { public ImageMapInfoCommand(ImageMaps plugin) {
super("imagemaps.info", plugin, true); super("imagemaps.info", plugin, true);
} }
@Override @Override
protected String execute(CommandSender sender, Command cmd, String label, String[] args) { protected String execute(CommandSender sender, Command cmd, String label, String[] args) {
if (!checkSender(sender)) { if (!checkSender(sender)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command.");
return null; return null;
} }
if (args.length < 2) { if (args.length < 2) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name.");
return null; return null;
} }
String filename = args[1]; String filename = args[1];
BufferedImage image = getPlugin().getImage(filename); BufferedImage image = getPlugin().getImage(filename);
if (image == null) { if (image == null) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "No image with this name exists."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "No image with this name exists.");
return null; return null;
} }
Tuple<Integer, Integer> size = getPlugin().getImageSize(filename, null); Tuple<Integer, Integer> size = getPlugin().getImageSize(filename, null);
BaseComponent reloadAction = new TextComponent("[Reload]"); BaseComponent reloadAction = new TextComponent("[Reload]");
reloadAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/imagemap reload \"%s\"", filename))); reloadAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
reloadAction.setColor(ChatColor.GOLD); String.format("/imagemap reload \"%s\"", filename)));
BaseComponent placeAction = new TextComponent("[Place]"); reloadAction.setColor(ChatColor.GOLD);
placeAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/imagemap place \"%s\"", filename))); BaseComponent placeAction = new TextComponent("[Place]");
placeAction.setColor(ChatColor.GOLD); placeAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
BaseComponent deleteAction = new TextComponent("[Delete]"); String.format("/imagemap place \"%s\"", filename)));
deleteAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/imagemap delete \"%s\"", filename))); placeAction.setColor(ChatColor.GOLD);
deleteAction.setColor(ChatColor.RED); BaseComponent deleteAction = new TextComponent("[Delete]");
deleteAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
BaseComponent actions = new TextComponent("Action: "); String.format("/imagemap delete \"%s\"", filename)));
actions.addExtra(reloadAction); deleteAction.setColor(ChatColor.RED);
actions.addExtra(" ");
actions.addExtra(placeAction); BaseComponent actions = new TextComponent("Action: ");
actions.addExtra(" "); actions.addExtra(reloadAction);
actions.addExtra(deleteAction); actions.addExtra(" ");
actions.addExtra(placeAction);
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Image Information: "); actions.addExtra(" ");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, String.format("File Name: %s", filename)); actions.addExtra(deleteAction);
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, String.format("Resolution: %dx%d", image.getWidth(), image.getHeight()));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, String.format("Ingame Size: %dx%d", size.getKey(), size.getValue())); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Image Information: ");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, actions); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, String.format("File Name: %s", filename));
return null; MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
} String.format("Resolution: %dx%d", image.getWidth(), image.getHeight()));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
@Override String.format("Ingame Size: %dx%d", size.getKey(), size.getValue()));
public void help(CommandSender sender) { MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, actions);
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Displays information about an image."); return null;
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap info <filename>"); }
}
@Override
@Override public void help(CommandSender sender) {
protected List<String> onTabComplete(CommandSender sender, String[] args) { MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Displays information about an image.");
if (args.length == 2) MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap info <filename>");
return Utils.getMatches(args[1], new File(plugin.getDataFolder(), "images").list()); }
return Collections.emptyList(); @Override
} protected List<String> onTabComplete(CommandSender sender, String[] args) {
} if (args.length == 2)
return Utils.getMatches(args[1], new File(plugin.getDataFolder(), "images").list());
return Collections.emptyList();
}
}

View File

@ -1,84 +1,88 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.Utils; import de.craftlancer.core.Utils;
import de.craftlancer.core.util.MessageLevel; import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil; import de.craftlancer.core.util.MessageUtil;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ClickEvent.Action; import net.md_5.bungee.api.chat.ClickEvent.Action;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.io.File; import java.io.File;
public class ImageMapListCommand extends ImageMapSubCommand { public class ImageMapListCommand extends ImageMapSubCommand {
public ImageMapListCommand(ImageMaps plugin) { public ImageMapListCommand(ImageMaps plugin) {
super("imagemaps.list", plugin, true); super("imagemaps.list", plugin, true);
} }
@Override @Override
protected String execute(CommandSender sender, Command cmd, String label, String[] args) { protected String execute(CommandSender sender, Command cmd, String label, String[] args) {
if (!checkSender(sender)) { if (!checkSender(sender)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command.");
return null; return null;
} }
String[] fileList = new File(plugin.getDataFolder(), "images").list(); String[] fileList = new File(plugin.getDataFolder(), "images").list();
long page = args.length >= 2 ? Utils.parseIntegerOrDefault(args[1], 0) - 1 : 0; long page = args.length >= 2 ? Utils.parseIntegerOrDefault(args[1], 0) - 1 : 0;
int numPages = (int) Math.ceil((double) fileList.length / Utils.ELEMENTS_PER_PAGE); int numPages = (int) Math.ceil((double) fileList.length / Utils.ELEMENTS_PER_PAGE);
MessageUtil.sendMessage(plugin, sender, MessageLevel.INFO,
MessageUtil.sendMessage(plugin, sender, MessageLevel.INFO, String.format("## Image List Page %d of %d ##", page + 1, numPages)); String.format("## Image List Page %d of %d ##", page + 1, numPages));
boolean even = false; boolean even = false;
for (String filename : Utils.paginate(fileList, page)) { for (String filename : Utils.paginate(fileList, page)) {
BaseComponent infoAction = new TextComponent("[Info]"); BaseComponent infoAction = new TextComponent("[Info]");
infoAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/imagemap info \"%s\"", filename))); infoAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
infoAction.setColor(ChatColor.GOLD); String.format("/imagemap info \"%s\"", filename)));
BaseComponent reloadAction = new TextComponent("[Reload]"); infoAction.setColor(ChatColor.GOLD);
reloadAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/imagemap reload \"%s\"", filename))); BaseComponent reloadAction = new TextComponent("[Reload]");
reloadAction.setColor(ChatColor.GOLD); reloadAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
BaseComponent placeAction = new TextComponent("[Place]"); String.format("/imagemap reload \"%s\"", filename)));
placeAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/imagemap place \"%s\"", filename))); reloadAction.setColor(ChatColor.GOLD);
placeAction.setColor(ChatColor.GOLD); BaseComponent placeAction = new TextComponent("[Place]");
BaseComponent deleteAction = new TextComponent("[Delete]"); placeAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
deleteAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, String.format("/imagemap delete \"%s\"", filename))); String.format("/imagemap place \"%s\"", filename)));
deleteAction.setColor(ChatColor.RED); placeAction.setColor(ChatColor.GOLD);
BaseComponent deleteAction = new TextComponent("[Delete]");
BaseComponent message = new TextComponent(filename); deleteAction.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND,
message.setColor(even ? ChatColor.GRAY : ChatColor.WHITE); String.format("/imagemap delete \"%s\"", filename)));
message.addExtra(" "); deleteAction.setColor(ChatColor.RED);
message.addExtra(infoAction);
message.addExtra(" "); BaseComponent message = new TextComponent(filename);
message.addExtra(reloadAction); message.setColor(even ? ChatColor.GRAY : ChatColor.WHITE);
message.addExtra(" "); message.addExtra(" ");
message.addExtra(placeAction); message.addExtra(infoAction);
message.addExtra(" "); message.addExtra(" ");
message.addExtra(deleteAction); message.addExtra(reloadAction);
message.addExtra(" ");
MessageUtil.sendMessage(plugin, sender, MessageLevel.NORMAL, message); message.addExtra(placeAction);
even = !even; message.addExtra(" ");
} message.addExtra(deleteAction);
BaseComponent navigation = new TextComponent(); MessageUtil.sendMessage(plugin, sender, MessageLevel.NORMAL, message);
BaseComponent prevPage = new TextComponent(String.format("<< Page %d", Math.max(page, 1))); even = !even;
BaseComponent nextPage = new TextComponent(String.format("Page %d >>", Math.min(page + 1, numPages))); }
prevPage.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/imagemap list " + Math.max(page, 1)));
nextPage.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/imagemap list " + Math.min(page + 2, numPages))); BaseComponent navigation = new TextComponent();
BaseComponent prevPage = new TextComponent(String.format("<< Page %d", Math.max(page, 1)));
navigation.addExtra(prevPage); BaseComponent nextPage = new TextComponent(String.format("Page %d >>", Math.min(page + 2, numPages)));
navigation.addExtra(" | "); prevPage.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/imagemap list " + Math.max(page, 1)));
navigation.addExtra(nextPage); nextPage.setClickEvent(new ClickEvent(Action.RUN_COMMAND, "/imagemap list " + Math.min(page + 2, numPages)));
MessageUtil.sendMessage(plugin, sender, MessageLevel.INFO, navigation);
return null; navigation.addExtra(prevPage);
} navigation.addExtra(" | ");
navigation.addExtra(nextPage);
@Override MessageUtil.sendMessage(plugin, sender, MessageLevel.INFO, navigation);
public void help(CommandSender sender) { return null;
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Lists all files in the images folder."); }
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap list [page]");
} @Override
} public void help(CommandSender sender) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Lists all files in the images folder.");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap list [page]");
}
}

View File

@ -1,128 +1,133 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.Utils; import de.craftlancer.core.Utils;
import de.craftlancer.core.util.MessageLevel; import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil; import de.craftlancer.core.util.MessageUtil;
import de.craftlancer.core.util.Tuple; import de.craftlancer.core.util.Tuple;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.FixedMetadataValue;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class ImageMapPlaceCommand extends ImageMapSubCommand { public class ImageMapPlaceCommand extends ImageMapSubCommand {
public ImageMapPlaceCommand(ImageMaps plugin) { public ImageMapPlaceCommand(ImageMaps plugin) {
super("imagemaps.place", plugin, false); super("imagemaps.place", plugin, false);
} }
@Override @Override
protected String execute(CommandSender sender, Command cmd, String label, String[] args) { protected String execute(CommandSender sender, Command cmd, String label, String[] args) {
if (!checkSender(sender)) { if (!checkSender(sender)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command.");
return null; return null;
} }
if (args.length < 2) { if (args.length < 2) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name.");
return null; return null;
} }
String filename = args[1]; String filename = args[1];
boolean isInvisible = false; boolean isInvisible = false;
boolean isFixed = false; boolean isFixed = false;
boolean isGlowing = false; boolean isGlowing = false;
Tuple<Integer, Integer> scale; Tuple<Integer, Integer> scale;
if (getPlugin().isInvisibilitySupported()) { if (getPlugin().isInvisibilitySupported()) {
isInvisible = args.length >= 3 && Boolean.parseBoolean(args[2]); isInvisible = args.length >= 3 && Boolean.parseBoolean(args[2]);
isFixed = args.length >= 4 && Boolean.parseBoolean(args[3]); isFixed = args.length >= 4 && Boolean.parseBoolean(args[3]);
if (getPlugin().isGlowingSupported()) { if (getPlugin().isGlowingSupported()) {
isGlowing = args.length >= 5 && Boolean.parseBoolean(args[4]); isGlowing = args.length >= 5 && Boolean.parseBoolean(args[4]);
scale = args.length >= 6 ? parseScale(args[5]) : new Tuple<>(-1, -1); scale = args.length >= 6 ? parseScale(args[5]) : new Tuple<>(-1, -1);
} else { }
scale = args.length >= 5 ? parseScale(args[4]) : new Tuple<>(-1, -1); else {
} scale = args.length >= 5 ? parseScale(args[4]) : new Tuple<>(-1, -1);
} else { }
scale = args.length >= 3 ? parseScale(args[2]) : new Tuple<>(-1, -1); }
} else {
scale = args.length >= 3 ? parseScale(args[2]) : new Tuple<>(-1, -1);
if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) { }
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Filename contains illegal character.");
return null; if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) {
} MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Filename contains illegal character.");
return null;
if (!getPlugin().hasImage(filename)) { }
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "No image with this name exists.");
return null; if (!getPlugin().hasImage(filename)) {
} MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "No image with this name exists.");
return null;
Player player = (Player) sender; }
player.setMetadata(ImageMaps.PLACEMENT_METADATA, new FixedMetadataValue(getPlugin(), new PlacementData(filename, isInvisible, isFixed, isGlowing, scale)));
Player player = (Player) sender;
Tuple<Integer, Integer> size = getPlugin().getImageSize(filename, scale); player.setMetadata(ImageMaps.PLACEMENT_METADATA,
MessageUtil.sendMessage(getPlugin(), new FixedMetadataValue(getPlugin(),
sender, new PlacementData(filename, isInvisible, isFixed, isGlowing, scale)));
MessageLevel.NORMAL,
String.format("Started placing of %s. It needs a %d by %d area.", args[1], size.getKey(), size.getValue())); Tuple<Integer, Integer> size = getPlugin().getImageSize(filename, scale);
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Right click on the block, that should be the upper left corner."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
return null; String.format("Started placing of %s. It needs a %d by %d area.", args[1],
} size.getKey(), size.getValue()));
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
@Override "Right click on the block, that should be the upper left corner.");
public void help(CommandSender sender) { return null;
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Starts placing an image."); }
if (getPlugin().isGlowingSupported()) { @Override
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap place <filename> [frameInvisible] [frameFixed] [frameGlowing] [size]"); public void help(CommandSender sender) {
} else if (getPlugin().isInvisibilitySupported()) { MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Starts placing an image.");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap place <filename> [frameInvisible] [frameFixed] [size]");
} else { if (getPlugin().isGlowingSupported()) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap place <filename> [size]"); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO,
} "Usage: /imagemap place <filename> [frameInvisible] [frameFixed] [frameGlowing] [size]");
}
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Size format: XxY -> 5x2, use -1 for default"); else if (getPlugin().isInvisibilitySupported()) {
MessageUtil.sendMessage(getPlugin(), MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO,
sender, "Usage: /imagemap place <filename> [frameInvisible] [frameFixed] [size]");
MessageLevel.NORMAL, }
"The plugin will scale the map to not be larger than the given size while maintaining the aspect ratio."); else {
MessageUtil.sendMessage(getPlugin(), MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap place <filename> [size]");
sender, }
MessageLevel.NORMAL,
"It's recommended to avoid the size function in favor of using properly sized source images."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
} "Size format: XxY -> 5x2, use -1 for default");
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
private static Tuple<Integer, Integer> parseScale(String string) { "The plugin will scale the map to not be larger than the given size while maintaining the aspect ratio.");
String[] tmp = string.split("x"); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"It's recommended to avoid the size function in favor of using properly sized source images.");
if (tmp.length < 2) }
return new Tuple<>(-1, -1);
private static Tuple<Integer, Integer> parseScale(String string) {
return new Tuple<>(Utils.parseIntegerOrDefault(tmp[0], -1), Utils.parseIntegerOrDefault(tmp[1], -1)); String[] tmp = string.split("x");
}
if (tmp.length < 2)
@Override return new Tuple<>(-1, -1);
protected List<String> onTabComplete(CommandSender sender, String[] args) {
if (args.length > 2 && !getPlugin().isInvisibilitySupported() return new Tuple<>(Utils.parseIntegerOrDefault(tmp[0], -1), Utils.parseIntegerOrDefault(tmp[1], -1));
|| args.length > 4 && !getPlugin().isGlowingSupported()) { }
return Collections.emptyList();
} @Override
protected List<String> onTabComplete(CommandSender sender, String[] args) {
switch (args.length) { if (args.length > 2 && !getPlugin().isInvisibilitySupported()
case 2: || args.length > 4 && !getPlugin().isGlowingSupported()) {
return Utils.getMatches(args[1], new File(plugin.getDataFolder(), "images").list()); return Collections.emptyList();
case 3: }
return Utils.getMatches(args[2], Arrays.asList("true", "false"));
case 4: switch (args.length) {
return Utils.getMatches(args[3], Arrays.asList("true", "false")); case 2:
case 5: return Utils.getMatches(args[1], new File(plugin.getDataFolder(), "images").list());
return Utils.getMatches(args[4], Arrays.asList("true", "false")); case 3:
default: return Utils.getMatches(args[2], Arrays.asList("true", "false"));
return Collections.emptyList(); case 4:
} return Utils.getMatches(args[3], Arrays.asList("true", "false"));
} case 5:
} return Utils.getMatches(args[4], Arrays.asList("true", "false"));
default:
return Collections.emptyList();
}
}
}

View File

@ -1,61 +1,64 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.Utils; import de.craftlancer.core.Utils;
import de.craftlancer.core.util.MessageLevel; import de.craftlancer.core.util.MessageLevel;
import de.craftlancer.core.util.MessageUtil; import de.craftlancer.core.util.MessageUtil;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.io.File; import java.io.File;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class ImageMapReloadCommand extends ImageMapSubCommand { public class ImageMapReloadCommand extends ImageMapSubCommand {
public ImageMapReloadCommand(ImageMaps plugin) { public ImageMapReloadCommand(ImageMaps plugin) {
super("imagemap.reload", plugin, true); super("imagemap.reload", plugin, true);
} }
@Override @Override
protected String execute(CommandSender sender, Command cmd, String label, String[] args) { protected String execute(CommandSender sender, Command cmd, String label, String[] args) {
if (!checkSender(sender)) { if (!checkSender(sender)) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You can't run this command.");
return null; return null;
} }
if (args.length < 2) { if (args.length < 2) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "You must specify a file name.");
return null; return null;
} }
String filename = args[1]; String filename = args[1];
if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) { if (filename.contains("/") || filename.contains("\\") || filename.contains(":")) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Filename contains illegal character."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.WARNING, "Filename contains illegal character.");
return null; return null;
} }
if (getPlugin().reloadImage(filename)) if (getPlugin().reloadImage(filename))
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Image reloaded."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Image reloaded.");
else else
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Image couldn't be reloaded (does it exist?)."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"Image couldn't be reloaded (does it exist?).");
return null;
} return null;
}
@Override
public void help(CommandSender sender) { @Override
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Reloads an image from disk, to be used when the file changed."); public void help(CommandSender sender) {
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL, "Avoid resolution changes, since they won't be scaled."); MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap reload <filename>"); "Reloads an image from disk, to be used when the file changed.");
} MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.NORMAL,
"Avoid resolution changes, since they won't be scaled.");
@Override MessageUtil.sendMessage(getPlugin(), sender, MessageLevel.INFO, "Usage: /imagemap reload <filename>");
protected List<String> onTabComplete(CommandSender sender, String[] args) { }
if (args.length == 2)
return Utils.getMatches(args[1], new File(plugin.getDataFolder(), "images").list()); @Override
protected List<String> onTabComplete(CommandSender sender, String[] args) {
return Collections.emptyList(); if (args.length == 2)
} return Utils.getMatches(args[1], new File(plugin.getDataFolder(), "images").list());
} return Collections.emptyList();
}
}

View File

@ -1,79 +1,69 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.LambdaRunnable; import de.craftlancer.core.LambdaRunnable;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.map.MapCanvas; import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapPalette; import org.bukkit.map.MapPalette;
import org.bukkit.map.MapRenderer; import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView; import org.bukkit.map.MapView;
import java.awt.geom.AffineTransform; import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp; import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
public class ImageMapRenderer extends MapRenderer { public class ImageMapRenderer extends MapRenderer {
private ImageMaps plugin; private ImageMaps plugin;
private BufferedImage image = null; private BufferedImage image = null;
private boolean first = true; private boolean first = true;
private final int x; private final int x;
private final int y; private final int y;
private final double scale; private final double scale;
public ImageMapRenderer(ImageMaps plugin, BufferedImage image, int x, int y, double scale) { public ImageMapRenderer(ImageMaps plugin, BufferedImage image, int x, int y, double scale) {
this.plugin = plugin; this.plugin = plugin;
this.x = x; this.x = x;
this.y = y; this.y = y;
this.scale = scale; this.scale = scale;
recalculateInput(image); recalculateInput(image);
} }
public void recalculateInput(BufferedImage input) { public void recalculateInput(BufferedImage input) {
if (x * ImageMaps.MAP_WIDTH > Math.round(input.getWidth() * scale) || y * ImageMaps.MAP_HEIGHT > Math.round(input.getHeight() * scale)) if (x * ImageMaps.MAP_WIDTH > Math.round(input.getWidth() * scale)
return; || y * ImageMaps.MAP_HEIGHT > Math.round(input.getHeight() * scale))
return;
int x1 = (int) Math.floor(x * ImageMaps.MAP_WIDTH / scale);
int y1 = (int) Math.floor(y * ImageMaps.MAP_HEIGHT / scale); int x1 = (int) Math.floor(x * ImageMaps.MAP_WIDTH / scale);
int y1 = (int) Math.floor(y * ImageMaps.MAP_HEIGHT / scale);
int x2 = (int) Math.ceil(Math.min(input.getWidth(), ((x + 1) * ImageMaps.MAP_WIDTH / scale)));
int y2 = (int) Math.ceil(Math.min(input.getHeight(), ((y + 1) * ImageMaps.MAP_HEIGHT / scale))); int x2 = (int) Math.ceil(Math.min(input.getWidth(), ((x + 1) * ImageMaps.MAP_WIDTH / scale)));
int y2 = (int) Math.ceil(Math.min(input.getHeight(), ((y + 1) * ImageMaps.MAP_HEIGHT / scale)));
if (x2 - x1 <= 0 || y2 - y1 <= 0)
return; if (x2 - x1 <= 0 || y2 - y1 <= 0)
return;
this.image = input.getSubimage(x1, y1, x2 - x1, y2 - y1);
this.image = input.getSubimage(x1, y1, x2 - x1, y2 - y1);
if (scale != 1D) {
BufferedImage resized = new BufferedImage(ImageMaps.MAP_WIDTH, ImageMaps.MAP_HEIGHT, input.getType() == 0 ? image.getType() : input.getType()); if (scale != 1D) {
AffineTransform at = new AffineTransform(); BufferedImage resized = new BufferedImage(ImageMaps.MAP_WIDTH, ImageMaps.MAP_HEIGHT,
at.scale(scale, scale); input.getType() == 0 ? image.getType() : input.getType());
AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); AffineTransform at = new AffineTransform();
this.image = scaleOp.filter(this.image, resized); at.scale(scale, scale);
} AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
this.image = scaleOp.filter(this.image, resized);
first = true; }
}
first = true;
@Override }
public void render(MapView view, MapCanvas canvas, Player player) {
if (image != null && first) { @Override
new LambdaRunnable(() -> { public void render(MapView view, MapCanvas canvas, Player player) {
@SuppressWarnings("deprecation") if (image != null && first) {
byte[] imageData = MapPalette.imageToBytes(image); new LambdaRunnable(() -> canvas.drawImage(0, 0, image)).runTaskLater(plugin, System.nanoTime() % 60);
// spread out pseudo randomly in a very naive way
new LambdaRunnable(() -> { first = false;
for (int x2 = 0; x2 < image.getWidth(null); ++x2) { }
for (int y2 = 0; y2 < image.getHeight(null); ++y2) { }
canvas.setPixel(x2, y2, imageData[y2 * image.getWidth(null) + x2]);
} }
}
}).runTaskLater(plugin, System.nanoTime() % 20);
// spread out pseudo randomly in a very naive way
}).runTaskAsynchronously(plugin);
first = false;
}
}
}

View File

@ -1,15 +1,15 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.command.SubCommand; import de.craftlancer.core.command.SubCommand;
public abstract class ImageMapSubCommand extends SubCommand { public abstract class ImageMapSubCommand extends SubCommand {
public ImageMapSubCommand(String permission, ImageMaps plugin, boolean console) { public ImageMapSubCommand(String permission, ImageMaps plugin, boolean console) {
super(permission, plugin, console); super(permission, plugin, console);
} }
@Override @Override
public ImageMaps getPlugin() { public ImageMaps getPlugin() {
return (ImageMaps) super.getPlugin(); return (ImageMaps) super.getPlugin();
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,117 +1,118 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
/** /**
* Called when an image is attempted to be placed. * Called when an image is attempted to be placed.
*/ */
public class ImagePlaceEvent extends Event implements Cancellable { public class ImagePlaceEvent extends Event implements Cancellable {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
private final Player player; private final Player player;
private final Block block; private final Block block;
private final BlockFace widthDirection; private final BlockFace widthDirection;
private final BlockFace heightDirection; private final BlockFace heightDirection;
private final int width; private final int width;
private final int height; private final int height;
private final PlacementData cache; private final PlacementData cache;
private boolean cancelled; private boolean cancelled;
public ImagePlaceEvent(Player player, Block block, BlockFace widthDirection, BlockFace heightDirection, int width, int height, PlacementData cache) { public ImagePlaceEvent(Player player, Block block, BlockFace widthDirection, BlockFace heightDirection, int width,
this.player = player; int height, PlacementData cache) {
this.block = block; this.player = player;
this.widthDirection = widthDirection; this.block = block;
this.heightDirection = heightDirection; this.widthDirection = widthDirection;
this.width = width; this.heightDirection = heightDirection;
this.height = height; this.width = width;
this.cache = cache; this.height = height;
} this.cache = cache;
}
/**
* The player attempting to place the image /**
* * The player attempting to place the image
* @return the player attempting to place the image *
*/ * @return the player attempting to place the image
public Player getPlayer() { */
return player; public Player getPlayer() {
} return player;
}
/**
* The initial block the image is placed against. /**
* * The initial block the image is placed against.
* @return the initial block the image is placed against *
*/ * @return the initial block the image is placed against
public Block getBlock() { */
return block; public Block getBlock() {
} return block;
}
/**
* The direction in which maps are placed in the height direction of the image. /**
* * The direction in which maps are placed in the height direction of the image.
* @return the height direction of the map placement *
*/ * @return the height direction of the map placement
public BlockFace getHeightDirection() { */
return heightDirection; public BlockFace getHeightDirection() {
} return heightDirection;
}
/**
* The direction in which maps are placed in the width direction of the image. /**
* * The direction in which maps are placed in the width direction of the image.
* @return the width direction of the map placement *
*/ * @return the width direction of the map placement
public BlockFace getWidthDirection() { */
return widthDirection; public BlockFace getWidthDirection() {
} return widthDirection;
}
/**
* The width of the image in maps /**
* * The width of the image in maps
* @return the width of the image in maps *
*/ * @return the width of the image in maps
public int getWidth() { */
return width; public int getWidth() {
} return width;
}
/**
* The height of the image in maps /**
* * The height of the image in maps
* @return the height of the image in maps *
*/ * @return the height of the image in maps
public int getHeight() { */
return height; public int getHeight() {
} return height;
}
/**
* The placement data used to place the image /**
* * The placement data used to place the image
* @return the placement data *
*/ * @return the placement data
public PlacementData getCacheEntry() { */
return cache; public PlacementData getCacheEntry() {
} return cache;
}
@Override
public boolean isCancelled() { @Override
return cancelled; public boolean isCancelled() {
} return cancelled;
}
@Override
public void setCancelled(boolean cancel) { @Override
this.cancelled = cancel; public void setCancelled(boolean cancel) {
} this.cancelled = cancel;
}
@Override
public HandlerList getHandlers() { @Override
return getHandlerList(); public HandlerList getHandlers() {
} return getHandlerList();
}
public static HandlerList getHandlerList() {
return handlers; public static HandlerList getHandlerList() {
} return handlers;
} }
}

View File

@ -1,80 +1,80 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
import de.craftlancer.core.util.Tuple; import de.craftlancer.core.util.Tuple;
/** /**
* Data associated with placing an image. * Data associated with placing an image.
*/ */
public class PlacementData { public class PlacementData {
private final String filename; private final String filename;
private final boolean isInvisible; private final boolean isInvisible;
private final boolean isFixed; private final boolean isFixed;
private final boolean isGlowing; private final boolean isGlowing;
private final Tuple<Integer, Integer> scale; private final Tuple<Integer, Integer> scale;
public PlacementData(String filename, boolean isInvisible, boolean isFixed, boolean isGlowing, Tuple<Integer, Integer> scale) { public PlacementData(String filename, boolean isInvisible, boolean isFixed, boolean isGlowing,
this.filename = filename; Tuple<Integer, Integer> scale) {
this.isInvisible = isInvisible; this.filename = filename;
this.isFixed = isFixed; this.isInvisible = isInvisible;
this.isGlowing = isGlowing; this.isFixed = isFixed;
this.scale = scale; this.isGlowing = isGlowing;
} this.scale = scale;
}
/**
* The file name of the image to be placed /**
* * The file name of the image to be placed
* @return the file name of the image *
*/ * @return the file name of the image
public String getFilename() { */
return filename; public String getFilename() {
} return filename;
}
/**
* Whether the placed item frame will have the "fixed" property set. /**
* A fixed frame can't be destroyed or modified by survival players. * Whether the placed item frame will have the "fixed" property set. A fixed frame can't be destroyed or modified by
* <p> * survival players.
* Only supported in 1.16 or higher! * <p>
* * Only supported in 1.16 or higher!
* @return whether the placed frames will be fixed or not *
*/ * @return whether the placed frames will be fixed or not
public boolean isFixed() { */
return isFixed; public boolean isFixed() {
} return isFixed;
}
/**
* Whether the placed item frame will have the "invisible" property set. /**
* An invisible frame won't be rendered, leaving only the item/map visible. * Whether the placed item frame will have the "invisible" property set. An invisible frame won't be rendered,
* <p> * leaving only the item/map visible.
* Only supported in 1.16 or higher! * <p>
* * Only supported in 1.16 or higher!
* @return whether the placed frames will be invisible or not *
*/ * @return whether the placed frames will be invisible or not
public boolean isInvisible() { */
return isInvisible; public boolean isInvisible() {
} return isInvisible;
}
/** /**
* Whether the placed item frame will be a glowing one. * Whether the placed item frame will be a glowing one.
* <p> * <p>
* Only supported in 1.17 or higher! * Only supported in 1.17 or higher!
* *
* @return whether the placed frames will be a glowing one * @return whether the placed frames will be a glowing one
*/ */
public boolean isGlowing() { public boolean isGlowing() {
return isGlowing; return isGlowing;
} }
/** /**
* The <b>requested</b> size of the image. The actual size might be smaller * The <b>requested</b> size of the image. The actual size might be smaller since the plugin won't modify aspect
* since the plugin won't modify aspect ratios. * ratios.
* <p> * <p>
* Values of -1 stand for the default value of an unscaled map. * Values of -1 stand for the default value of an unscaled map.
* *
* @return the requested size of the image * @return the requested size of the image
*/ */
public Tuple<Integer, Integer> getSize() { public Tuple<Integer, Integer> getSize() {
return scale; return scale;
} }
} }

View File

@ -1,11 +1,11 @@
package net.craftcitizen.imagemaps; package net.craftcitizen.imagemaps;
public enum PlacementResult { public enum PlacementResult {
INVALID_FACING, INVALID_FACING,
EVENT_CANCELLED, EVENT_CANCELLED,
INVALID_DIRECTION, INVALID_DIRECTION,
INSUFFICIENT_WALL, INSUFFICIENT_WALL,
INSUFFICIENT_SPACE, INSUFFICIENT_SPACE,
SUCCESS, SUCCESS,
OVERLAPPING_ENTITY; OVERLAPPING_ENTITY;
} }

View File

@ -1,48 +1,52 @@
main: net.craftcitizen.imagemaps.ImageMaps main: net.craftcitizen.imagemaps.ImageMaps
author: SydMontague author: SydMontague
version: ${project.version} version: ${project.version}
api-version: 1.13 api-version: 1.13
name: ImageMaps name: ImageMaps
commands: commands:
imagemap: imagemap:
description: ImageMaps plugin commands, place images on walls description: ImageMaps plugin commands, place images on walls
permission-message: You do not have permission to use this command. permission-message: You do not have permission to use this command.
usage: | usage: |
/imagemap place <filename> [frameVisible] [frameFixed] [frameGlowing] [size] - starts image placement /imagemap place <filename> [frameVisible] [frameFixed] [frameGlowing] [size] - starts image placement
/imagemap download <filename> <sourceURL> - downloads an image /imagemap download <filename> <sourceURL> - downloads an image
/imagemap delete <filename> - deletes an image /imagemap delete <filename> - deletes an image
/imagemap info <filename> - displays image info /imagemap info <filename> - displays image info
/imagemap reload <filename> - reloads an image from disk /imagemap reload <filename> - reloads an image from disk
/imagemap list [page] - lists all files in the images folder /imagemap list [page] - lists all files in the images folder
/imagemap help [command] - shows help /imagemap help [command] - shows help
permissions: permissions:
imagemaps.*: imagemaps.*:
default: op default: op
children: children:
imagemaps.place: true imagemaps.place: true
imagemaps.download: true imagemaps.download: true
imagemaps.delete: true imagemaps.delete: true
imagemaps.info: true imagemaps.info: true
imagemaps.list: true imagemaps.list: true
imagemaps.reload: true imagemaps.reload: true
imagemaps.help: true imagemaps.help: true
imagemaps.toggleFixed: true imagemaps.toggleFixed: true
imagemaps.toggleVisible: true imagemaps.toggleVisible: true
imagemaps.place: imagemaps.place:
default: op default: op
imagemaps.download: imagemaps.download:
default: op default: op
imagemaps.delete: imagemaps.delete:
default: op default: op
imagemaps.info: imagemaps.info:
default: op default: op
imagemaps.list: imagemaps.list:
default: op default: op
imagemaps.reload: imagemaps.reload:
default: op default: op
imagemaps.help: imagemaps.help:
default: op default: op
imagemaps.toggleFixed: imagemaps.toggleFixed:
default: op default: op
imagemaps.toggleVisible: imagemaps.toggleVisible:
default: op default: op
imagemaps.admin:
default: op
children:
imagemaps.*: true