Sign in to follow this  
Jonneh

Online Map Viewer

Recommended Posts

UPDATED FOR YOUR PLEASURE

So I was rather disturbed by the black spots everywhere too. With some of the new pavement types it was like whole black holes for deeds in places lol.

 

I went to decompile this mod and dig through, man let me first say Joneh is a genius coder, he will be missed around here.

 

He had made a hand written array that contained 256 values one for each possible tile type since tile types are a byte (256 maximum values, 255 if you count from 0 and you should) but most of them were left to 0 or -1, which is why when those tiles were pulled they came out black. I did away with that, called the common.jar colors that wurm puts in for the mapdumps. This will help to futureproof it, if they change those colors or change tiles or whatever it will just call the new values from the new setup. The only thing that may break it is if they change the common.jar to make my target of the colors not stick. You will notice there are some dark spots in my tundra. Players told me that was ligonberries, I dunno, but at least its dark green and not black. Pay attention in my example images the deed north of the tundra (Carbonek) for an example of the giant black spots and how it changes in the new version.

 

I was still using the older iteration of the mapviewer before this, and the setup with the  newer version I just worked on is a bit different. So I will briefly touch on the setup after the images. Without further wait:

 

Before After

PVe6tEg.png

MdEFL77.png

 

 

Original Before if you want a bigger view: http://i.imgur.com/PVe6tEg.png

Original After if you want a bigger view: http://i.imgur.com/MdEFL77.png

 

The mapviewer.jar and mapviewer.cfg need to go into the root folder of your server. Where your server.jar is. This new system has the class paths set up to get the common.jar and use it as a library, so its location is important. Unless you want to modify the MANIFEST

 

For the mapviewer.cfg file:

# WU MAP VIEWER CONFIG FILE

# RELATIVE OR ABSOLUTE PATH TO DIRECTORY FOR MAP
MAP_DIRECTORY = Creative

# RELATIVE OR ABSOLUTE PATH TO DIRECTORY TO OUTPUT TO
# THIS SHOULD BE A DIRECTORY ACCESSIBLE BY HTTP SERVER
OUTPUT_DIRECTORY = mapviewer

# SIZE OF SECTIONS TO SPLIT UP INTO
# SMALLER SIZES ARE MORE EFFICIENT FOR CACHING BUT USE MORE BANDWIDTH
SECTION_SIZE = 256

SHOW_DEEDS = true
SHOW_DEED_BORDERS_IN_3D_MODE = false
SHOW_DEED_BORDERS_IN_FLAT_MODE = true

Pretty self explained. The older version I was using was not hard but a bit more difficult to configure. No I am not modding the custom version from a few posts back (September 2016 or so) this is just Jonneh's version updated for the modern era.

 

Hope you guys enjoy. Cheers

 

Now you can get it for yourself: https://www.dropbox.com/s/8w50njp1gl38ldv/mapviewer.zip?dl=0

 

I only had to edit one file in the jar, and the Manifest. So I only have 1 working source code. I thought you guys might like to have it, in the spoiler below.

Spoiler

package com.wyverngame.mapviewer;

import com.wyverngame.mapviewer.Config;
import com.wyverngame.mapviewer.zone.BridgePart;
import com.wyverngame.mapviewer.zone.Deed;
import com.wyverngame.mapviewer.zone.Tile;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileAttribute;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;

public final class Renderer {
	private static final Logger LOGGER = Logger.getLogger(Renderer.class.getName());
	private final Config config;
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private final Map<Tile, BridgePart> bridgeParts = new HashMap();
	private int size = 4096;
	private int[][] typeData;
	private int[][] metaData;
	private int[][] heightData;

	public Renderer(Config config) {
		this.config = config;
	}

