Advertisement
perry206

Untitled

Jun 10th, 2014
243
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.56 KB | None | 0 0
  1. /*
  2. * Copyright 2014 Matthew Collins
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16.  
  17. package uk.co.thinkofdeath.thinkmap.bukkit;
  18.  
  19. import com.google.gson.Gson;
  20. import com.google.gson.GsonBuilder;
  21. import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
  22. import org.apache.commons.io.FileUtils;
  23. import org.bukkit.Chunk;
  24. import org.bukkit.World;
  25. import org.bukkit.command.Command;
  26. import org.bukkit.command.CommandSender;
  27. import org.bukkit.configuration.file.FileConfiguration;
  28. import org.bukkit.plugin.java.JavaPlugin;
  29. import uk.co.thinkofdeath.thinkmap.bukkit.textures.BufferedTexture;
  30. import uk.co.thinkofdeath.thinkmap.bukkit.textures.BufferedTextureFactory;
  31. import uk.co.thinkofdeath.thinkmap.bukkit.textures.TextureDetailsSerializer;
  32. import uk.co.thinkofdeath.thinkmap.bukkit.web.Packets;
  33. import uk.co.thinkofdeath.thinkmap.bukkit.web.WebHandler;
  34. import uk.co.thinkofdeath.thinkmap.bukkit.world.ChunkManager;
  35. import uk.co.thinkofdeath.thinkmap.textures.*;
  36. import uk.co.thinkofdeath.thinkmap.textures.mojang.MojangTextureProvider;
  37. import uk.co.thinkofdeath.thinkmap.textures.mojang.ZipTextureProvider;
  38.  
  39. import javax.imageio.ImageIO;
  40. import java.io.File;
  41. import java.io.FileInputStream;
  42. import java.io.IOException;
  43. import java.io.InputStream;
  44. import java.util.Date;
  45. import java.util.HashMap;
  46. import java.util.Map;
  47. import java.util.concurrent.ExecutorService;
  48. import java.util.concurrent.Executors;
  49. import java.util.concurrent.TimeUnit;
  50. import java.util.logging.Level;
  51.  
  52. public class ThinkMapPlugin extends JavaPlugin implements Runnable {
  53.  
  54. public static final String MINECRAFT_VERSION = "1.7.9";
  55. public static final int RESOURCE_VERSION = 1;
  56. public static final int WORLD_VERSION = 1;
  57.  
  58. private final Map<String, ChunkManager> chunkManagers = new HashMap<String, ChunkManager>();
  59. private WebHandler webHandler;
  60. private World targetWorld;
  61.  
  62. private final ExecutorService chunkExecutor = Executors.newFixedThreadPool(4);
  63.  
  64. private File resourceDir;
  65. private File worldDir;
  66. private Date startUpDate = new Date((System.currentTimeMillis() / 1000) * 1000);
  67.  
  68. @Override
  69. public void onEnable() {
  70. worldDir = new File(getDataFolder(), "worlds");
  71. getServer().getPluginManager().registerEvents(new Events(this), this);
  72. getServer().getScheduler().runTaskTimer(this, this, 20l, 20 * 2l);
  73.  
  74. for (World world : getServer().getWorlds()) {
  75. if (targetWorld == null) {
  76. targetWorld = world;
  77. getChunkManager(world);
  78. break; // TODO: Support multiple worlds
  79. }
  80. }
  81.  
  82. final FileConfiguration config = getConfig();
  83. config.options().copyDefaults(true);
  84. config.addDefault("webserver.port", 23333);
  85. config.addDefault("webserver.bind-address", "0.0.0.0");
  86. config.addDefault("resources.pack-name", "");
  87.  
  88. if (config.getInt("no-touchy.resource-version", 0) != RESOURCE_VERSION) {
  89. getLogger().info("Deleting ThinkMap-Resources due to a format update");
  90. config.set("no-touchy.resource-version", RESOURCE_VERSION);
  91. try {
  92. FileUtils.deleteDirectory(new File(getDataFolder(), "resources"));
  93. } catch (IOException e) {
  94. e.printStackTrace();
  95. }
  96. }
  97.  
  98. if (config.getInt("no-touchy.world-version", 0) != WORLD_VERSION) {
  99. getLogger().info("Deleting ThinkMap-Worlds due to a format update");
  100. config.set("no-touchy.world-version", WORLD_VERSION);
  101. try {
  102. FileUtils.deleteDirectory(worldDir);
  103. } catch (IOException e) {
  104. e.printStackTrace();
  105. }
  106. }
  107.  
  108. // Client settings
  109.  
  110. config.addDefault("client.hide-ores", false);
  111.  
  112. saveConfig();
  113.  
  114.  
  115. resourceDir = new File(getDataFolder(),
  116. "resources/"
  117. + (config.getString("resources.pack-name").length() == 0 ?
  118. "default" : config.getString("resources.pack-name"))
  119. );
  120.  
  121. // Resource loading
  122. final File blockInfo = new File(
  123. resourceDir,
  124. "blocks.json");
  125. if (blockInfo.exists()) {
  126. webHandler = new WebHandler(this);
  127. webHandler.start();
  128. } else {
  129. String resourcePack = config.getString("resources.pack-name");
  130. final File resourceFile = new File(getDataFolder(), resourcePack + ".zip");
  131. if (!resourceFile.exists()) {
  132. getLogger().log(Level.SEVERE, "Unable to find the resource pack "
  133. + config.getString("resources.pack-name"));
  134. resourcePack = "";
  135. }
  136. final String finalResourcePack = resourcePack;
  137. getServer().getScheduler().runTaskAsynchronously(this, new Runnable() {
  138. @Override
  139. public void run() {
  140. try {
  141. blockInfo.getParentFile().mkdirs();
  142. TextureFactory textureFactory = new BufferedTextureFactory();
  143. getLogger().info("Downloading textures. This may take some time");
  144. TextureProvider textureProvider =
  145. new MojangTextureProvider(MINECRAFT_VERSION, textureFactory);
  146.  
  147. try (InputStream in =
  148. getClassLoader().getResourceAsStream("textures/missing_texture.png")) {
  149. ((MojangTextureProvider) textureProvider).addTexture("missing_texture",
  150. textureFactory.fromInputStream(in));
  151. }
  152.  
  153. if (finalResourcePack.length() > 0) {
  154. textureProvider = new JoinedProvider(
  155. new ZipTextureProvider(
  156. new FileInputStream(resourceFile), textureFactory
  157. ),
  158. textureProvider
  159. );
  160. }
  161.  
  162. TextureStitcher stitcher = new TextureStitcher(textureProvider, textureFactory);
  163. getLogger().info("Stitching textures. The mapviewer will start after this " +
  164. "completes");
  165. long start = System.currentTimeMillis();
  166. StitchResult result = stitcher.stitch();
  167. // Save the result
  168. Gson gson = new GsonBuilder()
  169. .registerTypeAdapter(TextureDetails.class,
  170. new TextureDetailsSerializer())
  171. .create();
  172. HashMap<String, Object> info = new HashMap<String, Object>();
  173. info.put("textures", result.getDetails());
  174. info.put("textureImages", result.getOutput().length);
  175. FileUtils.writeStringToFile(
  176. blockInfo,
  177. gson.toJson(info)
  178. );
  179. int i = 0;
  180. for (Texture texture : result.getOutput()) {
  181. ImageIO.write(((BufferedTexture) texture).getImage(), "PNG",
  182. new File(resourceDir, "blocks_" + (i++) + ".png"));
  183. }
  184. getLogger().info("Stitching complete in " + (System.currentTimeMillis() -
  185. start) + "ms");
  186.  
  187. webHandler = new WebHandler(ThinkMapPlugin.this);
  188. webHandler.start();
  189. } catch (IOException e) {
  190. throw new RuntimeException(e);
  191. }
  192. }
  193. });
  194. }
  195. }
  196.  
  197. @Override
  198. public void onDisable() {
  199. if (webHandler != null) {
  200. webHandler.interrupt();
  201. }
  202. chunkExecutor.shutdown();
  203. try {
  204. chunkExecutor.awaitTermination(5, TimeUnit.SECONDS);
  205. } catch (InterruptedException e) {
  206. Thread.currentThread().interrupt();
  207. }
  208. chunkExecutor.shutdownNow();
  209. }
  210.  
  211. @Override
  212. public boolean onCommand(final CommandSender sender, Command command, String label, String[] args) {
  213. if (args.length == 1 && args[0].equals("forcegen")) {
  214. sender.sendMessage("Generating world data - Please wait");
  215. for (World world : getServer().getWorlds()) {
  216. sender.sendMessage("Generating world: " + world.getName());
  217. File worldFolder = new File(world.getWorldFolder(), "region");
  218. if (!worldFolder.exists()) {
  219. // handle nether/end
  220. worldFolder = new File(world.getWorldFolder(), String.format("DIM%d/region", world.getEnvironment().getId()));
  221. if (!worldFolder.exists()) {
  222. sender.sendMessage("Failed to generate: " + world.getName());
  223. continue;
  224. }
  225. }
  226. String[] regions = worldFolder.list();
  227. int i = 0;
  228. for (String region : regions) {
  229. if (!region.endsWith(".mca")) {
  230. continue;
  231. }
  232. String[] parts = region.split("\\.");
  233. int rx = Integer.parseInt(parts[1]);
  234. int rz = Integer.parseInt(parts[2]);
  235. for (int x = 0; x < 32; x++) {
  236. for (int z = 0; z < 32; z++) {
  237. int cx = (rx << 5) + x;
  238. int cz = (rz << 5) + z;
  239. boolean unload = !world.isChunkLoaded(cx, cz);
  240. if (world.loadChunk(cx, cz, false)) {
  241. Chunk chunk = world.getChunkAt(cx, cz);
  242. if (unload) {
  243. world.unloadChunkRequest(cx, cz);
  244. }
  245. }
  246. }
  247. }
  248. i++;
  249. sender.sendMessage(String.format("Progress: %d/%d", i, regions.length));
  250. }
  251.  
  252. }
  253. sender.sendMessage("Complete");
  254. }
  255. return true;
  256. }
  257.  
  258. public ExecutorService getChunkExecutor() {
  259. return chunkExecutor;
  260. }
  261.  
  262. public File getWorldDir() {
  263. return worldDir;
  264. }
  265.  
  266. public ChunkManager getChunkManager(World world) {
  267. synchronized (chunkManagers) {
  268. if (chunkManagers.containsKey(world.getName())) {
  269. return chunkManagers.get(world.getName());
  270. }
  271. ChunkManager chunkManager = new ChunkManager(this, world);
  272. chunkManagers.put(world.getName(), chunkManager);
  273. return chunkManager;
  274. }
  275. }
  276.  
  277. @Override
  278. public void run() {
  279. if (targetWorld == null) return;
  280. final BinaryWebSocketFrame frame = new BinaryWebSocketFrame(
  281. Packets.writeTimeUpdate((int) targetWorld.getTime())
  282. );
  283. sendAll(frame);
  284. }
  285.  
  286. public void sendAll(BinaryWebSocketFrame frame) {
  287. if (getWebHandler() == null) {
  288. return;
  289. }
  290. getWebHandler().getChannelGroup().writeAndFlush(frame);
  291. }
  292.  
  293.  
  294. public World getTargetWorld() {
  295. if (targetWorld == null) {
  296. targetWorld = getServer().getWorlds().get(0);
  297. }
  298. return targetWorld;
  299. }
  300.  
  301. public void setTargetWorld(World targetWorld) {
  302. this.targetWorld = targetWorld;
  303. }
  304.  
  305. public WebHandler getWebHandler() {
  306. return this.webHandler;
  307. }
  308.  
  309. public File getResourceDir() {
  310. return resourceDir;
  311. }
  312.  
  313. public Date getStartUpDate() {
  314. return startUpDate;
  315. }
  316. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement