Compare commits

...

138 Commits

Author SHA1 Message Date
FrozenCow 39db895b9d Fixed disable-webserver not being used (thanks for checking that Kilandor). 2011-02-24 00:58:40 +01:00
FrozenCow e6d2c4932a Reverted back to "== '13'" like flames suggested before. This seemed to raise incompatiblities for Firefox and Safari on Mac, not on Linux. 2011-02-24 00:38:46 +01:00
FrozenCow 00f55758c1 Changed version to 0.13. :D 2011-02-24 00:29:57 +01:00
FrozenCow ea64a55c04 Some dumb description changes in configuration. 2011-02-24 00:21:35 +01:00
FrozenCow fcbd76c591 Removed clock configuration. 2011-02-24 00:16:30 +01:00
FrozenCow 9a32485ca9 Small cleanup. 2011-02-24 00:16:10 +01:00
FrozenCow 20e954b905 Change for the inner nerd in me. 2011-02-24 00:06:36 +01:00
FrozenCow da4c456254 Merge remote-tracking branch 'flames/master' 2011-02-24 00:03:52 +01:00
FrozenCow 95bf263f11 Merge remote-tracking branch 'kilandor/master' 2011-02-24 00:02:15 +01:00
Jason Booth 774e013558 Fix jsonfile-interval should be 1 not 1000 2011-02-23 16:31:57 -06:00
Arthur Mayer b6ec0a2955 lechd updated override example 2011-02-23 23:28:28 +01:00
Arthur Mayer cdd30d95c5 lechd's new override style to let the sidebar always open and hides
also the icon
2011-02-23 23:03:26 +01:00
Arthur Mayer cc0bb3b509 fixed chat sending messages from web.
event.keyCode === '13', where the strict equal operator seem to break
safari, firefox and chrome (different value types? keydown event seem
not to provide either a string nor an integer)
2011-02-23 21:26:51 +01:00
FrozenCow 1d2cce6caa Simplified tile-mechanism again (a bit like hMod's version). 2011-02-23 14:06:13 +01:00
FrozenCow b7f6a5a39d Applied style-change of lechd. 2011-02-23 12:40:05 +01:00
FrozenCow 1cc43637ee Merge remote-tracking branch 'kilandor/master' into nowebserver
Conflicts:
	configuration.txt
	src/main/java/org/dynmap/DynmapPlayerListener.java
	src/main/java/org/dynmap/DynmapPlugin.java
	web/map.js
2011-02-22 17:58:39 +01:00
FrozenCow da7da17235 Applied some suggestions by JSLint. 2011-02-22 15:38:49 +01:00
FrozenCow b99f487567 Replaced onPlayerCommand by onCommand (server-consoles can now also be used to execute commands). 2011-02-22 14:51:40 +01:00
FrozenCow ccf6f2ac49 Player per world support @ client. 2011-02-22 14:49:03 +01:00
FrozenCow ca76b29fb9 Made Dynmap package not include subdirectory. 2011-02-22 14:09:14 +01:00
FrozenCow 40c7c9fa66 It's official, ima retard. 2011-02-22 09:17:38 +01:00
FrozenCow fae5014b4e Added commands to plugin.yml, removed disabledcommands and added fullrender <worldname>. 2011-02-22 00:42:37 +01:00
FrozenCow 0fbd0c0a44 Added commands to plugin.yml. 2011-02-21 22:39:21 +01:00
FrozenCow 8d0f509bfe Made MapTypes per World (instead of having MapTypes for all worlds). 2011-02-21 22:17:38 +01:00
FrozenCow 65f3ea4fe3 Used new Bukkit constructor format. 2011-02-21 16:22:16 +01:00
FrozenCow b097fb8321 Added entry for css overrides and cleaned up styles by lechd. 2011-02-20 23:55:16 +01:00
FrozenCow feb6d65d82 Merge remote-tracking branch 'flames/master' 2011-02-20 22:13:41 +01:00
FrozenCow cd4027495c New buttons and example override css by lechd. 2011-02-20 22:11:28 +01:00
Arthur Mayer 298c0f3391 corrected (hopefully) the chat response for show/hide commands 2011-02-20 20:06:07 +01:00
Arthur Mayer e15514291b only OPs can use fullrender. added response to chat for
hide/show/fillrender commands.
2011-02-20 19:49:05 +01:00
FrozenCow f80385e1af Added lechd's new images. 2011-02-20 18:47:18 +01:00
FrozenCow 618d1b05c9 Merge branch 'master' of https://github.com/flames/dynmap 2011-02-20 17:46:27 +01:00
alron aaa06bfc38 Automagic packages built. Love me for this. :) 2011-02-19 21:49:24 -08:00
Arthur Mayer ad07d68d7e added configuration option messagettl, TimeToLive for chatmessages, in
Milliseconds! 15seconds: messagettl: 15000
2011-02-20 02:11:44 +01:00
Arthur Mayer 02fb226350 removed forgotten comma 2011-02-20 02:02:45 +01:00
Arthur Mayer d7fe6072a5 a lot of changes. chat and ui related. thanks FrozenCow & lechd 2011-02-20 01:58:53 +01:00
Jason Booth 6ab82174a5 Added timestamp support to Update Tiles and Chat.
New web config to handle for jsonfile method
Modified webclient to handle timestamps to prevent duplication.
Removed duplicate code in JsonTimerTask.java
2011-02-19 18:55:01 -06:00
FrozenCow 83f334445b Made chatinput reset after send. 2011-02-19 21:16:14 +01:00
FrozenCow d5bd6ff038 Made sendmessage url relative. 2011-02-19 21:08:14 +01:00
Arthur Mayer 22cc46f4b8 many ui iprovements by lechd 2011-02-19 20:51:21 +01:00
FrozenCow 77539522f0 Merge branch 'master' of https://github.com/flames/dynmap 2011-02-19 16:31:36 +01:00
FrozenCow 2bd0052aa9 Added WebChat back to web. 2011-02-19 16:31:13 +01:00
FrozenCow c53e6058be Added debugging to configuration. Disabled by default. 2011-02-19 15:25:31 +01:00
Arthur Mayer 9b604d4e75 Merge remote branch 'choose_remote_name/master' into HEAD 2011-02-19 08:28:03 +01:00
Arthur Mayer 9d490cbcc8 removed my custom url, made it relative 2011-02-19 08:26:40 +01:00
FrozenCow 791341f210 Fixed httpserver thereby also more optimized. 2011-02-19 00:01:42 +01:00
FrozenCow 42d07d6ca2 Added quotes to login/out messages for yaml. 2011-02-19 00:01:21 +01:00
Arthur Mayer 61c6f4a086 corrected the json string in sendChat() 2011-02-18 20:15:18 +01:00
FrozenCow 723e7da8d3 Added stacktrace for errors. 2011-02-18 19:43:45 +01:00
FrozenCow d3cf795ebb Fixed stupid mistake with body of http requests. 2011-02-18 19:42:32 +01:00
Arthur Mayer 67baf5100c forgotten config change for chat 2011-02-18 18:46:48 +01:00
Arthur Mayer 56f126d5f2 uups. removed debug alert, added function call 2011-02-18 11:15:05 +01:00
Arthur Mayer 10f93c02c1 added chatSend() function 2011-02-18 10:21:55 +01:00
Arthur Mayer 5ddaf940ed chat interface added, config option changed from showchatballoons:
ture/false to showchat: balloons/modal
2011-02-18 07:08:29 +01:00
Arthur Mayer 7c917b729e added join and quit messages to chat 2011-02-18 05:30:49 +01:00
Arthur Mayer 00485ddcc2 fixed small bug/typo where players were not removed from player list
at quit game.
2011-02-18 01:28:58 +01:00
Arthur Mayer 55aeb3c583 added custom configuration to nether rendering, changed pom.xml, so
maven compiles dynmap.jar instead of dynamic-map.jar
2011-02-18 01:23:14 +01:00
FrozenCow 1388fa11e5 Some desperate attempts to make IE8 work. 2011-02-18 00:07:59 +01:00
FrozenCow b860c7dd0e Added pinning. 2011-02-18 00:07:51 +01:00
FrozenCow c67b2e5cc2 Added example to configuration. 2011-02-17 21:17:54 +01:00
FrozenCow 44748d7f07 Changed gui by lechd + map per world client-configuration. 2011-02-17 20:08:50 +01:00
Jason Booth 13099587e0 Fixed mistake with map updates only pulling interval+10 instead of interval+10000 2011-02-17 11:14:37 -06:00
Jason Booth 3916c363ae Fixed jsontimer-interval config not being used.
Change JsonTimerTask.java to use jsontimer-interval+10 to allow a buffer for late/delayed client requests(to prevent updated tiles info to be missing)
2011-02-17 10:05:07 -06:00
Jason Booth 77d9a88868 Fixed timer to be stopped onDisabled if it was started 2011-02-17 09:45:32 -06:00
Jason Booth e1f2ca26d6 Changed disable-webserver and jsonfile to default false 2011-02-17 09:38:08 -06:00
Jason Booth 3c1bde1092 Updated JsonTimerTask.java to be Multi-World Compatible 2011-02-17 09:33:27 -06:00
Jason Booth f7dbc89ab4 Merge branch 'master' of git://github.com/FrozenCow/dynmap
Conflicts:
	configuration.txt
	src/main/java/org/dynmap/DynmapPlugin.java