	@SuppressWarnings("unused")
	public int load(List<Deed> deeds, Map<Tile, BridgePart> bridgeParts) throws Throwable {
		this.bridgeParts.putAll(bridgeParts);
		Path temp = Paths.get("temp", new String[0]);
		if (Files.notExists(temp, new LinkOption[0])) {
			Files.createDirectory(temp, new FileAttribute[0]);
		}
		Path map = temp.resolve("top_layer.map");
		Files.deleteIfExists(map);
		Files.copy(this.config.getMapDirectory().resolve("top_layer.map"), map, new CopyOption[0]);
		Throwable throwable = null;
		Object var6_7 = null;
		try {
			DataInputStream in = new DataInputStream(
					new BufferedInputStream(Files.newInputStream(map, new OpenOption[0]), 65536));
			try {
				in.readLong();
				in.readByte();
				this.size = 1 << in.readByte();
				in.skipBytes(1014);
				this.typeData = new int[this.size][this.size];
				this.metaData = new int[this.size][this.size];
				this.heightData = new int[this.size][this.size];
				int y = 0;
				while (y < this.size) {
					int x = 0;
					while (x < this.size) {
						int tileType = in.read() & 255;
						int meta = in.read() & 255;
						short height = in.readShort();
						this.typeData[x][y] = tileType;
						this.metaData[x][y] = meta;
						this.heightData[x][y] = height;
						++x;
					}
					++y;
				}
				for (Deed deed : deeds) {
					deed.setHeight(this.heightData[deed.getX()][deed.getY()]);
				}
				return this.size;
			} catch (Throwable var5_6) {
				throw var5_6;
			} finally {
				if (in != null) {
					in.close();
				}
			}
		} catch (Throwable var6_8) {
			if (throwable == null) {
				throwable = var6_8;
			} else if (throwable != var6_8) {
				throwable.addSuppressed(var6_8);
			}
			throw throwable;
		}
	}
	
	public BufferedImage render(Renderer.Type type) {
		BufferedImage img = new BufferedImage(this.size, this.size, 1);
		int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
		Arrays.fill(pixels, 3686001);

		for (int x = 0; x < this.size - 1; ++x) {
			if (x % 128 == 0) {
				LOGGER.log(Level.INFO, "Rendered " + (int) ((float) x / (float) this.size * 100.0F) + "%");
			}

			for (int y = 0; y < this.size - 1; ++y) {
				int tiled = this.typeData[x][y];
				com.wurmonline.mesh.Tiles.Tile tilef = com.wurmonline.mesh.Tiles.getTile(tiled);
				java.awt.Color color = tilef.getColor();
				int r = color.getRed();
				int g = color.getGreen();
				int b = color.getBlue();
				float tileHeight = (float) this.heightData[x][y] / 40.0F;
				float tileHeightN = (float) this.heightData[x + 1][y + 1] / 40.0F;
				float tileHeightB = (float) this.heightData[x][y + 1] / 40.0F;
				float delta = tileHeightN - tileHeight;
				float factor = (float) (1.0D + Math.tanh((double) (delta / 4.0F)));
				r = (int) (factor * (float) r);
				g = (int) (factor * (float) g);
				b = (int) (factor * (float) b);
				if (tileHeight < 0.0F) {
					r = r / 5 + 41;
					g = r / 5 + 51;
					b = r / 5 + 102;
				}

				if (r < 0) {
					r = 0;
				}

				if (r > 255) {
					r = 255;
				}

				if (g < 0) {
					g = 0;
				}

				if (g > 255) {
					g = 255;
				}

				if (b < 0) {
					b = 0;
				}

				if (b > 255) {
					b = 255;
				}

				int height;
				if (type.equals(Renderer.Type.NORMAL)) {
					int tile = y - (int) tileHeight;
					if (tileHeightB - 1.0F > tileHeight) {
						tile = y - (int) tileHeightB;
					}

					int part = Integer.MAX_VALUE;
					if (tileHeight >= 0.0F && tileHeightB < 0.0F) {
						part = y + 1;
					}

					for (height = tile; (float) height <= (float) tile + Math.abs(delta) + 9.0F; ++height) {
						if (height >= 0 && height < this.size) {
							if (height == part) {
								r = r / 5 + 41;
								g = r / 5 + 51;
								b = r / 5 + 102;
							}

							pixels[height * this.size + x] = r << 16 | g << 8 | b;
						}
					}
				} else {
					pixels[y * this.size + x] = r << 16 | g << 8 | b;
				}

				Tile arg20 = new Tile(x, y);
				BridgePart arg21 = (BridgePart) this.bridgeParts.get(arg20);
				if (arg21 != null) {
					if (type.equals(Renderer.Type.NORMAL)) {
						height = arg21.getHeightOffset();
						if (arg21.getSlope() < 0) {
							height += arg21.getSlope();
						}

						int h = y - height / 40;
						int ha = y - arg21.getHeightOffset() / 40;
						int hb = y - (arg21.getHeightOffset() + arg21.getSlope()) / 40;
						if (h >= 0 && h < this.size - 1) {
							if (ha != hb) {
								pixels[(h - 1) * this.size + x] = arg21.getColour();
							}

							pixels[h * this.size + x] = arg21.getColour();
							pixels[(h + 1) * this.size + x] = arg21.getShadowColour();
						}
					} else {
						pixels[y * this.size + x] = arg21.getColour();
					}
				}
			}
		}

		return img;
	}

