【问题标题】:MapEditor export as JSON - Object encrypted? [duplicate]MapEditor 导出为 JSON - 对象加密? [复制]
【发布时间】:2015-12-05 19:46:51
【问题描述】:

我使用 MapEditor 来选择使用我制作的特定 TileMaps 来创建地图。我的问题是这样的:

当通过 JSON 导出创建的地图时,通常似乎大多数地图都显示为它们的 tile id,如下面的 sn-p 所示。

{
  "data":[1, 2, 1, 2, 3, 1, 3, 1, 2, 2, 3, 3, 4, 4, 4, 1], <------ TIle Id's
  "height":4,
  "name":"ground",
  "opacity":1,
  "properties":
     {
      "tileLayerProp":"1"
     },
  "type":"tilelayer",
  "visible":true,
  "width":4,
  "x":0,
  "y":0
}

但是,当我在看到的相同字段中检查自己导出的 JSON 映射时,

 {
         "compression":"zlib",
         "data":"eJzt1UFqwzAQQFFvus1Juizdldz\/ViULgQmWItmyJMtv4JGQBirNT9NlmXO+L2qEaXHP30K9u\/RWuq9SYR4rqenZ5+xdlOzrzHlsyJ2Wbe4yWz1KmoS5W4\/UmcLPfiKPsYm10CM9qTPlnDW231SPkiaP5T49UufKbbG1308tcpqs33eHHkfPFttvbouSHmc3GWGOnK9k53uabL1vth7PwjPG1GyRa7bvq9Biz\/TY\/8w9jrR4Te8Wo\/fY871TY2ZtcWQ\/Rz\/rtUaPcVq8z\/peV2wRdvp6\/Fs9XwqejzJndWjdY\/37QpOrTOwuM\/So3ST2v77WtGjQu0etJqFF7F5HptXfQ48WqZ3tbZJqUaNJyw6j9PjU5Cvyek6LVJP312LvuWOPvedocc9ZW\/T4rF2NHuNo3UKPsVrooccV9GqhR\/\/96zFui1F6tDhj7z2P2KPXeXvveOYepXfovd879gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4v4BxPaYbQ==",
         "encoding":"base64",
         "height":100,
         "name":"solids",
         "opacity":1,
         "type":"tilelayer",
         "visible":true,
         "width":100,
         "x":0,
         "y":0
        }, 

这两个都是真实的样本,第一个是从他们的文档中提取的,第二个是从我的原始导出中提取的。如您所见,他们的“数据”字段与我的不同,因为他们是 JSONArray,因此我相信这个函数,

