Path: blob/main/samples/ayunami2000/MapPacketCodec.java
8641 views
package ayunami2000;12import java.awt.image.BufferedImage;3import java.io.ByteArrayOutputStream;4import java.io.DataOutputStream;5import java.io.IOException;6import java.util.zip.Deflater;7import java.util.zip.DeflaterOutputStream;89public class MapPacketCodec {1011public interface FragmentHandler {12void sendFragment(byte[] data, boolean isLastFragment);13}1415public enum PixelFormat {16R5_G6_B5, R8_G8_B817}1819public final int mapId;20private Deflater deflate = null;21private PixelFormat pixelFormat = PixelFormat.R5_G6_B5;22private int[] pixels = null;23private int[] pallete = null;24private boolean palleteIsSet = false;25private boolean palleteIsDirty = false;2627/**28* @param mapId the ID of the map item to write to29*/30public MapPacketCodec(int mapId) {31this.mapId = mapId;32}3334/**35* @param enable enables java.util.zip deflate on packets encoded by this class36*/37public MapPacketCodec deflate(boolean enable) {38deflate(enable ? 5 : 0);39return this;40}4142/**43* @param level sets or disables compression level (0-9)44*/45public MapPacketCodec deflate(int level) {46deflate = level > 0 ? new Deflater(level) : null;47return this;48}4950/**51* @param pix sets if pixels should be encoded as 16 bits per pixel or 24 bits per pixel52*/53public MapPacketCodec pixelFormat(PixelFormat pix) {54pixelFormat = pix == null ? PixelFormat.R5_G6_B5 : pix;55return this;56}5758/**59* @param pixels If pallete is disabled, array of 16384 integers each containing the RGB of a pixel. If60* pallete is enabled, array of 16384 integers each containing an index in the current pallete between 0 and 25561*/62public MapPacketCodec setPixels(int[] pixels) {63if(pixels != null && pixels.length != 16384) {64throw new IllegalArgumentException("Pixel array must be 16384 pixels long");65}66this.pixels = pixels;67return this;68}6970/**71* @param pixels a 128x128 RGB java.awt.image.BufferedImage, this will disable the pallete72*/73public MapPacketCodec setPixels(BufferedImage pixels) {74if(pixels.getWidth() != 128 || pixels.getHeight() != 128) {75throw new IllegalArgumentException("BufferedImage must be 128x128 pixels");76}77palleteIsSet = false;78this.pallete = null;79palleteIsDirty = false;80int[] pxls = new int[16384];81pixels.getRGB(0, 0, 128, 128, pxls, 0, 128);82setPixels(pxls);83return this;84}8586/**87* sets and enables the pallete, or disables it if 'pallete' is null88*89* @param pallete an array of any size between 1 and 256 containing integers each representing a single RGB color90*/91public MapPacketCodec setPallete(int[] pallete) {92boolean b = pallete != null;93if(b) {94palleteIsSet = true;95this.pallete = pallete;96palleteIsDirty = true;97}else {98if(pixels != null && this.pallete != null) {99int[] px = pixels;100pixels = new int[16384];101for(int i = 0; i < 16384; ++i) {102int j = px[i];103pixels[i] = this.pallete[j >= this.pallete.length ? 0 : j];104}105}106this.pallete = null;107palleteIsSet = false;108palleteIsDirty = false;109}110return this;111}112113/**114* Disables the pallete115*/116public MapPacketCodec clearPallete() {117setPallete(null);118return this;119}120121/*122* Operations:123*124* - 0: disable engine125* - 1: compressed data126*127* - 2: set pixels R8_G8_B8128* - 3: set pixels R5_G6_B5129* - 4: set pallete R8_G8_B8130* - 5: set pallete R5_G6_B5131* - 6: set pixels via pallete132* - 7: set pallete and pixels R8_G8_B8133* - 8: set pallete and pixels R5_G6_B5134*135*/136137/**138* takes the current pixels array and writes it to a packet and returns it, or returns null if the current pixels array has not changed139*/140public byte[] getNextPacket() {141if(pixels == null) {142return null;143}144try {145ByteArrayOutputStream o = new ByteArrayOutputStream();146DataOutputStream s;147if(deflate != null) {148o.write(1);149s = new DataOutputStream(new DeflaterOutputStream(o, deflate));150}else {151s = new DataOutputStream(o);152}153if(!palleteIsSet || pallete == null) {154palleteIsSet = false;155if(pixelFormat == PixelFormat.R5_G6_B5) {156s.write(3);157for(int i = 0; i < 16384; ++i) {158int j = pixels[i];159int r = (j >> 19) & 0x1F;160int g = (j >> 10) & 0x3F;161int b = (j >> 3) & 0x1F;162s.writeShort((r << 11) | (g << 5) | b);163}164}else if(pixelFormat == PixelFormat.R8_G8_B8) {165s.write(2);166for(int i = 0; i < 16384; ++i) {167int j = pixels[i];168s.write((j >> 16) & 0xFF);169s.write((j >> 8) & 0xFF);170s.write(j & 0xFF);171}172}else {173return null; // ?174}175}else {176if(palleteIsDirty) {177if(pixelFormat == PixelFormat.R5_G6_B5) {178s.write(8);179s.write(pallete.length);180for(int i = 0; i < pallete.length; ++i) {181int j = pallete[i];182int r = (j >> 19) & 0x1F;183int g = (j >> 10) & 0x3F;184int b = (j >> 3) & 0x1F;185s.writeShort((r << 11) | (g << 5) | b);186}187}else if(pixelFormat == PixelFormat.R8_G8_B8) {188s.write(7);189s.write(pallete.length);190for(int i = 0; i < pallete.length; ++i) {191int j = pallete[i];192s.write((j >> 16) & 0xFF);193s.write((j >> 8) & 0xFF);194s.write(j & 0xFF);195}196}else {197return null; // ?198}199palleteIsDirty = false;200}else {201s.write(6);202}203for(int i = 0; i < 16384; ++i) {204s.write(pixels[i]);205}206}207pixels = null;208s.close();209return o.toByteArray();210}catch(IOException e) {211throw new RuntimeException("Failed to write ayunami map packet");212}213}214215public byte[] getDisablePacket() {216try {217palleteIsSet = false;218palleteIsDirty = false;219pallete = null;220pixels = null;221ByteArrayOutputStream o = new ByteArrayOutputStream();222DataOutputStream s = new DataOutputStream(o);223s.writeShort(mapId);224s.write(0);225return o.toByteArray();226}catch(IOException e) {227throw new RuntimeException("Failed to write ayunami map packet");228}229}230231}232233234