	public void save(Path path, Renderer.Type type) throws Throwable {
		if (Files.notExists(path, new LinkOption[0])) {
			Files.createDirectory(path, new FileAttribute[0]);
		}

		BufferedImage img = this.render(type);
		BufferedImage[][] parts = split(img, this.config.getSectionSize());
		int s = parts.length;

		for (int x = 0; x < s; ++x) {
			for (int y = 0; y < s; ++y) {
				overwriteIfChanged(parts[x][y], path.resolve(x + "." + y + ".png"), x, y);
			}
		}

	}

	@SuppressWarnings("unused")
	private static void overwriteIfChanged(BufferedImage img, Path path, int sx, int sy) throws Throwable {
		boolean changed = true;
		Throwable ex;
		Object arg5;
		if (Files.exists(path, new LinkOption[0])) {
			try {
				ex = null;
				arg5 = null;

				try {
					InputStream out = Files.newInputStream(path, new OpenOption[0]);

					try {
						BufferedImage ex1 = ImageIO.read(out);
						if (img.getWidth() == ex1.getWidth() && img.getHeight() == ex1.getHeight()) {
							changed = false;

							label467 : for (int x = 0; x < img.getWidth(); ++x) {
								for (int y = 0; y < img.getHeight(); ++y) {
									if (img.getRGB(x, y) != ex1.getRGB(x, y)) {
										changed = true;
										break label467;
									}
								}
							}
						} else {
							changed = true;
						}
					} finally {
						if (out != null) {
							out.close();
						}

					}
				} catch (Throwable arg33) {
					if (ex == null) {
						ex = arg33;
					} else if (ex != arg33) {
						ex.addSuppressed(arg33);
					}

					throw ex;
				}
			} catch (Exception arg34) {
				changed = true;
				arg34.printStackTrace();
			}
		}

		if (changed) {
			ex = null;
			arg5 = null;

			try {
				OutputStream arg35 = Files.newOutputStream(path, new OpenOption[0]);

				try {
					LOGGER.log(Level.INFO, "[Over]writing section " + sx + ", " + sy);
					ImageIO.write(img, "PNG", arg35);
				} finally {
					if (arg35 != null) {
						arg35.close();
					}

				}
			} catch (Throwable arg31) {
				if (ex == null) {
					ex = arg31;
				} else if (ex != arg31) {
					ex.addSuppressed(arg31);
				}

				throw ex;
			}
		}

	}

	private static BufferedImage[][] split(BufferedImage render, int size) {
		int count = render.getWidth() / size;
		BufferedImage[][] sections = new BufferedImage[count][count];

		for (int sx = 0; sx < count; ++sx) {
			for (int sy = 0; sy < count; ++sy) {
				int x = sx * size;
				int y = sy * size;
				LOGGER.log(Level.INFO, "Splitting section " + sx + ", " + sy);
				BufferedImage section = render.getSubimage(x, y, size, size);
				sections[sx][sy] = section;
			}
		}

		return sections;
	}