2011-02-17 08:54:23 -06:00
FrozenCow 909207ac26 Organized imports. 2011-02-15 21:44:08 +01:00
FrozenCow 99605ba433 Make sure request-body is skipped if not read. 2011-02-15 21:06:14 +01:00
FrozenCow ada9637d72 Added sendmessage handler (for chatting back). 2011-02-15 21:00:36 +01:00
FrozenCow 2d693b1ebf Improved HTTP performance and POST/PUT compatbility. 2011-02-15 21:00:04 +01:00
FrozenCow e900aca2e0 Added helper classes for HTTP. 2011-02-15 14:19:43 +01:00
FrozenCow 060d1092f9 Made clock configurable and split clocks from map. 2011-02-15 13:50:04 +01:00
FrozenCow 38df91bafe Report world for players in updates. 2011-02-15 13:38:46 +01:00
FrozenCow 18ad2e1d79 Removed copyrights through flames' css. 2011-02-15 13:33:40 +01:00
FrozenCow 5fb098259a focuschatballoons now defaults to false. 2011-02-15 13:08:33 +01:00
Daniel Chesters 24c9dfed41 if focuschatballoons is at false, disableAutoPan should be at true 2011-02-14 21:53:07 +01:00
FrozenCow a1c86bfabb Removed depricated time-images. 2011-02-14 00:02:52 +01:00
FrozenCow 49d45c653d Made clock and timeofday interchangable. 2011-02-14 00:01:20 +01:00
FrozenCow 42391cc4d5 Readded getMinecraftTime. 2011-02-13 23:30:19 +01:00
FrozenCow 3980ebefa1 Revert "Removed Clock"
This reverts commit 9ca8f8dc64e9a28da81a538a3578c2b2a8b34c88.
2011-02-13 23:27:37 +01:00
lishid 058ab0eea7 Transparent compass now 2011-02-13 23:27:37 +01:00
lishid 6e8160e576 Removed Clock 2011-02-13 23:27:37 +01:00
lishid 51e7420bdb Dynamic Time of the day Added 2011-02-13 23:27:37 +01:00
lishid 60ea503053 Added/Modified images 2011-02-13 23:27:37 +01:00
lishid f894c4945b Added/Modified images 2011-02-13 23:27:37 +01:00
lishid 7241b2be81 Added compass and TimeOfDay 2011-02-13 23:27:37 +01:00
unknown b729f28df4 initial commit 2011-02-13 23:27:37 +01:00
FrozenCow 1fc2cdb636 Force making directories on tile-rendering (needs cleaner fix). 2011-02-13 23:23:15 +01:00
FrozenCow b63369675d Re-added flushing again (oops). 2011-02-13 23:22:57 +01:00
FrozenCow a81665d38d Fixed time being reported of the correct world. 2011-02-13 22:46:45 +01:00
FrozenCow db9ced3394 Fixed tiles not updating. 2011-02-13 22:42:08 +01:00
FrozenCow d5d737d385 Fixed 'unknown command' being shown after fullrender. 2011-02-13 22:34:38 +01:00
FrozenCow f3a1d53277 Added maximumheight to configuration for somewhat better nether rendering. 2011-02-13 22:33:33 +01:00
FrozenCow 9a2b9ccac0 Fixed HttpServer some more. 2011-02-13 22:30:24 +01:00
FrozenCow 835e566151 Some improvements to HttpServer. 2011-02-13 02:56:00 +01:00
FrozenCow 2380325975 Added automatically creating tiles directory. 2011-02-13 01:33:05 +01:00
FrozenCow 100f3e0590 Added multiworld update support along with client-side support. 2011-02-13 01:19:47 +01:00
FrozenCow 5b0171c459 Server-side multiworld support with several improvements overal. 2011-02-12 23:47:00 +01:00
FrozenCow 2fd91ef94b Changed tilepath to tilespath in configuration. 2011-02-11 06:28:17 -08:00
FrozenCow 403a2acc53 Added default player-faces. 2011-02-10 01:20:50 +01:00
Jason Booth 959040e5f4 Merge branch 'master' of git://github.com/FrozenCow/dynmap 2011-02-09 14:24:13 -06:00
Jason Booth 2f6930bc17 Removed System debug messages.
Added missing JsonTimerTask.java
2011-02-09 11:57:46 -06:00
Jason Booth fb01f6ecf7 New config to Disable Webserver
New feature and config to output JSON to file
2011-02-09 11:35:09 -06:00
FrozenCow 29517e9a24 Fixed handling invalid http requests. 2011-02-09 17:22:16 +01:00
FrozenCow d566fccb1e Fixed rendering zoomedout tiles. 2011-02-09 13:25:06 +01:00
FrozenCow b2f6ae5132 Disabled fullrender by default. 2011-02-09 01:03:31 +01:00
FrozenCow 5c209c2a5e Renamed y to z in DynmapChunk. 2011-02-09 00:42:16 +01:00
FrozenCow fb1b5df3d0 Made zoomed-rendering make use of existing tile-files instead of keeping those tiles in memory. 2011-02-08 23:38:57 +01:00
FrozenCow 38ee8657e8 Better exception handling. 2011-02-08 20:59:51 +01:00
FrozenCow 89c8d564a4 Made use of newly introduced unloadChunk in BukkitAPI + removal of unstable features. 2011-02-08 20:27:37 +01:00
FrozenCow b31bb14452 disabledcommands can now be empty. 2011-02-07 22:26:55 +01:00
FrozenCow 553eb7952d Added ability to disable commands in configuration. 2011-02-07 17:25:16 +01:00
FrozenCow 421b91058a Merge https://github.com/kosiini/dynmap 2011-02-07 17:01:39 +01:00
Janne Sinisalo 100a03274c Compile fix for multiworld
Updated getWorlds()[0] to getWorlds().get(0)
2011-02-07 17:42:11 +02:00
FrozenCow d2b7169884 Workaround for IE's retardness (not yet tested). 2011-02-06 15:09:15 +01:00
FrozenCow 3e398e9124 Made updates in JSON format. Combined chat and tile queues into one UpdateQueue. Fixed UpdateQueue. 2011-02-06 03:00:51 +01:00
FrozenCow 7c257af454 Fixed Json stringify. 2011-02-06 02:00:27 +01:00
FrozenCow a937d13086 Added reflection-support for stringifyJson. 2011-02-05 21:09:49 +01:00
FrozenCow d651d58d63 Moved stringifyJson to Json class. 2011-02-05 21:02:39 +01:00
FrozenCow 9a655676ab Moved FileHandler to handlers package. 2011-02-05 20:54:28 +01:00
FrozenCow debf5bcc57 Renamed WebServer to HttpServer and WebServerRequest to HttpServerConnection. 2011-02-05 20:53:42 +01:00
FrozenCow 2a79aea7bb Moved handlers to their own (independent) classes. 2011-02-05 20:51:20 +01:00
FrozenCow 883eba6890 Removed debugging + small fix. 2011-02-05 19:57:32 +01:00
FrozenCow 226cc5f86c More work on HttpServer. 2011-02-05 19:51:48 +01:00
FrozenCow bf0edea7e2 Initial http-server work. 2011-02-05 19:51:48 +01:00
FrozenCow 711341ec47 Oops, forgot comma. 2011-02-05 19:51:06 +01:00
FrozenCow 14a3d32205 Used colors.txt from lechd. 2011-02-05 17:49:11 +01:00
FrozenCow 9f555bd4bb Added 'loadChunks' to configuration. 2011-02-05 03:03:52 +01:00
FrozenCow 902cc87458 Added 'focuschatballoons' to config influenced by Incendia's suggestion. 2011-02-05 02:59:03 +01:00
FrozenCow 9951baf8b5 Made tiles use nearest-neighbor filtering in Firefox and IE as suggested by lechd. 2011-02-05 02:54:06 +01:00
FrozenCow 335109d8c7 Added pumpkin colors as suggested by lechd. 2011-02-05 02:53:22 +01:00
FrozenCow 3940b91d0e Applied Eclipse formatting. 2011-02-05 02:25:18 +01:00
FrozenCow 4f138a56da Removed comments. 2011-02-05 02:11:49 +01:00
FrozenCow c8cf39a440 Added unstable fullmap rendering. Also... messed up formatting by pressing ctrl+shift+f in eclipse, sigh 2011-02-05 02:01:04 +01:00
FrozenCow 138aed8c33 Added chunk loading to rendering. 2011-02-04 23:12:55 +01:00
FrozenCow fde56275fe Changed day/night time as suggested by lologarithm. 2011-02-02 11:58:14 +01:00
FrozenCow 13e829cda0 Updated Server.getTime to World.getTime (to reflect Bukkit's changes) 2011-02-02 11:40:49 +01:00
101 changed files with 4228 additions and 2655 deletions
+34
View File
@@ -0,0 +1,34 @@
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>build</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>tar.bz2</format>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>README*</include>
<include>LICENSE*</include>
<include>NOTICE*</include>
<include>LICENSE*</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.basedir}/web</directory>
<outputDirectory>/dynmap/web</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory>/dynmap/</outputDirectory>
<includes>
<include>configuration.txt</include></includes></fileSet>
</fileSets>
<files>
<file>
<source>${project.build.directory}/${artifactId}-${version}.jar</source>
<outputDirectory>/</outputDirectory>
<destName>dynmap.jar</destName></file></files>
</assembly>
+101 -45
View File
@@ -1,45 +1,101 @@
# All paths in this configuration file are relative to Dynmap's data-folder: minecraft_server/plugins/dynmap/
# How often a tile gets rendered (in seconds).
renderinterval: 1
# The path where the tile-files are placed.
tilepath: web/tiles
# The path where the web-files are located.
webpath: web
# The network-interface the webserver will bind to (0.0.0.0 for all interfaces, 127.0.0.1 for only local access).
webserver-bindaddress: 0.0.0.0
# The TCP-port the webserver will listen on.
webserver-port: 8123
# The maptypes Dynmap will use to render.
maps:
- class: org.dynmap.kzedmap.KzedMap
renderers:
- class: org.dynmap.kzedmap.DefaultTileRenderer
prefix: t
- class: org.dynmap.kzedmap.CaveTileRenderer
prefix: ct
web:
# Interval the browser should poll for updates.
updaterate: 2000
showchatballoons: true
showplayerfacesonmap: true
showplayerfacesinmenu: true
# The name of the map shown when opening Dynmap's page (must be in menu).
defaultmap: defaultmap
# The maps shown in the menu.
shownmaps:
- type: KzedMapType
name: defaultmap
prefix: t
- type: KzedMapType
name: cavemap
prefix: ct
# All paths in this configuration file are relative to Dynmap's data-folder: minecraft_server/plugins/dynmap/
# How often a tile gets rendered (in seconds).
renderinterval: 1
# The path where the tile-files are placed.
tilespath: web/tiles
# The path where the web-files are located.
webpath: web
# The network-interface the webserver will bind to (0.0.0.0 for all interfaces, 127.0.0.1 for only local access).
webserver-bindaddress: 0.0.0.0
# The TCP-port the webserver will listen on.
webserver-port: 8123
# Disables Webserver portion of Dynmap (Advanced users only)
disable-webserver: false
# Writes JSON to file in the webpath
jsonfile: false
# How often the json file gets written to(in seconds)
jsonfile-interval: 1
# The maptypes Dynmap will use to render.
worlds:
- name: world
maps:
- class: org.dynmap.kzedmap.KzedMap
renderers:
- class: org.dynmap.kzedmap.DefaultTileRenderer
prefix: t
maximumheight: 127
- class: org.dynmap.kzedmap.CaveTileRenderer
prefix: ct
maximumheight: 127
- name: nether
maps:
- class: org.dynmap.kzedmap.KzedMap
renderers:
- class: org.dynmap.kzedmap.DefaultTileRenderer
prefix: nt
maximumheight: 64
web:
# Handles the clientside updates differently only enable if using jsonfile
jsonfile: false
# Interval the browser should poll for updates.
updaterate: 2000
# showchat: modal/balloons
showchat: modal
messagettl: 15000
showplayerfacesonmap: true
showplayerfacesinmenu: true
focuschatballoons: false
joinmessage: "%playername% joined"
quitmessage: "%playername% quit"
defaultworld: world
worlds:
- title: World
name: world
maps:
- type: KzedMapType
title: Surface
name: surface
prefix: t
- type: KzedMapType
title: Cave
name: cave
prefix: ct
- title: Nether
name: nether
maps:
- type: KzedMapType
title: Surface
name: nether
prefix: nt
# Example:
#- title: Other World # With what name the world is displayed.
# name: world_other # The actual name of the world (equal to your directory-name).
# maps:
# - type: KzedMapType # The type (or perspective) of the map. At the moment, there are no others than KzedMapType.
# title: Surface # The name of the map that will be displayed.
# name: surface # The actual name of the map (should be unique for this world).
# prefix: t # The prefix of the tile-files that are generated.
# icon: block_other.png # Sets a custom icon for the map. (optional)
# - type: KzedMapType
# title: Cave
# name: cave
# prefix: ct
# Enables debugging.
#debuggers:
# - class: org.dynmap.debug.LogDebugger
# - class: org.dynmap.debug.BukkitPlayerDebugger
+20 -3
View File
@@ -1,8 +1,8 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" 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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.bukkit</groupId>
<artifactId>dynamic-map</artifactId>
<version>0.0.1-SNAPSHOT</version>
<artifactId>dynmap</artifactId>
<version>0.13</version>
<name>DynamicMap</name>
<url>http://www.bukkit.org</url>
<build>
@@ -16,7 +16,24 @@
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>build</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
@@ -0,0 +1,108 @@
package org.dynmap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AsynchronousQueue<T> {
protected static final Logger log = Logger.getLogger("Minecraft");
private Object lock = new Object();
private Thread thread;
private LinkedList<T> queue = new LinkedList<T>();
private Set<T> set = new HashSet<T>();
private Handler<T> handler;
private int dequeueTime;
public AsynchronousQueue(Handler<T> handler, int dequeueTime) {
this.handler = handler;
this.dequeueTime = dequeueTime;
}
public boolean push(T t) {
synchronized (lock) {
if (set.add(t)) {
queue.addLast(t);
return true;
}
return false;
}
}
private T pop() {
synchronized (lock) {
try {
T t = queue.removeFirst();
if (!set.remove(t)) {
// This should never happen.
}
return t;
} catch (NoSuchElementException e) {
return null;
}
}
}
public int size() {
return set.size();
}
public void start() {
synchronized (lock) {
thread = new Thread(new Runnable() {
@Override
public void run() {
running();
}
});
thread.start();
try {
thread.setPriority(Thread.MIN_PRIORITY);
} catch (SecurityException e) {
log.info("Failed to set minimum priority for worker thread!");
}
}
}
public void stop() {
synchronized (lock) {
if (thread == null)
return;
Thread oldThread = thread;
thread = null;
log.info("Stopping map renderer...");
try {
oldThread.join();
} catch (InterruptedException e) {
log.info("Waiting for map renderer to stop is interrupted");
}
}
}
private void running() {
try {
while (Thread.currentThread() == thread) {
T t = pop();
if (t != null) {
handler.handle(t);
}
sleep(dequeueTime);
}
} catch (Exception ex) {
log.log(Level.SEVERE, "Exception on rendering-thread", ex);
}
}
private void sleep(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
}
}
}
+88 -93
View File
@@ -2,115 +2,110 @@ package org.dynmap;
import java.util.HashMap;
public class Cache<K, V>
{
private final int size;
private int len;
public class Cache<K, V> {
private final int size;
private int len;
private CacheNode head;
private CacheNode tail;
private CacheNode head;
private CacheNode tail;
private class CacheNode
{
public CacheNode prev;
public CacheNode next;
public K key;
public V value;
private class CacheNode {
public CacheNode prev;
public CacheNode next;
public K key;
public V value;
public CacheNode(K key, V value)
{
this.key = key;
this.value = value;
prev = null;
next = null;
}
public CacheNode(K key, V value) {
this.key = key;
this.value = value;
prev = null;
next = null;
}
public void unlink()
{
if(prev == null) {
head = next;
} else {
prev.next = next;
}
public void unlink() {
if (prev == null) {
head = next;
} else {
prev.next = next;
}
if(next == null) {
tail = prev;
} else {
next.prev = prev;
}
if (next == null) {
tail = prev;
} else {
next.prev = prev;
}
prev = null;
next = null;
prev = null;
next = null;
len --;
}
len--;
}
public void append()
{
if(tail == null) {
head = this;
tail = this;
} else {
tail.next = this;
prev = tail;
tail = this;
}
public void append() {
if (tail == null) {
head = this;
tail = this;
} else {
tail.next = this;
prev = tail;
tail = this;
}
len ++;
}
}
len++;
}
}
private HashMap<K, CacheNode> map;
private HashMap<K, CacheNode> map;
public Cache(int size)
{
this.size = size;
len = 0;
public Cache(int size) {
this.size = size;
len = 0;
head = null;
tail = null;
head = null;
tail = null;
map = new HashMap<K, CacheNode>();
}
map = new HashMap<K, CacheNode>();
}
/* returns value for key, if key exists in the cache
* otherwise null */
public V get(K key)
{
CacheNode n = map.get(key);
if(n == null)
return null;
return n.value;
}
/*
* returns value for key, if key exists in the cache otherwise null
*/
public V get(K key) {
CacheNode n = map.get(key);
if (n == null)
return null;
return n.value;
}
/* puts a new key-value pair in the cache
* if the key existed already, the value is updated, and the old value is returned
* if the key didn't exist, it is added; the oldest value (now pushed out of the
* cache) may be returned, or null if the cache isn't yet full */
public V put(K key, V value)
{
CacheNode n = map.get(key);
if(n == null) {
V ret = null;
/*
* puts a new key-value pair in the cache if the key existed already, the
* value is updated, and the old value is returned if the key didn't exist,
* it is added; the oldest value (now pushed out of the cache) may be
* returned, or null if the cache isn't yet full
*/
public V put(K key, V value) {
CacheNode n = map.get(key);
if (n == null) {
V ret = null;
if(len >= size) {
CacheNode first = head;
first.unlink();
map.remove(first.key);
ret = first.value;
}
if (len >= size) {
CacheNode first = head;
first.unlink();
map.remove(first.key);
ret = first.value;
}
CacheNode add = new CacheNode(key, value);
add.append();
map.put(key, add);
CacheNode add = new CacheNode(key, value);
add.append();
map.put(key, add);
return ret;
} else {
n.unlink();
V old = n.value;
n.value = value;
n.append();
return old;
}
}
return ret;
} else {
n.unlink();
V old = n.value;
n.value = value;
n.append();
return old;
}
}
}
-70
View File
@@ -1,70 +0,0 @@
package org.dynmap;
import java.util.ArrayList;
import java.util.LinkedList;
import org.bukkit.event.player.PlayerChatEvent;
public class ChatQueue {
public class ChatMessage
{
public long time;
public String playerName;
public String message;
public ChatMessage(PlayerChatEvent event)
{
time = System.currentTimeMillis();
playerName = event.getPlayer().getName();
message = event.getMessage();
}
}
/* a list of recent chat message */
private LinkedList<ChatMessage> messageQueue;
/* remember up to this old chat messages (ms) */
private static final int maxChatAge = 120000;
public ChatQueue() {
messageQueue = new LinkedList<ChatMessage>();
}
/* put a chat message in the queue */
public void pushChatMessage(PlayerChatEvent event)
{
synchronized(MapManager.lock) {
messageQueue.add(new ChatMessage(event));
}
}
public ChatMessage[] getChatMessages(long cutoff) {
ArrayList<ChatMessage> queue = new ArrayList<ChatMessage>();
ArrayList<ChatMessage> updateList = new ArrayList<ChatMessage>();
queue.addAll(messageQueue);
long now = System.currentTimeMillis();
long deadline = now - maxChatAge;
synchronized(MapManager.lock) {
for (ChatMessage message : queue)
{
if (message.time < deadline)
{
messageQueue.remove(message);
}
else if (message.time >= cutoff)
{
updateList.add(message);
}
}
}
ChatMessage[] messages = new ChatMessage[updateList.size()];
updateList.toArray(messages);
return messages;
}
}
+60
View File
@@ -0,0 +1,60 @@
package org.dynmap;
public class Client {
public static class Update {
public long timestamp;
public long servertime;
public Player[] players;
public Object[] updates;
}
public static class Player {
public String type = "player";
public String name;
public String world;
public double x, y, z;
public Player(String name, String world, double x, double y, double z) {
this.name = name;
this.world = world;
this.x = x;
this.y = y;
this.z = z;
}
}
public static class Stamped {
public long timestamp = System.currentTimeMillis();
}
public static class ChatMessage extends Stamped {
public String type = "chat";
public String playerName;
public String message;
public ChatMessage(String playerName, String message) {
this.playerName = playerName;
this.message = message;
}
}
public static class WebChatMessage extends Stamped {
public String type = "webchat";
public String playerName;
public String message;
public WebChatMessage(String playerName, String message) {
this.playerName = playerName;
this.message = message;
}
}
public static class Tile extends Stamped {
public String type = "tile";
public String name;
public Tile(String name) {
this.name = name;
}
}
}
@@ -7,22 +7,22 @@ import org.bukkit.event.block.BlockListener;
import org.bukkit.event.block.BlockPlaceEvent;
public class DynmapBlockListener extends BlockListener {
private MapManager mgr;
public DynmapBlockListener(MapManager mgr) {
this.mgr = mgr;
}
private MapManager mgr;
@Override
public void onBlockPlace(BlockPlaceEvent event) {
Block blockPlaced = event.getBlockPlaced();
mgr.touch(blockPlaced.getX(), blockPlaced.getY(), blockPlaced.getZ());
}
public DynmapBlockListener(MapManager mgr) {
this.mgr = mgr;
}
public void onBlockDamage(BlockDamageEvent event) {
if (event.getDamageLevel() == BlockDamageLevel.BROKEN) {
Block blockBroken = event.getBlock();
mgr.touch(blockBroken.getX(), blockBroken.getY(), blockBroken.getZ());
}
}
@Override
public void onBlockPlace(BlockPlaceEvent event) {
Block blockPlaced = event.getBlockPlaced();
mgr.touch(blockPlaced.getLocation());
}
public void onBlockDamage(BlockDamageEvent event) {
if (event.getDamageLevel() == BlockDamageLevel.BROKEN) {
Block blockBroken = event.getBlock();
mgr.touch(blockBroken.getLocation());
}
}
}
+10
View File
@@ -0,0 +1,10 @@
package org.dynmap;
public class DynmapChunk {
public int x, z;
public DynmapChunk(int x, int z) {
this.x = x;
this.z = z;
}
}
@@ -1,51 +1,33 @@
package org.dynmap;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.event.player.PlayerListener;
public class DynmapPlayerListener extends PlayerListener {
private MapManager mgr;
private PlayerList playerList;
public DynmapPlayerListener(MapManager mgr, PlayerList playerList) {
this.mgr = mgr;
this.playerList = playerList;
}
@Override
public void onPlayerCommand(PlayerChatEvent event) {
String[] split = event.getMessage().split(" ");
if (split[0].equalsIgnoreCase("/dynmap")) {
if (split.length > 1) {
if (split[1].equals("render")) {
Player player = event.getPlayer();
mgr.touch(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ());
event.setCancelled(true);
} else if (split[1].equals("hide")) {
if (split.length == 2) {
playerList.hide(event.getPlayer().getName());
} else for (int i=2;i<split.length;i++)
playerList.hide(split[i]);
event.setCancelled(true);
} else if (split[1].equals("show")) {
if (split.length == 2) {
playerList.show(event.getPlayer().getName());
} else for (int i=2;i<split.length;i++)
playerList.show(split[i]);
event.setCancelled(true);
}
}
}
}
/**
* Called when a player sends a chat message
*
* @param event Relevant event details
*/
public void onPlayerChat(PlayerChatEvent event)
{
mgr.addChatEvent(event);
DynmapPlugin plugin;
public DynmapPlayerListener(DynmapPlugin plugin) {
this.plugin = plugin;
}
@Override
public void onPlayerChat(PlayerChatEvent event) {
plugin.mapManager.pushUpdate(new Client.ChatMessage(event.getPlayer().getName(), event.getMessage()));
}
@Override
public void onPlayerJoin(PlayerEvent event) {
String joinMessage = plugin.configuration.getString("joinmessage", "%playername% joined");
joinMessage = joinMessage.replaceAll("%playername%", event.getPlayer().getName());
plugin.mapManager.pushUpdate(new Client.ChatMessage("Server", joinMessage));
}
@Override
public void onPlayerQuit(PlayerEvent event) {
String quitMessage = plugin.configuration.getString("quitmessage", "%playername% quit");
quitMessage = quitMessage.replaceAll("%playername%", event.getPlayer().getName());
plugin.mapManager.pushUpdate(new Client.ChatMessage("Server", quitMessage));
}
}
+261 -83
View File
@@ -1,101 +1,279 @@
package org.dynmap;
import java.util.logging.Logger;
import java.io.IOException;
import java.io.File;
import org.bukkit.*;
import org.bukkit.event.*;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.Timer;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.block.BlockListener;
import org.bukkit.plugin.*;
import org.bukkit.plugin.java.*;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.world.WorldEvent;
import org.bukkit.event.world.WorldListener;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.config.Configuration;
import org.dynmap.debug.BukkitPlayerDebugger;
import org.dynmap.web.WebServer;
import org.dynmap.Event.Listener;
import org.dynmap.debug.Debug;
import org.dynmap.debug.Debugger;
import org.dynmap.web.HttpServer;
import org.dynmap.web.handlers.ClientConfigurationHandler;
import org.dynmap.web.handlers.ClientUpdateHandler;
import org.dynmap.web.handlers.FilesystemHandler;
import org.dynmap.web.handlers.SendMessageHandler;
import org.dynmap.web.handlers.SendMessageHandler.Message;
import org.dynmap.web.Json;
public class DynmapPlugin extends JavaPlugin {
protected static final Logger log = Logger.getLogger("Minecraft");
protected static final Logger log = Logger.getLogger("Minecraft");
private WebServer webServer = null;
private MapManager mapManager = null;
private PlayerList playerList;
private BukkitPlayerDebugger debugger = new BukkitPlayerDebugger(this);
public static File dataRoot;
public DynmapPlugin(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File folder, File plugin, ClassLoader cLoader) {
super(pluginLoader, instance, desc, folder, plugin, cLoader);
dataRoot = folder;
}
public HttpServer webServer = null;
public MapManager mapManager = null;
public PlayerList playerList;
public Configuration configuration;
public World getWorld() {
return getServer().getWorlds()[0];
}
public MapManager getMapManager() {
return mapManager;
}
public WebServer getWebServer() {
return webServer;
}
public Timer timer;
public void onEnable() {
Configuration configuration = new Configuration(new File(this.getDataFolder(), "configuration.txt"));
configuration.load();
debugger.enable();
playerList = new PlayerList(getServer());
playerList.load();
mapManager = new MapManager(getWorld(), debugger, configuration);
mapManager.startManager();
public static File tilesDirectory;
try {
webServer = new WebServer(mapManager, getServer(), playerList, debugger, configuration);
} catch(IOException e) {
log.info("position failed to start WebServer (IOException)");
}
registerEvents();
}
public World getWorld() {
return getServer().getWorlds().get(0);
}
public void onDisable() {
mapManager.stopManager();
public MapManager getMapManager() {
return mapManager;
}
if(webServer != null) {
webServer.shutdown();
webServer = null;
}
debugger.disable();
}
public HttpServer getWebServer() {
return webServer;
}
public void registerEvents() {
BlockListener blockListener = new DynmapBlockListener(mapManager);
getServer().getPluginManager().registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.Normal, this);
getServer().getPluginManager().registerEvent(Event.Type.BLOCK_DAMAGED, blockListener, Priority.Normal, this);
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_COMMAND, new DynmapPlayerListener(mapManager, playerList), Priority.Normal, this);
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_CHAT, new DynmapPlayerListener(mapManager, playerList), Priority.Normal, this);
//getServer().getPluginManager().registerEvent(Event.Type.BLOCK_DESTROYED, listener, Priority.Normal, this);
/* etc.getLoader().addListener(PluginLoader.Hook.COMMAND, listener, this, PluginListener.Priority.MEDIUM);
etc.getLoader().addListener(PluginLoader.Hook.BLOCK_CREATED, listener, this, PluginListener.Priority.MEDIUM);
etc.getLoader().addListener(PluginLoader.Hook.BLOCK_DESTROYED, listener, this, PluginListener.Priority.MEDIUM);
etc.getLoader().addListener(PluginLoader.Hook.LOGIN, listener, this, PluginListener.Priority.MEDIUM);
public void onEnable() {
configuration = new Configuration(new File(this.getDataFolder(), "configuration.txt"));
configuration.load();
etc.getInstance().addCommand("/map_wait", " [wait] - set wait between tile renders (ms)");
etc.getInstance().addCommand("/map_stat", " - query number of tiles in render queue");
etc.getInstance().addCommand("/map_regen", " - regenerate entire map");
etc.getInstance().addCommand("/map_debug", " - send map debugging messages");
etc.getInstance().addCommand("/map_nodebug", " - disable map debugging messages");
etc.getInstance().addCommand("/addsign", " [name] - adds a named sign to the map");
etc.getInstance().addCommand("/removesign", " [name] - removes a named sign to the map");
etc.getInstance().addCommand("/listsigns", " - list all named signs");
etc.getInstance().addCommand("/tpsign", " [name] - teleport to a named sign");
*/
}
loadDebuggers();
tilesDirectory = getFile(configuration.getString("tilespath", "web/tiles"));
tilesDirectory.mkdirs();
playerList = new PlayerList(getServer(), getFile("hiddenplayers.txt"));
playerList.load();
mapManager = new MapManager(this, configuration);
mapManager.startRendering();
if (!configuration.getBoolean("disable-webserver", false)) {
loadWebserver();
}
if (configuration.getBoolean("jsonfile", false)) {
jsonConfig();
int jsonInterval = configuration.getInt("jsonfile-interval", 1) * 1000;
timer = new Timer();
timer.scheduleAtFixedRate(new JsonTimerTask(this, configuration), jsonInterval, jsonInterval);
}
registerEvents();
}
public void loadWebserver() {
InetAddress bindAddress;
{
String address = configuration.getString("webserver-bindaddress", "0.0.0.0");
try {
bindAddress = address.equals("0.0.0.0")
? null
: InetAddress.getByName(address);
} catch (UnknownHostException e) {
bindAddress = null;
}
}
int port = configuration.getInt("webserver-port", 8123);
webServer = new HttpServer(bindAddress, port);
webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web"))));
webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory));
webServer.handlers.put("/up/", new ClientUpdateHandler(mapManager, playerList, getServer()));
webServer.handlers.put("/up/configuration", new ClientConfigurationHandler((Map<?, ?>) configuration.getProperty("web")));
SendMessageHandler messageHandler = new SendMessageHandler();
messageHandler.onMessageReceived.addListener(new Listener<SendMessageHandler.Message>() {
@Override
public void triggered(Message t) {
mapManager.pushUpdate(new Client.WebChatMessage(t.name, t.message));
log.info("[WEB]" + t.name + ": " + t.message);
getServer().broadcastMessage("[WEB]" + t.name + ": " + t.message);
}
});
webServer.handlers.put("/up/sendmessage", messageHandler);
try {
webServer.startServer();
} catch (IOException e) {
log.severe("Failed to start WebServer on " + bindAddress + ":" + port + "!");
}
}
public void onDisable() {
mapManager.stopRendering();
if (webServer != null) {
webServer.shutdown();
webServer = null;
}
if (timer != null) {
timer.cancel();
}
Debug.clearDebuggers();
}
public void registerEvents() {
BlockListener blockListener = new DynmapBlockListener(mapManager);
getServer().getPluginManager().registerEvent(Event.Type.BLOCK_PLACED, blockListener, Priority.Monitor, this);
getServer().getPluginManager().registerEvent(Event.Type.BLOCK_DAMAGED, blockListener, Priority.Monitor, this);
WorldListener worldListener = new WorldListener() {
@Override
public void onWorldLoaded(WorldEvent event) {
mapManager.activateWorld(event.getWorld());
}
};
getServer().getPluginManager().registerEvent(Event.Type.WORLD_LOADED, worldListener, Priority.Monitor, this);
PlayerListener playerListener = new DynmapPlayerListener(this);
//getServer().getPluginManager().registerEvent(Event.Type.PLAYER_COMMAND, playerListener, Priority.Normal, this);
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_CHAT, playerListener, Priority.Normal, this);
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_LOGIN, playerListener, Priority.Normal, this);
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_JOIN, playerListener, Priority.Normal, this);
getServer().getPluginManager().registerEvent(Event.Type.PLAYER_QUIT, playerListener, Priority.Normal, this);
}
private static File combinePaths(File parent, String path) {
return combinePaths(parent, new File(path));
}
private static File combinePaths(File parent, File path) {
if (path.isAbsolute())
return path;
return new File(parent, path.getPath());
}
public File getFile(String path) {
return combinePaths(getDataFolder(), path);
}
protected void loadDebuggers() {
Object debuggersConfiguration = configuration.getProperty("debuggers");
Debug.clearDebuggers();
if (debuggersConfiguration != null) {
for (Object debuggerConfiguration : (List<?>) debuggersConfiguration) {
Map<?, ?> debuggerConfigurationMap = (Map<?, ?>) debuggerConfiguration;
try {
Class<?> debuggerClass = Class.forName((String) debuggerConfigurationMap.get("class"));
Constructor<?> constructor = debuggerClass.getConstructor(JavaPlugin.class, Map.class);
Debugger debugger = (Debugger) constructor.newInstance(this, debuggerConfigurationMap);
Debug.addDebugger(debugger);
} catch (Exception e) {
log.severe("Error loading debugger: " + e);
e.printStackTrace();
continue;
}
}
}
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
if (!cmd.getName().equalsIgnoreCase("dynmap"))
return false;
Player player = null;
if (sender instanceof Player)
player = (Player) sender;
if (args.length > 0) {
if (args[0].equals("render")) {
if (sender instanceof Player) {
mapManager.touch(((Player) sender).getLocation());
return true;
}
} else if (args[0].equals("hide")) {
if (args.length == 1 && player != null) {
playerList.hide(player.getName());
sender.sendMessage("You are now hidden on Dynmap.");
return true;
} else {
for (int i = 1; i < args.length; i++) {
playerList.hide(args[i]);
sender.sendMessage(args[i] + " is now hidden on Dynmap.");
}
return true;
}
} else if (args[0].equals("show")) {
if (args.length == 1 && player != null) {
playerList.show(player.getName());
sender.sendMessage("You are now visible on Dynmap.");
return true;
} else {
for (int i = 1; i < args.length; i++) {
playerList.show(args[i]);
sender.sendMessage(args[i] + " is now visible on Dynmap.");
}
return true;
}
} else if (args[0].equals("fullrender")) {
if (player == null || player.isOp()) {
if (args.length > 2) {
for (int i = 1; i < args.length; i++) {
World w = getServer().getWorld(args[i]);
mapManager.renderFullWorld(new Location(w, 0, 0, 0));
}
return true;
} else if (player != null) {
mapManager.renderFullWorld(player.getLocation());
return true;
}
} else if (player != null) {
player.sendMessage("Only OPs are allowed to use this command!");
return true;
}
}
}
return false;
}
private void jsonConfig() {
File outputFile;
Map<?, ?> clientConfig = (Map<?, ?>) configuration.getProperty("web");
File webpath = new File(configuration.getString("webpath", "web"), "dynmap_config.json");
if (webpath.isAbsolute())
outputFile = webpath;
else
outputFile = new File(getDataFolder(), webpath.toString());
try {
FileOutputStream fos = new FileOutputStream(outputFile);
fos.write(Json.stringifyJson(clientConfig).getBytes());
fos.close();
} catch (FileNotFoundException ex) {
System.out.println("FileNotFoundException : " + ex);
} catch (IOException ioe) {
System.out.println("IOException : " + ioe);
}
}
}
+12
View File
@@ -0,0 +1,12 @@
package org.dynmap;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.World;
public class DynmapWorld {
public World world;
public List<MapType> maps = new ArrayList<MapType>();
public UpdateQueue updates = new UpdateQueue();
}
+26
View File
@@ -0,0 +1,26 @@
package org.dynmap;
import java.util.LinkedList;
import java.util.List;
public class Event<T> {
private List<Listener<T>> listeners = new LinkedList<Listener<T>>();
public synchronized void addListener(Listener<T> l) {
listeners.add(l);
}
public synchronized void removeListener(Listener<T> l) {
listeners.remove(l);
}
public synchronized void trigger(T t) {
for (Listener<T> l : listeners) {
l.triggered(t);
}
}
public interface Listener<T> {
void triggered(T t);
}
}
+5
View File
@@ -0,0 +1,5 @@
package org.dynmap;
public interface Handler<T> {
void handle(T t);
}
@@ -0,0 +1,66 @@
package org.dynmap;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.TimerTask;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.util.config.Configuration;
import org.dynmap.web.Json;
class JsonTimerTask extends TimerTask {
private final DynmapPlugin plugin;
private Server server;
private MapManager mapManager;
private Configuration configuration;
public JsonTimerTask(DynmapPlugin instance, Configuration config) {
this.plugin = instance;
this.server = this.plugin.getServer();
this.mapManager = this.plugin.getMapManager();
this.configuration = config;
}
public void run() {
for (World world : this.server.getWorlds()) {
long current = System.currentTimeMillis();
Client.Update update = new Client.Update();
update.timestamp = current;
update.servertime = world.getTime() % 24000;
Player[] players = mapManager.playerList.getVisiblePlayers();
update.players = new Client.Player[players.length];
for (int i = 0; i < players.length; i++) {
Player p = players[i];
Location pl = p.getLocation();
update.players[i] = new Client.Player(p.getName(), pl.getWorld().getName(), pl.getX(), pl.getY(), pl.getZ());
}
update.updates = mapManager.getWorldUpdates(world.getName(), current - (configuration.getInt("jsonfile-interval", 1) + 10000));
File webpath = new File(this.configuration.getString("webpath", "web"), "dynmap_" + world.getName() + ".json");
File outputFile;
if (webpath.isAbsolute())
outputFile = webpath;
else {
outputFile = new File(plugin.getDataFolder(), webpath.toString());
}
try {
FileOutputStream fos = new FileOutputStream(outputFile);
fos.write(Json.stringifyJson(update).getBytes());
fos.close();
} catch (FileNotFoundException ex) {
System.out.println("FileNotFoundException : " + ex);
} catch (IOException ioe) {
System.out.println("IOException : " + ioe);
}
}
}
}
@@ -1,6 +0,0 @@
package org.dynmap;
public class MapLocation {
public float x;
public float y;
}
+211 -163
View File
@@ -3,182 +3,230 @@ package org.dynmap;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.util.config.ConfigurationNode;
import org.dynmap.debug.Debugger;
import org.dynmap.debug.Debug;
public class MapManager extends Thread {
protected static final Logger log = Logger.getLogger("Minecraft");
public class MapManager {
protected static final Logger log = Logger.getLogger("Minecraft");
private World world;
private Debugger debugger;
private MapType[] maps;
public StaleQueue staleQueue;
public ChatQueue chatQueue;
public PlayerList playerList;
public AsynchronousQueue<MapTile> tileQueue;
public Map<String, DynmapWorld> worlds = new HashMap<String, DynmapWorld>();
public Map<String, DynmapWorld> inactiveworlds = new HashMap<String, DynmapWorld>();
public PlayerList playerList;
/* lock for our data structures */
public static final Object lock = new Object();
/* lock for our data structures */
public static final Object lock = new Object();
/* whether the worker thread should be running now */
private boolean running = false;
public MapManager(DynmapPlugin plugin, ConfigurationNode configuration) {
this.tileQueue = new AsynchronousQueue<MapTile>(new Handler<MapTile>() {
@Override
public void handle(MapTile t) {
render(t);
}
}, (int) (configuration.getDouble("renderinterval", 0.5) * 1000));
for(Object worldConfigurationObj : (List<?>)configuration.getProperty("worlds")) {
Map<?, ?> worldConfiguration = (Map<?, ?>)worldConfigurationObj;
String worldName = (String)worldConfiguration.get("name");
DynmapWorld world = new DynmapWorld();
if (worldConfiguration.get("maps") != null) {
for(MapType map : loadMapTypes((List<?>)worldConfiguration.get("maps"))) {
world.maps.add(map);
}
}
inactiveworlds.put(worldName, world);
World bukkitWorld = plugin.getServer().getWorld(worldName);
if (bukkitWorld != null)
activateWorld(bukkitWorld);
}
tileQueue.start();
}
/* path to image tile directory */
public File tileDirectory;
/* web files location */
public File webDirectory;
/* bind web server to ip-address */
public String bindaddress = "0.0.0.0";
/* port to run web server on */
public int serverport = 8123;
/* time to pause between rendering tiles (ms) */
public int renderWait = 500;
public void debug(String msg)
{
debugger.debug(msg);
}
private static File combinePaths(File parent, String path) { return combinePaths(parent, new File(path)); }
private static File combinePaths(File parent, File path) {
if (path.isAbsolute()) return path;
return new File(parent, path.getPath());
}
public MapManager(World world, Debugger debugger, ConfigurationNode configuration)
{
this.world = world;
this.debugger = debugger;
this.staleQueue = new StaleQueue();
this.chatQueue = new ChatQueue();
tileDirectory = combinePaths(DynmapPlugin.dataRoot, configuration.getString("tilespath", "web/tiles"));
webDirectory = combinePaths(DynmapPlugin.dataRoot, configuration.getString("webpath", "web"));
renderWait = (int)(configuration.getDouble("renderinterval", 0.5) * 1000);
if (!tileDirectory.isDirectory())
tileDirectory.mkdirs();
maps = loadMapTypes(configuration);
}
private MapType[] loadMapTypes(ConfigurationNode configuration) {
List<?> configuredMaps = (List<?>)configuration.getProperty("maps");
ArrayList<MapType> mapTypes = new ArrayList<MapType>();
for(Object configuredMapObj : configuredMaps) {
try {
@SuppressWarnings("unchecked")
Map<String, Object> configuredMap = (Map<String, Object>)configuredMapObj;
String typeName = (String)configuredMap.get("class");
log.info("Loading map '" + typeName.toString() + "'...");
Class<?> mapTypeClass = Class.forName(typeName);
Constructor<?> constructor = mapTypeClass.getConstructor(MapManager.class, World.class, Debugger.class, Map.class);
MapType mapType = (MapType)constructor.newInstance(this, world, debugger, configuredMap);
mapTypes.add(mapType);
} catch (Exception e) {
debugger.error("Error loading map", e);
}
}
MapType[] result = new MapType[mapTypes.size()];
mapTypes.toArray(result);
return result;
}
/* initialize and start map manager */
public void startManager()
{
synchronized(lock) {
running = true;
this.start();
try {
this.setPriority(MIN_PRIORITY);
log.info("Set minimum priority for worker thread");
} catch(SecurityException e) {
log.info("Failed to set minimum priority for worker thread!");
}
}
}
void renderFullWorld(Location l) {
DynmapWorld world = worlds.get(l.getWorld().getName());
if (world == null) {
log.severe("Could not render: world '" + l.getWorld().getName() + "' not defined in configuration.");
return;
}
World w = world.world;
log.info("Full render starting on world '" + w.getName() + "'...");
for (MapType map : world.maps) {
int requiredChunkCount = 200;
HashSet<MapTile> found = new HashSet<MapTile>();
HashSet<MapTile> rendered = new HashSet<MapTile>();
LinkedList<MapTile> renderQueue = new LinkedList<MapTile>();
LinkedList<DynmapChunk> loadedChunks = new LinkedList<DynmapChunk>();
/* stop map manager */
public void stopManager()
{
synchronized(lock) {
if(!running)
return;
log.info("Stopping map renderer...");
running = false;
try {
this.join();
} catch(InterruptedException e) {
log.info("Waiting for map renderer to stop is interrupted");
}
}
}
for (MapTile tile : map.getTiles(l)) {
if (!found.contains(tile)) {
found.add(tile);
renderQueue.add(tile);
}
}
while (!renderQueue.isEmpty()) {
MapTile tile = renderQueue.pollFirst();
/* the worker/renderer thread */
public void run()
{
try {
log.info("Map renderer has started.");
while(running) {
boolean found = false;
MapTile t = staleQueue.popStaleTile();
if(t != null) {
debugger.debug("rendering tile " + t + "...");
t.getMap().render(t);
staleQueue.onTileUpdated(t);
try {
Thread.sleep(renderWait);
} catch(InterruptedException e) {
}
found = true;
}
if(!found) {
try {
Thread.sleep(500);
} catch(InterruptedException e) {
}
}
}
log.info("Map renderer has stopped.");
} catch(Exception ex) {
debugger.error("Exception on rendering-thread: " + ex.toString());
}
}
DynmapChunk[] requiredChunks = tile.getMap().getRequiredChunks(tile);
public void touch(int x, int y, int z) {
for (int i = 0; i < maps.length; i++) {
maps[i].touch(new Location(world, x, y, z));
}
}
public void invalidateTile(MapTile tile) {
debugger.debug("invalidating tile " + tile.getName());
staleQueue.pushStaleTile(tile);
}
public void addChatEvent(PlayerChatEvent event)
{
chatQueue.pushChatMessage(event);
}
if (requiredChunks.length > requiredChunkCount)
requiredChunkCount = requiredChunks.length;
// Unload old chunks.
while (loadedChunks.size() >= requiredChunkCount - requiredChunks.length) {
DynmapChunk c = loadedChunks.pollFirst();
w.unloadChunk(c.x, c.z, false, true);
}
// Load the required chunks.
for (DynmapChunk chunk : requiredChunks) {
boolean wasLoaded = w.isChunkLoaded(chunk.x, chunk.z);
w.loadChunk(chunk.x, chunk.z, false);
if (!wasLoaded)
loadedChunks.add(chunk);
}
if (render(tile)) {
found.remove(tile);
rendered.add(tile);
for (MapTile adjTile : map.getAdjecentTiles(tile)) {
if (!found.contains(adjTile) && !rendered.contains(adjTile)) {
found.add(adjTile);
renderQueue.add(adjTile);
}
}
}
found.remove(tile);
System.gc();
}
// Unload remaining chunks to clean-up.
while (!loadedChunks.isEmpty()) {
DynmapChunk c = loadedChunks.pollFirst();
w.unloadChunk(c.x, c.z, false, true);
}
}
log.info("Full render finished.");
}
public void activateWorld(World w) {
DynmapWorld world = inactiveworlds.get(w.getName());
if (world == null) {
world = worlds.get(w.getName());
} else {
inactiveworlds.remove(w.getName());
}
if (world != null) {
world.world = w;
worlds.put(w.getName(), world);
log.info("Activated world '" + w.getName() + "' in Dynmap.");
}
}
private MapType[] loadMapTypes(List<?> mapConfigurations) {
Event.Listener<MapTile> invalitateListener = new Event.Listener<MapTile>() {
@Override
public void triggered(MapTile t) {
invalidateTile(t);
}
};
ArrayList<MapType> mapTypes = new ArrayList<MapType>();
for (Object configuredMapObj : mapConfigurations) {
try {
@SuppressWarnings("unchecked")
Map<String, Object> configuredMap = (Map<String, Object>) configuredMapObj;
String typeName = (String) configuredMap.get("class");
log.info("Loading map '" + typeName.toString() + "'...");
Class<?> mapTypeClass = Class.forName(typeName);
Constructor<?> constructor = mapTypeClass.getConstructor(Map.class);
MapType mapType = (MapType) constructor.newInstance(configuredMap);
mapType.onTileInvalidated.addListener(invalitateListener);
mapTypes.add(mapType);
} catch (Exception e) {
log.log(Level.SEVERE, "Error loading maptype", e);
e.printStackTrace();
}
}
MapType[] result = new MapType[mapTypes.size()];
mapTypes.toArray(result);
return result;
}
public void touch(Location l) {
DynmapWorld world = worlds.get(l.getWorld().getName());
if (world == null)
return;
for (int i = 0; i < world.maps.size(); i++) {
MapTile[] tiles = world.maps.get(i).getTiles(l);
for (int j = 0; j < tiles.length; j++) {
invalidateTile(tiles[j]);
}
}
}
public void invalidateTile(MapTile tile) {
Debug.debug("Invalidating tile " + tile.getFilename());
tileQueue.push(tile);
}
public void startRendering() {
tileQueue.start();
}
public void stopRendering() {
tileQueue.stop();
}
public boolean render(MapTile tile) {
boolean result = tile.getMap().render(tile, getTileFile(tile));
pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
return result;
}
private HashMap<World, File> worldTileDirectories = new HashMap<World, File>();
private File getTileFile(MapTile tile) {
World world = tile.getWorld();
File worldTileDirectory = worldTileDirectories.get(world);
if (worldTileDirectory == null) {
worldTileDirectory = new File(DynmapPlugin.tilesDirectory, tile.getWorld().getName());
worldTileDirectories.put(world, worldTileDirectory);
}
worldTileDirectory.mkdirs();
return new File(worldTileDirectory, tile.getFilename());
}
public void pushUpdate(Object update) {
for(DynmapWorld world : worlds.values()) {
world.updates.pushUpdate(update);
}
}
public void pushUpdate(World world, Object update) {
pushUpdate(world.getName(), update);
}
public void pushUpdate(String worldName, Object update) {
DynmapWorld world = worlds.get(worldName);
world.updates.pushUpdate(update);
}
public Object[] getWorldUpdates(String worldName, long since) {
DynmapWorld world = worlds.get(worldName);
if (world == null)
return new Object[0];
return world.updates.getUpdatedObjects(since);
}
}
+24 -10
View File
@@ -1,14 +1,28 @@
package org.dynmap;
import org.bukkit.World;
public abstract class MapTile {
private MapType map;
public MapType getMap() {
return map;
}
public abstract String getName();
public MapTile(MapType map) {
this.map = map;
}
private World world;
private MapType map;
public World getWorld() {
return world;
}
public MapType getMap() {
return map;
}
public abstract String getFilename();
public MapTile(World world, MapType map) {
this.world = world;
this.map = map;
}
@Override
public int hashCode() {
return getFilename().hashCode() ^ getWorld().hashCode();
}
}
+11 -29
View File
@@ -1,35 +1,17 @@
package org.dynmap;
import java.io.File;
import org.bukkit.Location;
import org.bukkit.World;
import org.dynmap.debug.Debugger;
public abstract class MapType {
private MapManager manager;
public MapManager getMapManager() {
return manager;
}
private World world;
public World getWorld() {
return world;
}
private Debugger debugger;
public Debugger getDebugger() {
return debugger;
}
public MapType(MapManager manager, World world, Debugger debugger) {
this.manager = manager;
this.world = world;
this.debugger = debugger;
}
public void invalidateTile(MapTile tile) {
manager.invalidateTile(tile);
}
public abstract void touch(Location l);
public abstract void render(MapTile tile);
public Event<MapTile> onTileInvalidated = new Event<MapTile>();
public abstract MapTile[] getTiles(Location l);
public abstract MapTile[] getAdjecentTiles(MapTile tile);
public abstract DynmapChunk[] getRequiredChunks(MapTile tile);
public abstract boolean render(MapTile tile, File outputFile);
}
+83 -64
View File
@@ -14,68 +14,87 @@ import org.bukkit.Server;
import org.bukkit.entity.Player;
public class PlayerList {
private Server server;
private HashSet<String> hiddenPlayerNames = new HashSet<String>();
private File hiddenPlayersFile = new File(DynmapPlugin.dataRoot, "hiddenplayers.txt");
public PlayerList(Server server) {
this.server = server;
}
public void save() {
OutputStream stream;
try {
stream = new FileOutputStream(hiddenPlayersFile);
OutputStreamWriter writer = new OutputStreamWriter(stream);
for(String player : hiddenPlayerNames) {
writer.write(player);
writer.write("\n");
}
writer.close();
stream.close();
} catch(IOException e) {
e.printStackTrace();
}
}
public void load() {
try {
Scanner scanner = new Scanner(hiddenPlayersFile);
while(scanner.hasNextLine()) {
String line = scanner.nextLine();
hiddenPlayerNames.add(line);
}
scanner.close();
} catch (FileNotFoundException e) {
return;
}
}
public void hide(String playerName) {
hiddenPlayerNames.add(playerName);
save();
}
public void show(String playerName) {
hiddenPlayerNames.remove(playerName);
save();
}
public void setVisible(String playerName, boolean visible) {
if (visible) show(playerName); else hide(playerName);
}
public Player[] getVisiblePlayers() {
ArrayList<Player> visiblePlayers = new ArrayList<Player>();
Player[] onlinePlayers = server.getOnlinePlayers();
for(int i=0;i<onlinePlayers.length;i++){
Player p = onlinePlayers[i];
if (!hiddenPlayerNames.contains(p.getName())) {
visiblePlayers.add(p);
}
}
Player[] result = new Player[visiblePlayers.size()];
visiblePlayers.toArray(result);
return result;
}
private Server server;
private HashSet<String> hiddenPlayerNames = new HashSet<String>();
private File hiddenPlayersFile;
public PlayerList(Server server, File hiddenPlayersFile) {
this.server = server;
this.hiddenPlayersFile = hiddenPlayersFile;
}
public void save() {
OutputStream stream;
try {
stream = new FileOutputStream(hiddenPlayersFile);
OutputStreamWriter writer = new OutputStreamWriter(stream);
for (String player : hiddenPlayerNames) {
writer.write(player);
writer.write("\n");
}
writer.close();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public void load() {
try {
Scanner scanner = new Scanner(hiddenPlayersFile);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
hiddenPlayerNames.add(line);
}
scanner.close();
} catch (FileNotFoundException e) {
return;
}
}
public void hide(String playerName) {
hiddenPlayerNames.add(playerName);
save();
}
public void show(String playerName) {
hiddenPlayerNames.remove(playerName);
save();
}
public void setVisible(String playerName, boolean visible) {
if (visible)
show(playerName);
else
hide(playerName);
}
// TODO: Clean this up... one day
public Player[] getVisiblePlayers(String worldName) {
ArrayList<Player> visiblePlayers = new ArrayList<Player>();
Player[] onlinePlayers = server.getOnlinePlayers();
for (int i = 0; i < onlinePlayers.length; i++) {
Player p = onlinePlayers[i];
if (p.getWorld().getName().equals(worldName) && !hiddenPlayerNames.contains(p.getName())) {
visiblePlayers.add(p);
}
}
Player[] result = new Player[visiblePlayers.size()];
visiblePlayers.toArray(result);
return result;
}
public Player[] getVisiblePlayers() {
ArrayList<Player> visiblePlayers = new ArrayList<Player>();
Player[] onlinePlayers = server.getOnlinePlayers();
for (int i = 0; i < onlinePlayers.length; i++) {
Player p = onlinePlayers[i];
if (!hiddenPlayerNames.contains(p.getName())) {
visiblePlayers.add(p);
}
}
Player[] result = new Player[visiblePlayers.size()];
visiblePlayers.toArray(result);
return result;
}
}

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