public static void load(String path) throws Exception 
    {
        JSONParser parser = new JSONParser();
        Object obj = parser.parse(new FileReader(path));
        JSONObject jObj = (JSONObject) obj;

        JSONArray layers = (JSONArray) jObj.get("layers");
        int amount = layers.size();

        for (int i = 0; i < amount; i++) 
        {

            JSONObject layer = (JSONObject) layers.get(i);
            String type = (String) layer.get("name");

            if (type.equals("solids")) 
            {
                WIDTH = (int) ((long)layer.get("width"));
                HEIGHT = (int) ((long)layer.get("height"));
                solids = parse((JSONArray) layer.get("data"));
            } 

一直给我带来问题。是不是因为在我的地图的“数据”字段中,我相信这是一个 JSONString 和一个编码的那个。

在重新搜索之后,我似乎需要解码“数据”,最终以某种方式最终会变成您在第一个代码块中看到的“数据”字段。

关于我如何做到这一点或只是禁用所有编码的任何提示?

编辑:我请求的解析函数

private static Image[][] parse(JSONArray array)
    {
        Image[][] layer = new Image[WIDTH][HEIGHT];
        int index;

        for (int x = 0; x < WIDTH; ++x)
        {
            for (int y = 0; y < HEIGHT; ++y)
            {
                index = (int)((long)array.get((y * WIDTH) + x)); //must cast because JSON returns long
                layer[x][y] = getSpriteImage(index);
            }
        }
        return layer;
    }

编辑 2:我的编辑加载函数

public static void load(String path) throws Exception 
    {
        JSONParser parser = new JSONParser();
        Object obj = parser.parse(new FileReader(path));
        JSONObject jObj = (JSONObject) obj;

        JSONArray layers = (JSONArray) jObj.get("layers");
        int amount = layers.size();

        for (int i = 0; i < amount; i++) 
        {

            JSONObject layer = (JSONObject) layers.get(i);
            String type = (String) layer.get("name");

            if (type.equals("solids")) 
            {
                Decoder decoder = Base64.getDecoder();
                byte[] decodedBytes = decoder.decode((byte[]) layer.get("data"));
                Inflater decompresser = new Inflater();
                solids = parse((JSONArray)decompresser.inflate(decodedBytes));

编辑 3:我的 getSpriteImage 函数

private static Image getSpriteImage(int index)
{
    if (index == 0 )
    {
        return null;
    }

    index -= 1;

    SpriteSheet sheet = Resources.getSprite("tileset");
    int verti = sheet.getVerticalCount();
    int horiz = sheet.getHorizontalCount();

    int y = (index / verti);
    int x = (index % horiz);

    return sheet.getSubImage(x, y);
}

编辑 5:地图的外观

[44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, etcccccccccccccccccccccccccccccccccccccccccccccccc]

编辑 6:世界和游戏状态的渲染方法

world-Tile.SIZE的最终值 = 5;

public static void render(float xRend, float yRend)
    {
        int offset = 2;
        int xStart = (int)(xRend / Tile.SIZE) - offset;
        int yStart = (int)(yRend / Tile.SIZE) - offset;
        int xEnd = (Window.WIDTH / Tile.SIZE) + xStart + (offset * 2);
        int yEnd = (Window.HEIGHT / Tile.SIZE) + yStart + (offset * 2);

        for (int x = xStart; x < xEnd; ++x)
        {
            for (int y = yStart; y < yEnd; ++y)
            {
                if (solidTileBound(x, y))
                {
                    solids[x][y].draw(x * Tile.SIZE, y * Tile.SIZE, Tile.SIZE, Tile.SIZE);
                }
            }
        }

    }

和游戏状态:

@Override
public void render(GameContainer gc, StateBasedGame stateGame, Graphics gfx) throws SlickException 
{
    gfx.drawString(("Game State"), 50, 50);

    //gfx.translate(-1500, -1500);
    World.render(500, 500);
    //gfx.resetTransform();

}

编辑 7:

[LOG] Loading C:\Users\William.William-PC\Desktop\testMap.json
Sun Dec 06 18:51:33 EST 2015 ERROR:Error loading World
org.newdawn.slick.SlickException: Error loading World
    at main.java.TestGame.init(TestGame.java:39)
    at org.newdawn.slick.AppGameContainer.setup(AppGameContainer.java:390)
    at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:314)
    at main.java.Main.main(Main.java:40)
Caused by: java.lang.RuntimeException: Resource not found: tileset.png
    at org.newdawn.slick.util.ResourceLoader.getResourceAsStream(ResourceLoader.java:69)
    at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.java:169)
    at org.newdawn.slick.Image.<init>(Image.java:196)
    at org.newdawn.slick.SpriteSheet.<init>(SpriteSheet.java:129)
    at org.newdawn.slick.SpriteSheet.<init>(SpriteSheet.java:115)
    at org.newdawn.slick.SpriteSheet.<init>(SpriteSheet.java:102)
    at main.java.Resources.addTileSet(Resources.java:55)
    at main.java.JSONLoader.load(JSONLoader.java:33)
    at main.java.TestGame.init(TestGame.java:31)
    ... 3 more

我彻底查看了它,但我不确定我应该将tileset.png 放在哪里,或者为什么世界不会为此加载。您是否创建了自己的 .json 世界导出来测试这一点?

【问题讨论】:

  • 第二个data 字段是base64 编码的。
  • 我明白了,但在我的问题中,我问有人如何解码它,或者只是以某种方式禁用导出编码?我正在使用地图编辑器
  • 解码成382字节的二进制数据,原来是the default encoding for a byte[]
  • 我发现该链接对我来说有点令人困惑,因为我正在尝试。我尝试添加这段代码,我在正确的轨道上吗? Decoder decoder = Base64.getDecoder(); byte[] decodedBytes = decoder.decode((byte[]) layer.get("data"));
  • 是的,应该可以的。你究竟是如何导出 JSON 的?也许可以在那里覆盖默认编码。

标签: java json slick tiled


【解决方案1】:

非常接近。不幸的是,Inflater 比这更复杂:

代替

            Decoder decoder = Base64.getDecoder();
            byte[] decodedBytes = decoder.decode((byte[]) layer.get("data"));
            Inflater decompresser = new Inflater();
            solids = parse((JSONArray)decompresser.inflate(decodedBytes));

试试这个:

            Object o = layer.get("data");

            if ( o instanceof JSONArray )
                solids = parseJSONArray( (JSONArray) o );
            else if ( o instanceof String 
                && "base64".equals( layer.get( "encoding" ) )
                && "zlib".equals( layer.get( "compression" ) )
            )
            {
                // base64 decode
                Decoder decoder = Base64.getDecoder();
                byte[] decodedBytes = decoder.decode((String) o);

                // zlib decompress
                Inflater decompresser = new Inflater();
                decompresser.setInput(decodedBytes);
                byte[] decompressedBytes = new byte[WIDTH * HEIGHT * 4];
                int resultLength = decompresser.inflate(decompressedBytes);
                decompresser.end();

                // convert `byte[N*4]` to `int[N]`
                int[] result = new int[WIDTH * HEIGHT];
                ByteBuffer bb = ByteBuffer.wrap(decompressedBytes);
                bb.order(ByteOrder.LITTLE_ENDIAN);
                bb.asIntBuffer().get(result);

                solids = parseIntArray( result );
            }
            else
                throw new RuntimeException( "Unimplemented data type: "
                    + o.getClass().getName() );

将原来的 parse 函数重命名为 parseJSONArray(例如), 然后将其复制到一个新函数parseByteArray,如下所示:

private static Image[][] parseIntArray( int[] array )
{
    Image[][] layer = new Image[WIDTH][HEIGHT];

    for (int x = 0; x < WIDTH; ++x)
        for (int y = 0; y < HEIGHT; ++y)
            layer[x][y] = getSpriteImage( array[ y * WIDTH + x ] );

    return layer;
}

【讨论】:

  • 我将在“试试这个:”中假设您打算在所有解压缩器实例上/或拼写相同?
  • 只是仔细检查了它不是键盘或其他东西!因此,一旦我调整了所有内容并重新运行了我的引擎,World.load("res/maps/world.json"); 我在解码时遇到错误,Decoder decoder = Base64.getDecoder(); byte[] decodedBytes = decoder.decode((byte[]) layer.get("data")); 给了我一个类似的错误,java.lang.ClassCastException: java.lang.String cannot be cast to [B at world.World.load(World.java:61)
  • 啊,我不小心删除了那个-是的,那里也有问题:decoder.decode( layer.get("data") )String 转换为byte[]。已更新,希望现在可以使用。
  • 嗯.. 我仍然在byte[] decodedBytes = decoder.decode(layer.get("data")); 上收到错误消息,上面写着The method decode(byte[]) in the type Base64.Decoder is not applicable for the arguments (Object)。看来我们正在传递 decode 一个它不喜欢的对象?
  • 更新了运行时检查;它现在应该同时支持 JSONArray 和 String 并且如果是别的东西就抛出异常。
猜你喜欢
  • 2022-01-09
  • 2018-07-17
  • 2020-10-06
  • 2014-01-10
  • 1970-01-01
  • 1970-01-01
  • 2010-12-28
  • 2018-08-31
  • 2011-06-07
相关资源
最近更新 更多