	public static enum Type {
		NORMAL, FLAT;
	}
}

 

 

Edited by Xyp
added the source of the class I had to edit. Only source file I have.
  • Like 5

Share this post


Link to post
Share on other sites

Thanks man. :)

Edited by MrLolan

Share this post


Link to post
Share on other sites

Xyp, i dont know why but isnt working for me.

Program making only map files and empty sections-3d folder

 

 

Now I saw it: " The mapviewer.jar and mapviewer.cfg need to go into the root folder of your server. Where your server.jar is. This new system has the class paths set up to get the common.jar and use it as a library, so its location is important. Unless you want to modify the MANIFEST"

 

:D

Edited by MrLolan

Share this post


Link to post
Share on other sites

@XypWorking like a charm! Love you long time. :wub::P:wub:

 

If you ever have an urge to add guard towers, I wouldn't argue and might even love you longer time. LOL

 

But seriously this no longer triggers OCD alert flare ups and cringing every time I look at my map. \o/

Share this post


Link to post
Share on other sites

Yeah I was annoyed at the black holes too. It was either this or mod everything to pull towards the holes like gravity lol. I don't personally have interest in guard towers, so ill put it on my boredom list, but im quite busy lately. Its on a list though.

Share this post


Link to post
Share on other sites

No worries, like I say if you ever have an "urge" not critical by any means simply a 'would be nice' feature.

Share this post


Link to post
Share on other sites

Any idea if the newer version of Jonneh's map tool will be updated with Xyp's fix?  Not so much for the towers, but for mobile/touch support that he had added.

Share this post


Link to post
Share on other sites
On 9/26/2017 at 3:47 PM, mwdennis said:

Any idea if the newer version of Jonneh's map tool will be updated with Xyp's fix?  Not so much for the towers, but for mobile/touch support that he had added.

 

Xyp did his fix for the latest version Jonneh ever released. The one with the towers was done by someone else modifying the code it wasn't done by the original author. As the site that contained those modification is long gone the answer to your question is probably not.

Share this post


Link to post
Share on other sites

I've updated the generator and tweaked a few things...

  • Can now pass name of config file as parameter to the jar, should make generating multiple maps in batch easier
  • Added focus zone markers on the map (currently no build zones show with a transparent red color - other zone types can be tweaked in CSS)
  • Added highways view
  • Updated the colors for all new tile types

I'm currently using this for my servers, you can see an example of all the features here - https://otherlands.bdew.net/map/walden/


Download: https://www.dropbox.com/s/gbamfmkyroz4cxy/mapgen.jar?dl=0

  • Like 1

Share this post


Link to post
Share on other sites
14 hours ago, bdew said:

I've updated the generator and tweaked a few things...

  • Can now pass name of config file as parameter to the jar, should make generating multiple maps in batch easier
  • Added focus zone markers on the map (currently no build zones show with a transparent red color - other zone types can be tweaked in CSS)
  • Added highways view
  • Updated the colors for all new tile types

I'm currently using this for my servers, you can see an example of all the features here - https://otherlands.bdew.net/map/walden/


Download: https://www.dropbox.com/s/gbamfmkyroz4cxy/mapgen.jar?dl=0

