首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为MMO动态生成地图网页

为MMO动态生成地图网页
EN

Code Review用户
提问于 2015-05-08 17:18:25
回答 2查看 123关注 0票数 4

这个问题与我上一个关于MMO服务器的问题有关。

在这里,我使用这个程序所做的是连接到另一个与MMO服务器位于同一服务器上的Java服务器程序。一旦连接,它将接收包含MMO服务器的所有播放器数据以及所有区域数据的有效负载。这是大约15兆字节的数据,每小时左右传输一次。

使用这些数据,我创建了一个简单的网页。我将在这个问题上发布的是用来生成页面的代码。我知道我做错了很多事情,所以希望我能有很多的批评和提高。

分析区域数据,然后基于该数据创建网页上地图的图像。

下面是一个链接,链接到实时网页:

世界地图

代码语言:javascript
复制
public class RegionWebsiteGenerator {

    private Map<MapPoint, String> regionMap = new HashMap<MapPoint, String>();
    private Map<String, Integer> regionOwners = new HashMap<String, Integer>();
    private Map<String, Integer> topOwnersAndRanks = new HashMap<String, Integer>();

    private int regionWidth = 12;
    private int numRegions = 60; //need to know this number ahead of time

    public RegionWebsiteGenerator() {
        this.loadRegions();
        this.countOwnersForRegions(this.regionMap);
        this.populateTopOwners(this.regionOwners);
        this.createMapImageForRegions(this.regionMap);
    }

    //load and parse data
    private void loadRegions() {
        File dir = new File("regions");
        File[] directoryListing = dir.listFiles();
        if (directoryListing != null) {
            for (File child : directoryListing) {

                //validation
                String fileName = child.getName();
                String delims = ","; //separator for map point
                String[] points = fileName.split(delims);
                if (points.length > 0) {
                    try {
                        MapPoint point = new MapPoint(Integer.parseInt(points[0]), Integer.parseInt(points[1]));

                        //read the valid file
                        if (point != null) {
                            BufferedReader br = new BufferedReader(new FileReader(child));
                            @SuppressWarnings("unused")
                            String firstLine = br.readLine();
                            String secondLine = br.readLine(); //second line is the region data
                            this.regionMap.put(point, secondLine);
                            br.close();
                        }
                    } catch (Exception e) {
                        System.out.println("file is not a region");
                    }
                }   
            }
        }
    }   
    private void countOwnersForRegions(Map<MapPoint, String>regions) {
        for (String regionString : regions.values()) {
            String ownerName = this.getOwnerNameForRegion(regionString);
            if (this.regionOwners.containsKey(ownerName)) {
                int currentCount = this.regionOwners.get(ownerName);
                this.regionOwners.put(ownerName, currentCount++);
            } else {
                this.regionOwners.put(ownerName, 1);
            }
        }
    }
    private void populateTopOwners(Map<String, Integer>regionOwners) {
        Set<Entry<String, Integer>> entries = PlayerWebsiteGenerator.entriesSortedByValues(regionOwners);
        Object[] entriesArray = entries.toArray();
        int maxCount = Math.min(entriesArray.length, 10);
        for (int i = 0; i < maxCount; i++) {
            @SuppressWarnings("rawtypes")
            Entry entry = (Entry)entriesArray[i];
            String name = (String)entry.getKey();
            if (!name.equals("^")) {
                this.topOwnersAndRanks.put((String)entry.getKey(), i);
            }
        }
    }

