Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lDEVinux
GitHub Repository: lDEVinux/eaglercraft
Path: blob/main/samples/ayunami2000/MapPacketCodec.java
8641 views
1
package ayunami2000;
2
3
import java.awt.image.BufferedImage;
4
import java.io.ByteArrayOutputStream;
5
import java.io.DataOutputStream;
6
import java.io.IOException;
7
import java.util.zip.Deflater;
8
import java.util.zip.DeflaterOutputStream;
9
10
public class MapPacketCodec {
11
12
public interface FragmentHandler {
13
void sendFragment(byte[] data, boolean isLastFragment);
14
}
15
16
public enum PixelFormat {
17
R5_G6_B5, R8_G8_B8
18
}
19
20
public final int mapId;
21
private Deflater deflate = null;
22
private PixelFormat pixelFormat = PixelFormat.R5_G6_B5;
23
private int[] pixels = null;
24
private int[] pallete = null;
25
private boolean palleteIsSet = false;
26
private boolean palleteIsDirty = false;
27
28
/**
29
* @param mapId the ID of the map item to write to
30
*/
31
public MapPacketCodec(int mapId) {
32
this.mapId = mapId;
33
}
34
35
/**
36
* @param enable enables java.util.zip deflate on packets encoded by this class
37
*/
38
public MapPacketCodec deflate(boolean enable) {
39
deflate(enable ? 5 : 0);
40
return this;
41
}
42
43
/**
44
* @param level sets or disables compression level (0-9)
45
*/
46
public MapPacketCodec deflate(int level) {
47
deflate = level > 0 ? new Deflater(level) : null;
48
return this;
49
}
50
51
/**
52
* @param pix sets if pixels should be encoded as 16 bits per pixel or 24 bits per pixel
53
*/
54
public MapPacketCodec pixelFormat(PixelFormat pix) {
55
pixelFormat = pix == null ? PixelFormat.R5_G6_B5 : pix;
56
return this;
57
}
58
59
/**
60
* @param pixels If pallete is disabled, array of 16384 integers each containing the RGB of a pixel. If
61
* pallete is enabled, array of 16384 integers each containing an index in the current pallete between 0 and 255
62
*/
63
public MapPacketCodec setPixels(int[] pixels) {
64
if(pixels != null && pixels.length != 16384) {
65
throw new IllegalArgumentException("Pixel array must be 16384 pixels long");
66
}
67
this.pixels = pixels;
68
return this;
69
}
70
71
/**
72
* @param pixels a 128x128 RGB java.awt.image.BufferedImage, this will disable the pallete
73
*/
74
public MapPacketCodec setPixels(BufferedImage pixels) {
75
if(pixels.getWidth() != 128 || pixels.getHeight() != 128) {
76
throw new IllegalArgumentException("BufferedImage must be 128x128 pixels");
77
}
78
palleteIsSet = false;
79
this.pallete = null;
80
palleteIsDirty = false;
81
int[] pxls = new int[16384];
82
pixels.getRGB(0, 0, 128, 128, pxls, 0, 128);
83
setPixels(pxls);
84
return this;
85
}
86
87
/**
88
* sets and enables the pallete, or disables it if 'pallete' is null
89
*
90
* @param pallete an array of any size between 1 and 256 containing integers each representing a single RGB color
91
*/
92
public MapPacketCodec setPallete(int[] pallete) {
93
boolean b = pallete != null;
94
if(b) {
95
palleteIsSet = true;
96
this.pallete = pallete;
97
palleteIsDirty = true;
98
}else {
99
if(pixels != null && this.pallete != null) {
100
int[] px = pixels;
101
pixels = new int[16384];
102
for(int i = 0; i < 16384; ++i) {
103
int j = px[i];
104
pixels[i] = this.pallete[j >= this.pallete.length ? 0 : j];
105
}
106
}
107
this.pallete = null;
108
palleteIsSet = false;
109
palleteIsDirty = false;
110
}
111
return this;
112
}
113
114
/**
115
* Disables the pallete
116
*/
117
public MapPacketCodec clearPallete() {
118
setPallete(null);
119
return this;
120
}
121
122
/*
123
* Operations:
124
*
125
* - 0: disable engine
126
* - 1: compressed data
127
*
128
* - 2: set pixels R8_G8_B8
129
* - 3: set pixels R5_G6_B5
130
* - 4: set pallete R8_G8_B8
131
* - 5: set pallete R5_G6_B5
132
* - 6: set pixels via pallete
133
* - 7: set pallete and pixels R8_G8_B8
134
* - 8: set pallete and pixels R5_G6_B5
135
*
136
*/
137
138
/**
139
* takes the current pixels array and writes it to a packet and returns it, or returns null if the current pixels array has not changed
140
*/
141
public byte[] getNextPacket() {
142
if(pixels == null) {
143
return null;
144
}
145
try {
146
ByteArrayOutputStream o = new ByteArrayOutputStream();
147
DataOutputStream s;
148
if(deflate != null) {
149
o.write(1);
150
s = new DataOutputStream(new DeflaterOutputStream(o, deflate));
151
}else {
152
s = new DataOutputStream(o);
153
}
154
if(!palleteIsSet || pallete == null) {
155
palleteIsSet = false;
156
if(pixelFormat == PixelFormat.R5_G6_B5) {
157
s.write(3);
158
for(int i = 0; i < 16384; ++i) {
159
int j = pixels[i];
160
int r = (j >> 19) & 0x1F;
161
int g = (j >> 10) & 0x3F;
162
int b = (j >> 3) & 0x1F;
163
s.writeShort((r << 11) | (g << 5) | b);
164
}
165
}else if(pixelFormat == PixelFormat.R8_G8_B8) {
166
s.write(2);
167
for(int i = 0; i < 16384; ++i) {
168
int j = pixels[i];
169
s.write((j >> 16) & 0xFF);
170
s.write((j >> 8) & 0xFF);
171
s.write(j & 0xFF);
172
}
173
}else {
174
return null; // ?
175
}
176
}else {
177
if(palleteIsDirty) {
178
if(pixelFormat == PixelFormat.R5_G6_B5) {
179
s.write(8);
180
s.write(pallete.length);
181
for(int i = 0; i < pallete.length; ++i) {
182
int j = pallete[i];
183
int r = (j >> 19) & 0x1F;
184
int g = (j >> 10) & 0x3F;
185
int b = (j >> 3) & 0x1F;
186
s.writeShort((r << 11) | (g << 5) | b);
187
}
188
}else if(pixelFormat == PixelFormat.R8_G8_B8) {
189
s.write(7);
190
s.write(pallete.length);
191
for(int i = 0; i < pallete.length; ++i) {
192
int j = pallete[i];
193
s.write((j >> 16) & 0xFF);
194
s.write((j >> 8) & 0xFF);
195
s.write(j & 0xFF);
196
}
197
}else {
198
return null; // ?
199
}
200
palleteIsDirty = false;
201
}else {
202
s.write(6);
203
}
204
for(int i = 0; i < 16384; ++i) {
205
s.write(pixels[i]);
206
}
207
}
208
pixels = null;
209
s.close();
210
return o.toByteArray();
211
}catch(IOException e) {
212
throw new RuntimeException("Failed to write ayunami map packet");
213
}
214
}
215
216
public byte[] getDisablePacket() {
217
try {
218
palleteIsSet = false;
219
palleteIsDirty = false;
220
pallete = null;
221
pixels = null;
222
ByteArrayOutputStream o = new ByteArrayOutputStream();
223
DataOutputStream s = new DataOutputStream(o);
224
s.writeShort(mapId);
225
s.write(0);
226
return o.toByteArray();
227
}catch(IOException e) {
228
throw new RuntimeException("Failed to write ayunami map packet");
229
}
230
}
231
232
}
233
234