Recursos de desarrollo / Ejemplo de clase de edición de nivel clásico de Minecraft

Quien soy
Joel Fulleda
@joelfulleda
Autor y referencias

Para compilar y usar esta clase, haga que su classpath incluya la ruta al archivo LevelEditor.java y al archivo minecraft-server.jar.


javac -classpath.: minecraft-server.jar LevelEditor.java

java -classpath.: minecraft-server.jar LevelEditor

or

java -classpath.: minecraft-server.jar LevelEditor new_server_level.dat


import java.io.*; import java.text.DateFormat; import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPInputStream; public class LevelEditor { private com.mojang.minecraft.level.Level level = null; LevelEditor() { } // load from file called filename public void load(String filename) { FileInputStream fis = null; GZIPInputStream gzis = null; ObjectInputStream in = null; DataInputStream inputstream = null; try { fis = new FileInputStream(filename); gzis = new GZIPInputStream(fis); inputstream = new DataInputStream(gzis); if((inputstream.readInt()) != 0x271bb788) { return; } if((inputstream.readByte()) > 2) { System.out.println("Error: Level version > 2, this is unexpected!"); return; } in = new ObjectInputStream(gzis); level = (com.mojang.minecraft.level.Level)in.readObject(); inputstream.close(); in.close(); System.out.println("Loading level "+filename+" successful"); } catch(IOException ex) { ex.printStackTrace(); } catch(ClassNotFoundException ex) { ex.printStackTrace(); } level.initTransient(); } // save in file called filename public void save(String filename) { FileOutputStream fos = null; GZIPOutputStream gzos = null; ObjectOutputStream out = null; DataOutputStream outputstream = null; try { fos = new FileOutputStream(filename); gzos = new GZIPOutputStream(fos); outputstream = new DataOutputStream(gzos); outputstream.writeInt(0x271bb788); outputstream.writeByte(2); out = new ObjectOutputStream(gzos); out.writeObject(level); outputstream.close(); out.close(); System.out.println("Saving level "+filename+" successful"); } catch(IOException ex) { ex.printStackTrace(); } } // prints all there is to know about a level, except for the blocks data public void printInfo() { if (level == null) { return; } System.out.println("Level info:"); System.out.println("name: "+level.name); System.out.println("creator: "+level.creator); System.out.println("createTime: "+(DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL).format(level.createTime))); System.out.println("width: "+level.width); System.out.println("height: "+level.height); System.out.println("depth: "+level.depth); System.out.println("spawnpoint: ["+level.xSpawn+","+level.ySpawn+","+level.zSpawn+"]"); System.out.println("spawn rotation: "+level.rotSpawn); } // safe to use method, return value let's you know if anything was changed public boolean setTile(int x, int y, int z, int t) { if ( x >=0 && x < level.width && y >=0 && y < level.depth && z >=0 && z < level.height && t >= 0 && t <= 37 ) { if (t == 8 || t == 10) { level.setTile(x,y,z,t); } else if (t >= 0 && t <= 18) { level.setTileNoUpdate(x,y,z,t); } return true; } return false; } // gets you the level coordinates from the blocks array index public int getCoords(int index) { int x = index % level.width; index = (index-x) / level.width; int z = index % level.height; int y = (index-z) / level.height; return new int {x, y, z}; } public void clearBlocks() { for (int i=0; i<level.blocks.length; i++) { level.blocks[i] = 0; } } public void floor(int y, int type) { for (int i=0; i<level.width; i++) { for (int j=0; j<level.height; j++) { setTile(i,y,j,type); } } } public void wallX(int x1, int x2, int z, int y, int height, int type) { for (int i=x1; i<=x2; i++) { for (int j=y; j<y+height; j++) { if (!setTile(i,j,z,type)) { System.out.println("Warning: a tile got ignored while building a wallX: ["+i+","+j+","+z+"]"); } } } } public void wallZ(int x, int z1, int z2, int y, int height, int type) { for (int i=z1; i<=z2; i++) { for (int j=y; j<y+height; j++) { if (!setTile(x,j,i,type)) { System.out.println("Warning: a tile got ignored while building a wallZ: ["+x+","+j+","+i+"]"); } } } } // substitute all of block type 'from' to 'to' :) returning the number of blocks altered public int substitute(byte from, byte to) { int count=0; for (int i=0; i<level.blocks.length; i++) { if (level.blocks[i] == from) { level.blocks[i] = to; count++; } } return count; } public void setSize(int x, int y, int z) { level.setData(x, y, z, new byte[x*y*z]); } public static void main(String args) { LevelEditor le = new LevelEditor(); String filename = "server_level.dat"; if(args.length > 0) { filename = args[0]; le.load(filename); if (le.level == null) { System.out.println("Loading level "+filename+" failed"); return; } } else { le.level = new com.mojang.minecraft.level.Level(); } // Do some fancy editing here // set a custom size: 256 wide, 128 high, 512 length le.setSize(256, 128, 512); // first, let's clear out the field le.clearBlocks(); // add a bunch of walls to fill the lower part of the level for (int i=0; i<le.level.width; i++) { le.wallX(0,le.level.height-1,i,0,(int)le.level.getWaterLevel()-1,3); } // lay the floor le.floor((int)le.level.getWaterLevel()-1,2); // let the level find a spawn location for us le.level.findSpawn(); // Leave our fingerprint le.level.creator = "Minecrafter"; le.level.name = "A Custom World"; le.level.createTime = System.currentTimeMillis(); le.save(filename); le.printInfo(); } }


Para ayudar a obtener los bytes correctos para diferentes tipos de bloques, también puede usar esta clase



Bloques de clase pública {public static final byte air = (byte) 0; rock de byte final estático público = (byte) 1; public static final byte grass = (byte) 2; public static final byte dirt = (byte) 3; piedra de byte final estática pública = (byte) 4; madera de byte final estática pública = (byte) 5; arbusto de byte final estático público = (byte) 6; byte final estático público blackrock = (byte) 7; agua pública estática final byte = (byte) 8; byte final estático público waterstill = (byte) 9; público estático final byte lava = (byte) 10; byte final estático público lavastill = (byte) 11; arena de byte final estática pública = (byte) 12; público estático final byte gravel = (byte) 13; byte final estático público goldrock = (byte) 14; byte final estático público ironrock = (byte) 15; carbón de byte final estático público = (byte) 16; tronco de byte final estático público = (byte) 17; public static final byte leaf = (byte) 18; esponja de byte final estático público = (byte) 19; vidrio de byte final estático público = (byte) 20; byte final estático público rojo = (byte) 21; byte final estático público naranja = (byte) 22; byte final estático público amarillo = (byte) 23; byte final estático público verde claro = (byte) 24; byte final estático público verde = (byte) 25; byte final estático público aquagreen = (byte) 26; byte final estático público cian = (byte) 27; byte final estático público azul claro = (byte) 28; byte final estático público azul = (byte) 29; byte final estático público púrpura = (byte) 30; byte final estático público lightpurple = (byte) 31; byte final estático público rosa = (byte) 32; byte final estático público darkpink = (byte) 33; byte final estático público darkgrey = (byte) 34; byte final estático público gris claro = (byte) 35; byte final estático público blanco = (byte) 36; byte final estático público yellowflower = (byte) 37; byte final estático público redflower = (byte) 38; hongo de byte final estático público = (byte) 39; public static final byte redmushroom = (byte) 40; public static final byte goldsolid = (byte) 41; public static final byte iron = (byte) 42; public static final byte escalera llena = (byte) 43; public static final byte escalera paso = (byte) 44; ladrillo de byte final estático público = (byte) 45; byte final estático público tnt = (byte) 46; librería pública estática de bytes finales = (byte) 47; byte final estático público stonevine = (byte) 48; público estático último byte obsidiana = (byte) 49; }


Añade un comentario de Recursos de desarrollo / Ejemplo de clase de edición de nivel clásico de Minecraft
¡Comentario enviado con éxito! Lo revisaremos en las próximas horas.