    //output the html
    public void generatePage() {
        String filePath = "../www/site1/stats/regions.html";
        File regionHTMLFile = new File(filePath);
        try {
            regionHTMLFile.createNewFile();

            BufferedWriter output;
            try {
                output = new BufferedWriter(new FileWriter(regionHTMLFile));
                output.write("<!doctype html>");
                output.newLine();
                output.write("<html>");
                output.newLine();
                output.write("<link rel=\"stylesheet\" type=\"text/css\" href=\"regions.css\" media=\"screen\" />");
                output.newLine();
                output.write("<head>");
                output.newLine();
                output.write("</head>");
                output.newLine();
                output.write("<body onload=\"javascript:scrollWin()\">");
                output.newLine();

                output.write("<div id=\"title\">");
                output.newLine();
                output.write("<p>Live Region Map</p>");
                output.newLine();
                output.write("</div>");
                output.newLine();

                output.write("<div id=\"map\">");
                output.newLine();
                output.write("<img src=\"regions.png\" alt=\"Map\">"); //style=\"width:1800px;height:1800px\"
                output.newLine();
                output.write("</div>");
                output.newLine();

                output.write("<div id=\"legend\">");
                output.newLine();
                output.write("<p>Region Owners</p>");
                output.newLine();
                output.write("<p>Legend</p>");
                output.newLine();

                this.writeLegendToHTML(output);

                output.write("</div>");
                output.newLine();

                output.write("<script>");
                output.newLine();
                output.write("function scrollWin() {");
                output.newLine();
                output.write("window.scrollTo(window.outerHeight/2, window.outerWidth/2);");
                output.newLine();
                output.write("}");
                output.newLine();
                output.write("</script>");
                output.newLine();

                output.write("</body>");
                output.newLine();
                output.write("</html>");
                output.close();
            } catch (IOException e) {
                e.printStackTrace();
            }    
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void writeLegendToHTML(BufferedWriter output) throws IOException {
        int currentRank = 0;
        for (String string : this.topOwnersAndRanks.keySet()) {
            output.write("<div id=\"rank" + String.valueOf(currentRank) + "\">");
            output.newLine();
            output.write("<p>" + string + "</p>");
            output.newLine();
            output.write("</div>");
            output.newLine();
            currentRank++;
        }
    }

    //generate the map image
    private void createMapImageForRegions(Map<MapPoint, String>regions) {

        BufferedImage img = new BufferedImage(numRegions*regionWidth, numRegions*regionWidth, BufferedImage.TYPE_INT_RGB);

        for (MapPoint point : regions.keySet()) {

            int i = point.x * regionWidth;
            int j = (59 - point.y) * regionWidth; //flip the image because it draws starting top left

            String ownerName = this.getOwnerNameForRegion(regions.get(point));

            Color color = new Color(this.getColorForBiomeType(this.getBiomeTypeForRegion(regions.get(point))));
            if (this.topOwnersAndRanks.containsKey(ownerName)) {
                color = new Color(this.getColorForRank(this.topOwnersAndRanks.get(ownerName)));
            }

            Graphics graphics = img.getGraphics();
            graphics.setColor(color);
            graphics.drawRect(i, j, regionWidth, regionWidth);
            graphics.fillRect(i, j, regionWidth, regionWidth);
        }

        File imageFile = new File("../www/site1/stats/regions.png");
        try {
            ImageIO.write(img, "PNG", imageFile);
        } catch (IOException e) {
            System.out.println("failed to write image");
        }
    }
    private int getColorForRank(int rank) {
        int r = 0;
        int g = 0;
        int b = 0;
        int a = 255;
        switch (rank) {
            case 0:
                //gold
                r = 204;
                g = 204;
                b = 0;
                break;
            case 1:
                //Dark magenta
                r = 153;
                g = 0;
                b = 76;
                break;
            case 2:
                //dark red
                r = 153;
                g = 0;
                b = 0;
                break;
            case 3:
                //light blue
                r = 153;
                g = 255;
                b = 255;
                break;
            case 4:
                //pink
                r = 255;
                g = 204;
                b = 204;
                break;
            case 5:
                //light gray
                r = 224;
                g = 224;
                b = 224;
                break;
            case 6:
                //dark gray
                r = 64;
                g = 64;
                b = 64;
                break;
            case 7:
                //dark blue
                r = 0;
                g = 0;
                b = 102;
                break;
            case 8:
                //dark purple
                r = 51;
                g = 0;
                b = 102;
                break;
            case 9:
                //light purple
                r = 153;
                g = 153;
                b = 255;
                break;
            default:
                //will be black
                break;
        }
        //color is created by this bit shifting trick
        return (a << 24) | (r << 16) | (g << 8) | b;
    }
    private int getColorForBiomeType(int biomeType) {
        int r = 0;
        int g = 0;
        int b = 0;
        int a = 255;
        if (biomeType == 0) {
            //woodlands
            r = 52;
            g = 108;
            b = 0;
        } else if (biomeType == 1) {
            //mountains
            r = 102;
            g = 51;
            b = 0;
        } else if (biomeType == 2) {
            //plains
            r = 0;
            g = 255;
            b = 0;
        } else if (biomeType == 3) {
            //wasteland
            r = 255;
            g = 153;
            b = 51;
        } else if (biomeType == 4) {
            //swampy
            r = 0;
            g = 153;
            b = 76;
        } else if (biomeType == 5) {
            //aquatic
            r = 0;
            g = 128;
            b = 255;
        }
        //color is created by this bit shifting trick
        return (a << 24) | (r << 16) | (g << 8) | b;
    }

    //get the necessary information using the pattern found in deserialization method below
    private int getBiomeTypeForRegion(String region) {
        String delims = DelimiterType.TOP_LEVEL.string;
        String[] messageFragments = region.split(delims);
        return Integer.parseInt(messageFragments[0]);
    }
    private String getOwnerNameForRegion(String region) {
        String delims = DelimiterType.TOP_LEVEL.string;
        String[] messageFragments = region.split(delims);
        return messageFragments[4];
    }
    /*
    public static Region decodeRegionFromString(String string) {
        String delims = DelimiterType.TOP_LEVEL.string;
        String[] messageFragments = string.split(delims);

        int biomeType = Integer.parseInt(messageFragments[0]);
        Region region = new Region(BiomeType.values()[biomeType], new MapPoint(Integer.parseInt(messageFragments[1]), Integer.parseInt(messageFragments[2])));

        region.name = messageFragments[3];
        region.setOwnerName(messageFragments[4]);

        int numTiles = Integer.parseInt(messageFragments[5]);
        int messageIndex = 6;
        for (int i = 0; i < numTiles; i++) {
            int tileType = Integer.parseInt(messageFragments[messageIndex]);
            messageIndex++;

            if (tileType == TileType.CAPITAL.ordinal()) {
                TileCapital tile = TileCapital.decodeTileFromString(messageFragments[messageIndex]);
                messageIndex++;
                region.setTileForPosition(tile.position(), tile);
            } else {
                Tile tile = Tile.decodeTileFromString(TileType.values()[tileType], messageFragments[messageIndex]);
                messageIndex++;
                region.setTileForPosition(tile.position(), tile);
            }
        }
        return region;
    }
    */
    //DO NOT DELETE COMMENTED METHOD
}

下面是生成的HTML文件:

代码语言:javascript
复制
<!doctype html>
<html>
<link rel="stylesheet" type="text/css" href="regions.css" media="screen" />
<head>
</head>
<body onload="javascript:scrollWin()">
<div id="title">
<p>Live Region Map</p>
</div>
<div id="map">
<img src="regions.png" alt="Map">
</div>
<div id="legend">
<p>Region Owners</p>
<p>Legend</p>
<div id="rank0">
<p>Name14</p>
</div>
</div>
<script>
function scrollWin() {
window.scrollTo(window.outerHeight/2, window.outerWidth/2);
}
</script>
</body>
</html>

下面是CSS文件,该文件目前从未更改过:

代码语言:javascript
复制
body {
    background-color:black;
}

#title {
    font-size: 40pt;
    color: white;
    text-align: center;
    border:5px solid white;
}

#map {
    text-align: center;
}