This map is awesome, but without async load-unload -- cant use it on 8k maps :(

Share this post


Link to post
Share on other sites

what do you mean async load-unload? what actual issues are you having?

Share this post


Link to post
Share on other sites
15 hours ago, bdew said:

what do you mean async load-unload? what actual issues are you having?

This map works like this: You open map and waiting for downloading all parts, then you can see procmon -- map use huge of memmory and GPU when using. For good usage I try to use huge map parts, like 4096. But a lot of people with low-end PC cant use this and we migrate to 

 

Share this post


Link to post
Share on other sites
On 12/27/2017 at 7:02 AM, bdew said:

 

I'm just getting a blank map with the 3D, Flat, and Roads options on the side.  I know that I've been able to use mapviewer on a previous LAN without having to set up a website for it, but I don't remember how it was done. I know this because I have never set up a website for myself, ever, in which to view maps.

Share this post


Link to post
Share on other sites
12 minutes ago, Batta said:

 

I'm just getting a blank map with the 3D, Flat, and Roads options on the side.  I know that I've been able to use mapviewer on a previous LAN without having to set up a website for it, but I don't remember how it was done. I know this because I have never set up a website for myself, ever, in which to view maps.

 

It should work. Are you getting any errors when running the generator? And does your output folder look like this?

 

63lO77E.png

Share this post


Link to post
Share on other sites
11 minutes ago, bdew said:

 

It should work. Are you getting any errors when running the generator? And does your output folder look like this?

 

63lO77E.png

Everything except the sections folders.  I do remember that I had them in the past, with previous mapviewer.

Share this post


Link to post
Share on other sites
1 minute ago, Batta said:

Everything except the sections folders.  I do remember that I had them in the past, with previous mapviewer.

 

Those folders are where your actual map images are. Check the output from the generator for any errors.

Share this post


Link to post
Share on other sites
1 minute ago, bdew said:

 

Those folders are where your actual map images are. Check the output from the generator for any errors.

Okay, will do. Which file would I find the output in?

 

Share this post


Link to post
Share on other sites

@bdew Because your file was just a jar, I am also using the original mapviewer config file from the OP. Is that correct?

 

 

And here's my mapviewer config:

Spoiler

# WU MAP VIEWER CONFIG FILE

# RELATIVE OR ABSOLUTE PATH TO DIRECTORY FOR MAP
MAP_DIRECTORY = C:\Program Files (x86)\Steam\steamapps\common\Wurm Unlimited Dedicated Server\Small World

# RELATIVE OR ABSOLUTE PATH TO DIRECTORY TO OUTPUT TO
# THIS SHOULD BE A DIRECTORY ACCESSIBLE BY HTTP SERVER
OUTPUT_DIRECTORY = C:\Program Files (x86)\Steam\steamapps\common\Wurm Unlimited Dedicated Server\MapViewer

# SIZE OF SECTIONS TO SPLIT UP INTO
# SMALLER SIZES ARE MORE EFFICIENT FOR CACHING BUT USE MORE BANDWIDTH
SECTION_SIZE = 256

SHOW_DEEDS = true
SHOW_DEED_BORDERS_IN_3D_MODE = false
SHOW_DEED_BORDERS_IN_FLAT_MODE = true

 

Edited by Batta

Share this post


Link to post
Share on other sites

Try using the other slash ( / ) in the directory paths, or doubling them up ( \\ )

Share this post


Link to post
Share on other sites
7 minutes ago, bdew said:

Try using the other slash ( / ) in the directory paths, or doubling them up ( \\ )

Neither of those fixes worked. Anything else I can try?

 

Share this post


Link to post
Share on other sites

 

21 hours ago, bdew said:

Check the output from the generator for any errors.

 

Look at the output from the generator that it prints as it runs, if there is an error it will be there, if you can't figure it out post the full text here.

Share this post


Link to post
Share on other sites
2 hours ago, bdew said:

 

 

Look at the output from the generator that it prints as it runs, if there is an error it will be there, if you can't figure it out post the full text here.

 

I can't seem to find anything like this. When I run the mapgen.jar there is no screen that comes up, if that's what you mean?  I also looked at all the files I could find and none of them seemed related. Would you please let me know what the output from the generator would look like, or what it would be called, so I can find it?

Share this post


Link to post
Share on other sites
20 hours ago, Batta said:

 

I can't seem to find anything like this. When I run the mapgen.jar there is no screen that comes up, if that's what you mean?  I also looked at all the files I could find and none of them seemed related. Would you please let me know what the output from the generator would look like, or what it would be called, so I can find it?

 

run from the command line in the folder with the jar "java -jar mapgen.jar" - it should print stuff to the console window

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this