#legend {
    border: 5px solid white;
    text-align: center;
    font-size: 30pt;
    color: white;
}

#rank0 {
    text-align: center;
    background-color: rgb(204, 204, 0);
}
#rank1 {
    text-align: center;
    background-color: rgb(153, 0, 76);
}
#rank2 {
    text-align: center;
    background-color: rgb(153, 0, 0);
}
#rank3 {
    text-align: center;
    background-color: rgb(153, 255, 255);
}
#rank4 {
        text-align: center;
    background-color: rgb(255, 204, 204);
}
#rank5 {
    text-align: center;
    background-color: rgb(224, 224, 224);
}
#rank6 {
    text-align: center;
    background-color: rgb(64, 64, 64);
}
#rank7 {
    text-align: center;
    background-color: rgb(0, 0, 102);
}
#rank8 {
    text-align: center;
    background-color: rgb(51, 0, 102);
}
#rank9 {
    text-align: center;
    background-color: rgb(153, 153, 255);
}

我对HTMLCSS知之甚少,所以对它们的任何评论也将不胜感激。

EN

回答 2

Code Review用户

回答已采纳

发布于 2015-05-08 21:40:06

彩色

专用int getColorForRank(int秩){ int r= 0;int g= 0;int b= 0;int a= 255;开关(秩){ case 0: /gold= 204;g= 204;b= 0;例1: //暗品红r= 153;g= 0;b= 76;断裂;例2: //暗红r= 153;g= 0;b= 0;例3: //淡蓝色r= 153;g= 255;b= 255;断裂;例4: //粉红色r= 255;g= 204;B= 204;断裂;例5: //浅灰r= 224;g= 224;b= 224;断裂;例6: //深灰色r= 64;G= 64;b= 64;断裂;例7: //深蓝色r= 0;g= 0;b= 102;断裂;例8: //暗紫色r= 51;g= 0;b= 102;断裂;例9: //浅紫色r= 153;g= 153;b= 255;分隔符;默认值://将是黑色断线;}//颜色是通过此位移位技巧返回(a << 24) \x (r << 16) \ (g << 8) \ b;}创建的。

我会像这样定义Enum Color

代码语言:javascript
复制
public enum Color {
    GOLD(204,204,0);
    
    private int r = 0;
    private int g = 0;
    private int b = 0;
    private int a = 255;
    
    private Color(int r, int g, int b) {
        this.r = r;
        this.g = g;
        this.b = b;
    }
    
    public int color() {
        return (a << 24) | (r << 16) | (g << 8) | b; 
    }
}

现在,你唯一需要做的就是构造一个颜色的Map,你只需要做一些像mapOfColors.get(1).color()和瞧!你可以对你拥有的每一种颜色(生物群落等等)进行反复练习和重复。

SuppressWarnings是一种代码嗅觉

大多数情况下,@Suprresswarnigns是一种代码气味。通常,你可以做一些事情来避免手头的问题,或者它警告你,你在做坏事!让我们来看看你的问题:

@SuppressWarnings("unused") String firstLine = br.readLine();

这是警告您不要使用firstLine。如果您不需要它,为什么要创建一个变量并分配它。您知道可以忽略返回的值。

代码语言:javascript
复制
 br.readLine();//skip the first line

模板

你用手做的事情可以很容易地通过使用像速度这样的模板引擎来完成,或者在一个webapp中转换。它将简化generatePage(),因为您将使用所需的所有信息构造模型变量,并只发布页面。

为一个页面编写一个小型的Java web应用程序看起来有点过分了,但我相信你将来会添加一些页面,我希望到那时你不会通过做你目前正在做的事情来生成所有的页面。

Trivia

代码语言:javascript
复制
private int regionWidth = 12;

这是一个常数,所以应该是:

代码语言:javascript
复制
private final static int REGION_WIDTH = 12;

//不删除注释方法

注释的方法只是你的课堂上的噪音。我希望您使用的是源代码管理,如果您确实删除了该代码,并做了一个标记来记住在哪里可以找到它,但就目前的情况而言,它根本没有用。

票数 4
EN

Code Review用户

发布于 2015-05-08 17:52:41

Java中的

我对Java一无所知,但是像print语句这样硬编码的静态标记的数量给我带来了危险。没有读取您可以使用的文件内容的函数吗?这似乎会使您以后修改模板时更容易进行修改。

使用语义上最合适的标记

在页面标题中使用以下标记:

代码语言:javascript
复制
<div id="title">
<p>Live Region Map</p>
</div>

您应该使用的是h1 (标题):

代码语言:javascript
复制
<h1>Live Region Map</h1>

你的传奇真的需要两行文字吗?简化(并使用适当的标记):

代码语言:javascript
复制
<h2>Region Owners</h2>

业主本身应列明:

代码语言:javascript
复制
<ul class="legend">
<li>baz</li>
<li>Krepi</li>
</ul>

过度使用ID

我认为这里根本没有必要使用I。您不能将它们用作JavaScript的钩子。如果您不确定是否应该使用类或id,请与类一起使用。

利用级联

对于您的传奇,您是指定文本-对齐10次!只要一次就可以了(使用上面的标记):

代码语言:javascript
复制
.legend li {
    text-align: center;
}

内联与链接CSS

通常,我会建议任何使用行样式的人将这些信息放在外部样式表中。但是,对于像这样动态生成的内容,特别是当您重用相同的信息来生成映像时,最好将其定位(在Java中)并使用内联样式。

代码语言:javascript
复制
<ul class="legend">
<li style="background-color: rgb(204, 204, 0)">baz</li>
<li style="background-color: rgb(153, 0, 0)">Krepi</li>
</ul>

如果您没有在两个地方重用这些信息,我建议您使用:nth-child而不是一个类(或id):

代码语言:javascript
复制
.legend li:nth-child(1) {
    background-color: rgb(204, 204, 0);
}
.legend li:nth-child(2) {
   background-color: rgb(153, 0, 76);
}
.legend li:nth-child(3) {
   background-color: rgb(153, 0, 0);
}
.legend li:nth-child(4) {
   background-color: rgb(153, 255, 255);
}
.legend li:nth-child(5) {
    background-color: rgb(255, 204, 204);
}
.legend li:nth-child(6) {
   background-color: rgb(224, 224, 224);
}
.legend li:nth-child(7) {
   background-color: rgb(64, 64, 64);
}
.legend li:nth-child(8) {
   background-color: rgb(0, 0, 102);
}
.legend li:nth-child(9) {
   background-color: rgb(51, 0, 102);
}
.legend li:nth-child(10) {
   background-color: rgb(153, 153, 255);
}
票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/90186

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档