mirror of
https://git.zelz.net/catfoolyou/Project164.git
synced 2025-12-16 04:37:41 +00:00
250 errors
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public class AbortedException extends RuntimeException {
|
||||
|
||||
}
|
||||
233
src/main/java/net/lax1dude/eaglercraft/AssetRepository.java
Normal file
233
src/main/java/net/lax1dude/eaglercraft/AssetRepository.java
Normal file
@@ -0,0 +1,233 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.jcraft.jzlib.CRC32;
|
||||
import com.jcraft.jzlib.GZIPInputStream;
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class AssetRepository {
|
||||
|
||||
private static final HashMap<String,byte[]> filePool = new HashMap<>();
|
||||
public static final HashMap<String, String> fileNameOverrides = new HashMap<>();
|
||||
|
||||
public static final void loadOverrides(JSONObject json) {
|
||||
JSONObject overrides = json.optJSONObject("assetOverrides", null);
|
||||
if (overrides != null) {
|
||||
for (String fileName : overrides.keySet()) {
|
||||
if(fileName.startsWith("/")) fileName = fileName.substring(1);
|
||||
String val = overrides.optString(fileName, null);
|
||||
if (val != null) {
|
||||
AssetRepository.fileNameOverrides.put(fileName, val);
|
||||
if (!fileName.toLowerCase().endsWith(".mp3")) {
|
||||
loadFromURL(fileName, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final void install(byte[] pkg) throws IOException {
|
||||
EaglerInputStream in = new EaglerInputStream(pkg);
|
||||
|
||||
byte[] header = new byte[8];
|
||||
in.read(header);
|
||||
String type = readASCII(header);
|
||||
|
||||
if("EAGPKG$$".equals(type)) {
|
||||
int l = pkg.length - 16;
|
||||
if(l < 1) {
|
||||
throw new IOException("EPK file is incomplete");
|
||||
}
|
||||
byte[] endCode = new byte[] { (byte)':', (byte)':', (byte)':', (byte)'Y',
|
||||
(byte)'E', (byte)'E', (byte)':', (byte)'>' };
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
if(pkg[pkg.length - 8 + i] != endCode[i]) {
|
||||
throw new IOException("EPK file is missing EOF code (:::YEE:>)");
|
||||
}
|
||||
}
|
||||
loadNew(new EaglerInputStream(pkg, 8, pkg.length - 16));
|
||||
}else if("EAGPKG!!".equals(type)) {
|
||||
loadOld(in);
|
||||
}else {
|
||||
throw new IOException("invalid epk file type '" + type + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private static final int loadShort(InputStream is) throws IOException {
|
||||
return (is.read() << 8) | is.read();
|
||||
}
|
||||
|
||||
private static final int loadInt(InputStream is) throws IOException {
|
||||
return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read();
|
||||
}
|
||||
|
||||
private static final String readASCII(byte[] bytesIn) throws IOException {
|
||||
char[] charIn = new char[bytesIn.length];
|
||||
for(int i = 0; i < bytesIn.length; ++i) {
|
||||
charIn[i] = (char)((int)bytesIn[i] & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
private static final String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = bytesIn.read();
|
||||
char[] charIn = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
charIn[i] = (char)(bytesIn.read() & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
public static final void loadNew(InputStream is) throws IOException {
|
||||
|
||||
String vers = readASCII(is);
|
||||
if(!vers.startsWith("ver2.")) {
|
||||
throw new IOException("Unknown or invalid EPK version: " + vers);
|
||||
}
|
||||
|
||||
is.skip(is.read()); // skip filename
|
||||
is.skip(loadShort(is)); // skip comment
|
||||
is.skip(8); // skip millis date
|
||||
|
||||
int numFiles = loadInt(is);
|
||||
|
||||
char compressionType = (char)is.read();
|
||||
|
||||
InputStream zis;
|
||||
switch(compressionType) {
|
||||
case 'G':
|
||||
zis = new GZIPInputStream(is);
|
||||
break;
|
||||
case 'Z':
|
||||
zis = new InflaterInputStream(is);
|
||||
break;
|
||||
case '0':
|
||||
zis = is;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Invalid or unsupported EPK compression: " + compressionType);
|
||||
}
|
||||
|
||||
int blockFile = ('F' << 24) | ('I' << 16) | ('L' << 8) | 'E';
|
||||
int blockEnd = ('E' << 24) | ('N' << 16) | ('D' << 8) | '$';
|
||||
int blockHead = ('H' << 24) | ('E' << 16) | ('A' << 8) | 'D';
|
||||
|
||||
CRC32 crc32 = new CRC32();
|
||||
int blockType;
|
||||
for(int i = 0; i < numFiles; ++i) {
|
||||
|
||||
blockType = loadInt(zis);
|
||||
|
||||
if(blockType == blockEnd) {
|
||||
throw new IOException("Unexpected END when there are still " + (numFiles - i) + " files remaining");
|
||||
}
|
||||
|
||||
String name = readASCII(zis);
|
||||
int len = loadInt(zis);
|
||||
|
||||
if(i == 0) {
|
||||
if(blockType == blockHead) {
|
||||
byte[] readType = new byte[len];
|
||||
zis.read(readType);
|
||||
if(!"file-type".equals(name) || !"epk/resources".equals(readASCII(readType))) {
|
||||
throw new IOException("EPK is not of file-type 'epk/resources'!");
|
||||
}
|
||||
if(zis.read() != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
continue;
|
||||
}else {
|
||||
throw new IOException("File '" + name + "' did not have a file-type block as the first entry in the file");
|
||||
}
|
||||
}
|
||||
|
||||
if(blockType == blockFile) {
|
||||
if(len < 5) {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
int expectedCRC = loadInt(zis);
|
||||
|
||||
byte[] load = new byte[len - 5];
|
||||
zis.read(load);
|
||||
|
||||
if(len > 5) {
|
||||
crc32.reset();
|
||||
crc32.update(load, 0, load.length);
|
||||
if(expectedCRC != (int)crc32.getValue()) {
|
||||
throw new IOException("File '" + name + "' has an invalid checksum");
|
||||
}
|
||||
}
|
||||
|
||||
if(zis.read() != ':') {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
filePool.put(name, load);
|
||||
|
||||
if(name.endsWith("title/eagtek.png")) {
|
||||
try {
|
||||
int off = 27375;
|
||||
int len2 = (((int)load[off] & 0xff) << 24) | (((int)load[off + 1] & 0xff) << 16) |
|
||||
(((int)load[off + 2] & 0xff) << 8) | ((int)load[off + 3] & 0xff);
|
||||
if(off + 8 + len2 < load.length) {
|
||||
loadNew(new EaglerInputStream(load, off + 8, len2));
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
}
|
||||
}
|
||||
}else {
|
||||
zis.skip(len);
|
||||
}
|
||||
|
||||
if(zis.read() != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
}
|
||||
|
||||
if(loadInt(zis) != blockEnd) {
|
||||
throw new IOException("EPK missing END$ object");
|
||||
}
|
||||
|
||||
zis.close();
|
||||
}
|
||||
|
||||
public static final void loadOld(InputStream is) throws IOException {
|
||||
DataInputStream in = new DataInputStream(is);
|
||||
in.readUTF();
|
||||
in = new DataInputStream(new InflaterInputStream(is));
|
||||
String s = null;
|
||||
SHA1Digest dg = new SHA1Digest();
|
||||
while("<file>".equals(s = in.readUTF())) {
|
||||
String path = in.readUTF();
|
||||
byte[] digest = new byte[20];
|
||||
byte[] digest2 = new byte[20];
|
||||
in.read(digest);
|
||||
int len = in.readInt();
|
||||
byte[] file = new byte[len];
|
||||
in.read(file);
|
||||
if(filePool.containsKey(path)) continue;
|
||||
dg.update(file, 0, len); dg.doFinal(digest2, 0);
|
||||
if(!Arrays.equals(digest, digest2)) throw new IOException("invalid file hash for "+path);
|
||||
filePool.put(path, file);
|
||||
if(!"</file>".equals(in.readUTF())) throw new IOException("invalid epk file");
|
||||
}
|
||||
if(in.available() > 0 || !" end".equals(s)) throw new IOException("invalid epk file");
|
||||
}
|
||||
|
||||
public static final byte[] getResource(String path) {
|
||||
if(path.startsWith("/")) path = path.substring(1);
|
||||
return filePool.get(path);
|
||||
}
|
||||
|
||||
public static final void loadFromURL(String path, String url) {
|
||||
filePool.put(path, EaglerAdapter.downloadURL(url));
|
||||
}
|
||||
|
||||
}
|
||||
845
src/main/java/net/lax1dude/eaglercraft/Base64.java
Normal file
845
src/main/java/net/lax1dude/eaglercraft/Base64.java
Normal file
@@ -0,0 +1,845 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Provides Base64 encoding and decoding as defined by <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
|
||||
*
|
||||
* <p>
|
||||
* This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
|
||||
* Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
|
||||
* </p>
|
||||
* <p>
|
||||
* The class can be parameterized in the following manner with various constructors:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>URL-safe mode: Default off.</li>
|
||||
* <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of
|
||||
* 4 in the encoded data.
|
||||
* <li>Line separator: Default is CRLF ("\r\n")</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The URL-safe parameter is only applied to encode operations. Decoding seamlessly handles both modes.
|
||||
* </p>
|
||||
* <p>
|
||||
* Since this class operates directly on byte streams, and not character streams, it is hard-coded to only
|
||||
* encode/decode character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252,
|
||||
* UTF-8, etc).
|
||||
* </p>
|
||||
* <p>
|
||||
* This class is thread-safe.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
|
||||
* @since 1.0
|
||||
*/
|
||||
public class Base64 extends BaseNCodec {
|
||||
|
||||
/**
|
||||
* BASE32 characters are 6 bits in length.
|
||||
* They are formed by taking a block of 3 octets to form a 24-bit string,
|
||||
* which is converted into 4 BASE64 characters.
|
||||
*/
|
||||
private static final int BITS_PER_ENCODED_BYTE = 6;
|
||||
private static final int BYTES_PER_UNENCODED_BLOCK = 3;
|
||||
private static final int BYTES_PER_ENCODED_BLOCK = 4;
|
||||
|
||||
/**
|
||||
* This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
|
||||
* equivalents as specified in Table 1 of RFC 2045.
|
||||
*
|
||||
* Thanks to "commons" project in ws.apache.org for this code.
|
||||
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
|
||||
*/
|
||||
private static final byte[] STANDARD_ENCODE_TABLE = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
|
||||
* changed to - and _ to make the encoded Base64 results more URL-SAFE.
|
||||
* This table is only used when the Base64's mode is set to URL-SAFE.
|
||||
*/
|
||||
private static final byte[] URL_SAFE_ENCODE_TABLE = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
|
||||
};
|
||||
|
||||
/**
|
||||
* This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified
|
||||
* in Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64
|
||||
* alphabet but fall within the bounds of the array are translated to -1.
|
||||
*
|
||||
* Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both
|
||||
* URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
|
||||
*
|
||||
* Thanks to "commons" project in ws.apache.org for this code.
|
||||
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
|
||||
*/
|
||||
private static final byte[] DECODE_TABLE = {
|
||||
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00-0f
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10-1f
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, // 20-2f + - /
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, // 30-3f 0-9
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40-4f A-O
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, // 50-5f P-Z _
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60-6f a-o
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 // 70-7a p-z
|
||||
};
|
||||
|
||||
/**
|
||||
* Base64 uses 6-bit fields.
|
||||
*/
|
||||
/** Mask used to extract 6 bits, used when encoding */
|
||||
private static final int MASK_6BITS = 0x3f;
|
||||
/** Mask used to extract 4 bits, used when decoding final trailing character. */
|
||||
private static final int MASK_4BITS = 0xf;
|
||||
/** Mask used to extract 2 bits, used when decoding final trailing character. */
|
||||
private static final int MASK_2BITS = 0x3;
|
||||
|
||||
// The static final fields above are used for the original static byte[] methods on Base64.
|
||||
// The private member fields below are used with the new streaming approach, which requires
|
||||
// some state be preserved between calls of encode() and decode().
|
||||
|
||||
/**
|
||||
* Decodes Base64 data into octets.
|
||||
* <p>
|
||||
* <b>Note:</b> this method seamlessly handles data encoded in URL-safe or normal mode.
|
||||
* </p>
|
||||
*
|
||||
* @param base64Data
|
||||
* Byte array containing Base64 data
|
||||
* @return Array containing decoded data.
|
||||
*/
|
||||
public static byte[] decodeBase64(final byte[] base64Data) {
|
||||
return new Base64().decode(base64Data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a Base64 String into octets.
|
||||
* <p>
|
||||
* <b>Note:</b> this method seamlessly handles data encoded in URL-safe or normal mode.
|
||||
* </p>
|
||||
*
|
||||
* @param base64String
|
||||
* String containing Base64 data
|
||||
* @return Array containing decoded data.
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] decodeBase64(final String base64String) {
|
||||
return new Base64().decode(base64String);
|
||||
}
|
||||
|
||||
// Implementation of integer encoding used for crypto
|
||||
/**
|
||||
* Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature.
|
||||
*
|
||||
* @param pArray
|
||||
* a byte array containing base64 character data
|
||||
* @return A BigInteger
|
||||
* @since 1.4
|
||||
*/
|
||||
public static BigInteger decodeInteger(final byte[] pArray) {
|
||||
return new BigInteger(1, decodeBase64(pArray));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary data using the base64 algorithm but does not chunk the output.
|
||||
*
|
||||
* @param binaryData
|
||||
* binary data to encode
|
||||
* @return byte[] containing Base64 characters in their UTF-8 representation.
|
||||
*/
|
||||
public static byte[] encodeBase64(final byte[] binaryData) {
|
||||
return encodeBase64(binaryData, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
|
||||
*
|
||||
* @param binaryData
|
||||
* Array containing binary data to encode.
|
||||
* @param isChunked
|
||||
* if {@code true} this encoder will chunk the base64 output into 76 character blocks
|
||||
* @return Base64-encoded data.
|
||||
* @throws IllegalArgumentException
|
||||
* Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
|
||||
*/
|
||||
public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked) {
|
||||
return encodeBase64(binaryData, isChunked, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
|
||||
*
|
||||
* @param binaryData
|
||||
* Array containing binary data to encode.
|
||||
* @param isChunked
|
||||
* if {@code true} this encoder will chunk the base64 output into 76 character blocks
|
||||
* @param urlSafe
|
||||
* if {@code true} this encoder will emit - and _ instead of the usual + and / characters.
|
||||
* <b>Note: no padding is added when encoding using the URL-safe alphabet.</b>
|
||||
* @return Base64-encoded data.
|
||||
* @throws IllegalArgumentException
|
||||
* Thrown when the input array needs an output array bigger than {@link Integer#MAX_VALUE}
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked, final boolean urlSafe) {
|
||||
return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
|
||||
*
|
||||
* @param binaryData
|
||||
* Array containing binary data to encode.
|
||||
* @param isChunked
|
||||
* if {@code true} this encoder will chunk the base64 output into 76 character blocks
|
||||
* @param urlSafe
|
||||
* if {@code true} this encoder will emit - and _ instead of the usual + and / characters.
|
||||
* <b>Note: no padding is added when encoding using the URL-safe alphabet.</b>
|
||||
* @param maxResultSize
|
||||
* The maximum result size to accept.
|
||||
* @return Base64-encoded data.
|
||||
* @throws IllegalArgumentException
|
||||
* Thrown when the input array needs an output array bigger than maxResultSize
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] encodeBase64(final byte[] binaryData, final boolean isChunked,
|
||||
final boolean urlSafe, final int maxResultSize) {
|
||||
if (binaryData == null || binaryData.length == 0) {
|
||||
return binaryData;
|
||||
}
|
||||
|
||||
// Create this so can use the super-class method
|
||||
// Also ensures that the same roundings are performed by the ctor and the code
|
||||
final Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
|
||||
final long len = b64.getEncodedLength(binaryData);
|
||||
if (len > maxResultSize) {
|
||||
throw new IllegalArgumentException("Input array too big, the output array would be bigger (" +
|
||||
len +
|
||||
") than the specified maximum size of " +
|
||||
maxResultSize);
|
||||
}
|
||||
|
||||
return b64.encode(binaryData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character blocks
|
||||
*
|
||||
* @param binaryData
|
||||
* binary data to encode
|
||||
* @return Base64 characters chunked in 76 character blocks
|
||||
*/
|
||||
public static byte[] encodeBase64Chunked(final byte[] binaryData) {
|
||||
return encodeBase64(binaryData, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary data using the base64 algorithm but does not chunk the output.
|
||||
*
|
||||
* NOTE: We changed the behavior of this method from multi-line chunking (commons-codec-1.4) to
|
||||
* single-line non-chunking (commons-codec-1.5).
|
||||
*
|
||||
* @param binaryData
|
||||
* binary data to encode
|
||||
* @return String containing Base64 characters.
|
||||
* @since 1.4 (NOTE: 1.4 chunked the output, whereas 1.5 does not).
|
||||
*/
|
||||
public static String encodeBase64String(final byte[] binaryData) {
|
||||
return new String(encodeBase64(binaryData, false), Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
|
||||
* url-safe variation emits - and _ instead of + and / characters.
|
||||
* <b>Note: no padding is added.</b>
|
||||
* @param binaryData
|
||||
* binary data to encode
|
||||
* @return byte[] containing Base64 characters in their UTF-8 representation.
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] encodeBase64URLSafe(final byte[] binaryData) {
|
||||
return encodeBase64(binaryData, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the output. The
|
||||
* url-safe variation emits - and _ instead of + and / characters.
|
||||
* <b>Note: no padding is added.</b>
|
||||
* @param binaryData
|
||||
* binary data to encode
|
||||
* @return String containing Base64 characters
|
||||
* @since 1.4
|
||||
*/
|
||||
public static String encodeBase64URLSafeString(final byte[] binaryData) {
|
||||
return new String(encodeBase64(binaryData, false, true), Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature.
|
||||
*
|
||||
* @param bigInteger
|
||||
* a BigInteger
|
||||
* @return A byte array containing base64 character data
|
||||
* @throws NullPointerException
|
||||
* if null is passed in
|
||||
* @since 1.4
|
||||
*/
|
||||
public static byte[] encodeInteger(final BigInteger bigInteger) {
|
||||
return encodeBase64(toIntegerBytes(bigInteger), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
|
||||
* method treats whitespace as valid.
|
||||
*
|
||||
* @param arrayOctet
|
||||
* byte array to test
|
||||
* @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
|
||||
* {@code false}, otherwise
|
||||
* @deprecated 1.5 Use {@link #isBase64(byte[])}, will be removed in 2.0.
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isArrayByteBase64(final byte[] arrayOctet) {
|
||||
return isBase64(arrayOctet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the {@code octet} is in the base 64 alphabet.
|
||||
*
|
||||
* @param octet
|
||||
* The value to test
|
||||
* @return {@code true} if the value is defined in the the base 64 alphabet, {@code false} otherwise.
|
||||
* @since 1.4
|
||||
*/
|
||||
public static boolean isBase64(final byte octet) {
|
||||
return octet == PAD_DEFAULT || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a given byte array to see if it contains only valid characters within the Base64 alphabet. Currently the
|
||||
* method treats whitespace as valid.
|
||||
*
|
||||
* @param arrayOctet
|
||||
* byte array to test
|
||||
* @return {@code true} if all bytes are valid characters in the Base64 alphabet or if the byte array is empty;
|
||||
* {@code false}, otherwise
|
||||
* @since 1.5
|
||||
*/
|
||||
public static boolean isBase64(final byte[] arrayOctet) {
|
||||
for (int i = 0; i < arrayOctet.length; i++) {
|
||||
if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a given String to see if it contains only valid characters within the Base64 alphabet. Currently the
|
||||
* method treats whitespace as valid.
|
||||
*
|
||||
* @param base64
|
||||
* String to test
|
||||
* @return {@code true} if all characters in the String are valid characters in the Base64 alphabet or if
|
||||
* the String is empty; {@code false}, otherwise
|
||||
* @since 1.5
|
||||
*/
|
||||
public static boolean isBase64(final String base64) {
|
||||
return isBase64(base64.getBytes(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte-array representation of a {@code BigInteger} without sign bit.
|
||||
*
|
||||
* @param bigInt
|
||||
* {@code BigInteger} to be converted
|
||||
* @return a byte array representation of the BigInteger parameter
|
||||
*/
|
||||
static byte[] toIntegerBytes(final BigInteger bigInt) {
|
||||
int bitlen = bigInt.bitLength();
|
||||
// round bitlen
|
||||
bitlen = ((bitlen + 7) >> 3) << 3;
|
||||
final byte[] bigBytes = bigInt.toByteArray();
|
||||
|
||||
if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) {
|
||||
return bigBytes;
|
||||
}
|
||||
// set up params for copying everything but sign bit
|
||||
int startSrc = 0;
|
||||
int len = bigBytes.length;
|
||||
|
||||
// if bigInt is exactly byte-aligned, just skip signbit in copy
|
||||
if ((bigInt.bitLength() % 8) == 0) {
|
||||
startSrc = 1;
|
||||
len--;
|
||||
}
|
||||
final int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec
|
||||
final byte[] resizedBytes = new byte[bitlen / 8];
|
||||
System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len);
|
||||
return resizedBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
|
||||
* to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
|
||||
* between the two modes.
|
||||
*/
|
||||
private final byte[] encodeTable;
|
||||
|
||||
// Only one decode table currently; keep for consistency with Base32 code
|
||||
private final byte[] decodeTable = DECODE_TABLE;
|
||||
|
||||
/**
|
||||
* Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
|
||||
*/
|
||||
private final byte[] lineSeparator;
|
||||
|
||||
/**
|
||||
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
|
||||
* {@code decodeSize = 3 + lineSeparator.length;}
|
||||
*/
|
||||
private final int decodeSize;
|
||||
|
||||
/**
|
||||
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
|
||||
* {@code encodeSize = 4 + lineSeparator.length;}
|
||||
*/
|
||||
private final int encodeSize;
|
||||
|
||||
/**
|
||||
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
|
||||
* <p>
|
||||
* When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* When decoding all variants are supported.
|
||||
* </p>
|
||||
*/
|
||||
public Base64() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode.
|
||||
* <p>
|
||||
* When encoding the line length is 76, the line separator is CRLF, and the encoding table is STANDARD_ENCODE_TABLE.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* When decoding all variants are supported.
|
||||
* </p>
|
||||
*
|
||||
* @param urlSafe
|
||||
* if {@code true}, URL-safe encoding is used. In most cases this should be set to
|
||||
* {@code false}.
|
||||
* @since 1.4
|
||||
*/
|
||||
public Base64(final boolean urlSafe) {
|
||||
this(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
|
||||
* <p>
|
||||
* When encoding the line length is given in the constructor, the line separator is CRLF, and the encoding table is
|
||||
* STANDARD_ENCODE_TABLE.
|
||||
* </p>
|
||||
* <p>
|
||||
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
|
||||
* </p>
|
||||
* <p>
|
||||
* When decoding all variants are supported.
|
||||
* </p>
|
||||
*
|
||||
* @param lineLength
|
||||
* Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
|
||||
* 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
|
||||
* decoding.
|
||||
* @since 1.4
|
||||
*/
|
||||
public Base64(final int lineLength) {
|
||||
this(lineLength, CHUNK_SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
|
||||
* <p>
|
||||
* When encoding the line length and line separator are given in the constructor, and the encoding table is
|
||||
* STANDARD_ENCODE_TABLE.
|
||||
* </p>
|
||||
* <p>
|
||||
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
|
||||
* </p>
|
||||
* <p>
|
||||
* When decoding all variants are supported.
|
||||
* </p>
|
||||
*
|
||||
* @param lineLength
|
||||
* Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
|
||||
* 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
|
||||
* decoding.
|
||||
* @param lineSeparator
|
||||
* Each line of encoded data will end with this sequence of bytes.
|
||||
* @throws IllegalArgumentException
|
||||
* Thrown when the provided lineSeparator included some base64 characters.
|
||||
* @since 1.4
|
||||
*/
|
||||
public Base64(final int lineLength, final byte[] lineSeparator) {
|
||||
this(lineLength, lineSeparator, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
|
||||
* <p>
|
||||
* When encoding the line length and line separator are given in the constructor, and the encoding table is
|
||||
* STANDARD_ENCODE_TABLE.
|
||||
* </p>
|
||||
* <p>
|
||||
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
|
||||
* </p>
|
||||
* <p>
|
||||
* When decoding all variants are supported.
|
||||
* </p>
|
||||
*
|
||||
* @param lineLength
|
||||
* Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
|
||||
* 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
|
||||
* decoding.
|
||||
* @param lineSeparator
|
||||
* Each line of encoded data will end with this sequence of bytes.
|
||||
* @param urlSafe
|
||||
* Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode
|
||||
* operations. Decoding seamlessly handles both modes.
|
||||
* <b>Note: no padding is added when using the URL-safe alphabet.</b>
|
||||
* @throws IllegalArgumentException
|
||||
* Thrown when the {@code lineSeparator} contains Base64 characters.
|
||||
* @since 1.4
|
||||
*/
|
||||
public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
|
||||
this(lineLength, lineSeparator, urlSafe, CodecPolicy.LENIANT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
|
||||
* <p>
|
||||
* When encoding the line length and line separator are given in the constructor, and the encoding table is
|
||||
* STANDARD_ENCODE_TABLE.
|
||||
* </p>
|
||||
* <p>
|
||||
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
|
||||
* </p>
|
||||
* <p>
|
||||
* When decoding all variants are supported.
|
||||
* </p>
|
||||
*
|
||||
* @param lineLength
|
||||
* Each line of encoded data will be at most of the given length (rounded down to nearest multiple of
|
||||
* 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when
|
||||
* decoding.
|
||||
* @param lineSeparator
|
||||
* Each line of encoded data will end with this sequence of bytes.
|
||||
* @param urlSafe
|
||||
* Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode
|
||||
* operations. Decoding seamlessly handles both modes.
|
||||
* <b>Note: no padding is added when using the URL-safe alphabet.</b>
|
||||
* @param decodingPolicy The decoding policy.
|
||||
* @throws IllegalArgumentException
|
||||
* Thrown when the {@code lineSeparator} contains Base64 characters.
|
||||
* @since 1.15
|
||||
*/
|
||||
public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe, final CodecPolicy decodingPolicy) {
|
||||
super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK,
|
||||
lineLength,
|
||||
lineSeparator == null ? 0 : lineSeparator.length,
|
||||
PAD_DEFAULT,
|
||||
decodingPolicy);
|
||||
// TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
|
||||
// @see test case Base64Test.testConstructors()
|
||||
if (lineSeparator != null) {
|
||||
if (containsAlphabetOrPad(lineSeparator)) {
|
||||
final String sep = new String(lineSeparator, Charset.forName("UTF-8"));
|
||||
throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
|
||||
}
|
||||
if (lineLength > 0){ // null line-sep forces no chunking rather than throwing IAE
|
||||
this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
|
||||
this.lineSeparator = new byte[lineSeparator.length];
|
||||
System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
|
||||
} else {
|
||||
this.encodeSize = BYTES_PER_ENCODED_BLOCK;
|
||||
this.lineSeparator = null;
|
||||
}
|
||||
} else {
|
||||
this.encodeSize = BYTES_PER_ENCODED_BLOCK;
|
||||
this.lineSeparator = null;
|
||||
}
|
||||
this.decodeSize = this.encodeSize - 1;
|
||||
this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
|
||||
}
|
||||
|
||||
// Implementation of the Encoder Interface
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
|
||||
* with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
|
||||
* call is not necessary when decoding, but it doesn't hurt, either.
|
||||
* </p>
|
||||
* <p>
|
||||
* Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
|
||||
* silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
|
||||
* garbage-out philosophy: it will not check the provided data for validity.
|
||||
* </p>
|
||||
* <p>
|
||||
* Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
|
||||
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
|
||||
* </p>
|
||||
*
|
||||
* @param in
|
||||
* byte[] array of ascii data to base64 decode.
|
||||
* @param inPos
|
||||
* Position to start reading data from.
|
||||
* @param inAvail
|
||||
* Amount of bytes available from input for decoding.
|
||||
* @param context
|
||||
* the context to be used
|
||||
*/
|
||||
@Override
|
||||
void decode(final byte[] in, int inPos, final int inAvail, final Context context) {
|
||||
if (context.eof) {
|
||||
return;
|
||||
}
|
||||
if (inAvail < 0) {
|
||||
context.eof = true;
|
||||
}
|
||||
for (int i = 0; i < inAvail; i++) {
|
||||
final byte[] buffer = ensureBufferSize(decodeSize, context);
|
||||
final byte b = in[inPos++];
|
||||
if (b == pad) {
|
||||
// We're done.
|
||||
context.eof = true;
|
||||
break;
|
||||
}
|
||||
if (b >= 0 && b < DECODE_TABLE.length) {
|
||||
final int result = DECODE_TABLE[b];
|
||||
if (result >= 0) {
|
||||
context.modulus = (context.modulus+1) % BYTES_PER_ENCODED_BLOCK;
|
||||
context.ibitWorkArea = (context.ibitWorkArea << BITS_PER_ENCODED_BYTE) + result;
|
||||
if (context.modulus == 0) {
|
||||
buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 16) & MASK_8BITS);
|
||||
buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
|
||||
buffer[context.pos++] = (byte) (context.ibitWorkArea & MASK_8BITS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Two forms of EOF as far as base64 decoder is concerned: actual
|
||||
// EOF (-1) and first time '=' character is encountered in stream.
|
||||
// This approach makes the '=' padding characters completely optional.
|
||||
if (context.eof && context.modulus != 0) {
|
||||
final byte[] buffer = ensureBufferSize(decodeSize, context);
|
||||
|
||||
// We have some spare bits remaining
|
||||
// Output all whole multiples of 8 bits and ignore the rest
|
||||
switch (context.modulus) {
|
||||
// case 0 : // impossible, as excluded above
|
||||
case 1 : // 6 bits - either ignore entirely, or raise an exception
|
||||
validateTrailingCharacter();
|
||||
break;
|
||||
case 2 : // 12 bits = 8 + 4
|
||||
validateCharacter(MASK_4BITS, context);
|
||||
context.ibitWorkArea = context.ibitWorkArea >> 4; // dump the extra 4 bits
|
||||
buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
|
||||
break;
|
||||
case 3 : // 18 bits = 8 + 8 + 2
|
||||
validateCharacter(MASK_2BITS, context);
|
||||
context.ibitWorkArea = context.ibitWorkArea >> 2; // dump 2 bits
|
||||
buffer[context.pos++] = (byte) ((context.ibitWorkArea >> 8) & MASK_8BITS);
|
||||
buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Impossible modulus " + context.modulus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
|
||||
* the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, to flush last
|
||||
* remaining bytes (if not multiple of 3).
|
||||
* </p>
|
||||
* <p><b>Note: no padding is added when encoding using the URL-safe alphabet.</b></p>
|
||||
* <p>
|
||||
* Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
|
||||
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
|
||||
* </p>
|
||||
*
|
||||
* @param in
|
||||
* byte[] array of binary data to base64 encode.
|
||||
* @param inPos
|
||||
* Position to start reading data from.
|
||||
* @param inAvail
|
||||
* Amount of bytes available from input for encoding.
|
||||
* @param context
|
||||
* the context to be used
|
||||
*/
|
||||
@Override
|
||||
void encode(final byte[] in, int inPos, final int inAvail, final Context context) {
|
||||
if (context.eof) {
|
||||
return;
|
||||
}
|
||||
// inAvail < 0 is how we're informed of EOF in the underlying data we're
|
||||
// encoding.
|
||||
if (inAvail < 0) {
|
||||
context.eof = true;
|
||||
if (0 == context.modulus && lineLength == 0) {
|
||||
return; // no leftovers to process and not using chunking
|
||||
}
|
||||
final byte[] buffer = ensureBufferSize(encodeSize, context);
|
||||
final int savedPos = context.pos;
|
||||
switch (context.modulus) { // 0-2
|
||||
case 0 : // nothing to do here
|
||||
break;
|
||||
case 1 : // 8 bits = 6 + 2
|
||||
// top 6 bits:
|
||||
buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 2) & MASK_6BITS];
|
||||
// remaining 2:
|
||||
buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 4) & MASK_6BITS];
|
||||
// URL-SAFE skips the padding to further reduce size.
|
||||
if (encodeTable == STANDARD_ENCODE_TABLE) {
|
||||
buffer[context.pos++] = pad;
|
||||
buffer[context.pos++] = pad;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2 : // 16 bits = 6 + 6 + 4
|
||||
buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 10) & MASK_6BITS];
|
||||
buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 4) & MASK_6BITS];
|
||||
buffer[context.pos++] = encodeTable[(context.ibitWorkArea << 2) & MASK_6BITS];
|
||||
// URL-SAFE skips the padding to further reduce size.
|
||||
if (encodeTable == STANDARD_ENCODE_TABLE) {
|
||||
buffer[context.pos++] = pad;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Impossible modulus " + context.modulus);
|
||||
}
|
||||
context.currentLinePos += context.pos - savedPos; // keep track of current line position
|
||||
// if currentPos == 0 we are at the start of a line, so don't add CRLF
|
||||
if (lineLength > 0 && context.currentLinePos > 0) {
|
||||
System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
|
||||
context.pos += lineSeparator.length;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < inAvail; i++) {
|
||||
final byte[] buffer = ensureBufferSize(encodeSize, context);
|
||||
context.modulus = (context.modulus+1) % BYTES_PER_UNENCODED_BLOCK;
|
||||
int b = in[inPos++];
|
||||
if (b < 0) {
|
||||
b += 256;
|
||||
}
|
||||
context.ibitWorkArea = (context.ibitWorkArea << 8) + b; // BITS_PER_BYTE
|
||||
if (0 == context.modulus) { // 3 bytes = 24 bits = 4 * 6 bits to extract
|
||||
buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 18) & MASK_6BITS];
|
||||
buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 12) & MASK_6BITS];
|
||||
buffer[context.pos++] = encodeTable[(context.ibitWorkArea >> 6) & MASK_6BITS];
|
||||
buffer[context.pos++] = encodeTable[context.ibitWorkArea & MASK_6BITS];
|
||||
context.currentLinePos += BYTES_PER_ENCODED_BLOCK;
|
||||
if (lineLength > 0 && lineLength <= context.currentLinePos) {
|
||||
System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
|
||||
context.pos += lineSeparator.length;
|
||||
context.currentLinePos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the {@code octet} is in the Base64 alphabet.
|
||||
*
|
||||
* @param octet
|
||||
* The value to test
|
||||
* @return {@code true} if the value is defined in the the Base64 alphabet {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
protected boolean isInAlphabet(final byte octet) {
|
||||
return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns our current encode mode. True if we're URL-SAFE, false otherwise.
|
||||
*
|
||||
* @return true if we're in URL-SAFE mode, false otherwise.
|
||||
* @since 1.4
|
||||
*/
|
||||
public boolean isUrlSafe() {
|
||||
return this.encodeTable == URL_SAFE_ENCODE_TABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether decoding the final trailing character is possible in the context
|
||||
* of the set of possible base 64 values.
|
||||
*
|
||||
* <p>The character is valid if the lower bits within the provided mask are zero. This
|
||||
* is used to test the final trailing base-64 digit is zero in the bits that will be discarded.
|
||||
*
|
||||
* @param emptyBitsMask The mask of the lower bits that should be empty
|
||||
* @param context the context to be used
|
||||
*
|
||||
* @throws IllegalArgumentException if the bits being checked contain any non-zero value
|
||||
*/
|
||||
private void validateCharacter(final int emptyBitsMask, final Context context) {
|
||||
if (isStrictDecoding() && (context.ibitWorkArea & emptyBitsMask) != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Strict decoding: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible encoding. " +
|
||||
"Expected the discarded bits from the character to be zero.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether decoding allows an entire final trailing character that cannot be
|
||||
* used for a complete byte.
|
||||
*
|
||||
* @throws IllegalArgumentException if strict decoding is enabled
|
||||
*/
|
||||
private void validateTrailingCharacter() {
|
||||
if (isStrictDecoding()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Strict decoding: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible encoding. " +
|
||||
"Decoding requires at least two trailing 6-bit characters to create bytes.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
672
src/main/java/net/lax1dude/eaglercraft/BaseNCodec.java
Normal file
672
src/main/java/net/lax1dude/eaglercraft/BaseNCodec.java
Normal file
@@ -0,0 +1,672 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
public abstract class BaseNCodec {
|
||||
|
||||
static enum CodecPolicy {
|
||||
STRICT,LENIANT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds thread context so classes can be thread-safe.
|
||||
*
|
||||
* This class is not itself thread-safe; each thread must allocate its own copy.
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
static class Context {
|
||||
|
||||
/**
|
||||
* Place holder for the bytes we're dealing with for our based logic.
|
||||
* Bitwise operations store and extract the encoding or decoding from this variable.
|
||||
*/
|
||||
int ibitWorkArea;
|
||||
|
||||
/**
|
||||
* Place holder for the bytes we're dealing with for our based logic.
|
||||
* Bitwise operations store and extract the encoding or decoding from this variable.
|
||||
*/
|
||||
long lbitWorkArea;
|
||||
|
||||
/**
|
||||
* Buffer for streaming.
|
||||
*/
|
||||
byte[] buffer;
|
||||
|
||||
/**
|
||||
* Position where next character should be written in the buffer.
|
||||
*/
|
||||
int pos;
|
||||
|
||||
/**
|
||||
* Position where next character should be read from the buffer.
|
||||
*/
|
||||
int readPos;
|
||||
|
||||
/**
|
||||
* Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless,
|
||||
* and must be thrown away.
|
||||
*/
|
||||
boolean eof;
|
||||
|
||||
/**
|
||||
* Variable tracks how many characters have been written to the current line. Only used when encoding. We use
|
||||
* it to make sure each encoded line never goes beyond lineLength (if lineLength > 0).
|
||||
*/
|
||||
int currentLinePos;
|
||||
|
||||
/**
|
||||
* Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This
|
||||
* variable helps track that.
|
||||
*/
|
||||
int modulus;
|
||||
|
||||
Context() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String useful for debugging (especially within a debugger.)
|
||||
*
|
||||
* @return a String useful for debugging.
|
||||
*/
|
||||
@SuppressWarnings("boxing") // OK to ignore boxing here
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " +
|
||||
"modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), Arrays.toString(buffer),
|
||||
currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* EOF
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
static final int EOF = -1;
|
||||
|
||||
/**
|
||||
* MIME chunk size per RFC 2045 section 6.8.
|
||||
*
|
||||
* <p>
|
||||
* The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
|
||||
* equal signs.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
|
||||
*/
|
||||
public static final int MIME_CHUNK_SIZE = 76;
|
||||
|
||||
/**
|
||||
* PEM chunk size per RFC 1421 section 4.3.2.4.
|
||||
*
|
||||
* <p>
|
||||
* The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
|
||||
* equal signs.
|
||||
* </p>
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc1421">RFC 1421 section 4.3.2.4</a>
|
||||
*/
|
||||
public static final int PEM_CHUNK_SIZE = 64;
|
||||
|
||||
private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
|
||||
|
||||
/**
|
||||
* Defines the default buffer size - currently {@value}
|
||||
* - must be large enough for at least one encoded block+separator
|
||||
*/
|
||||
private static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||
|
||||
/**
|
||||
* The maximum size buffer to allocate.
|
||||
*
|
||||
* <p>This is set to the same size used in the JDK {@code java.util.ArrayList}:</p>
|
||||
* <blockquote>
|
||||
* Some VMs reserve some header words in an array.
|
||||
* Attempts to allocate larger arrays may result in
|
||||
* OutOfMemoryError: Requested array size exceeds VM limit.
|
||||
* </blockquote>
|
||||
*/
|
||||
private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
|
||||
|
||||
/** Mask used to extract 8 bits, used in decoding bytes */
|
||||
protected static final int MASK_8BITS = 0xff;
|
||||
|
||||
/**
|
||||
* Byte used to pad output.
|
||||
*/
|
||||
protected static final byte PAD_DEFAULT = '='; // Allow static access to default
|
||||
|
||||
/**
|
||||
* Chunk separator per RFC 2045 section 2.1.
|
||||
*
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
|
||||
*/
|
||||
static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
|
||||
|
||||
/**
|
||||
* Compares two {@code int} values numerically treating the values
|
||||
* as unsigned. Taken from JDK 1.8.
|
||||
*
|
||||
* <p>TODO: Replace with JDK 1.8 Integer::compareUnsigned(int, int).</p>
|
||||
*
|
||||
* @param x the first {@code int} to compare
|
||||
* @param y the second {@code int} to compare
|
||||
* @return the value {@code 0} if {@code x == y}; a value less
|
||||
* than {@code 0} if {@code x < y} as unsigned values; and
|
||||
* a value greater than {@code 0} if {@code x > y} as
|
||||
* unsigned values
|
||||
*/
|
||||
private static int compareUnsigned(final int xx, final int yy) {
|
||||
int x = xx + Integer.MIN_VALUE;
|
||||
int y = yy + Integer.MIN_VALUE;
|
||||
return (x < y) ? -1 : ((x == y) ? 0 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a positive capacity at least as large the minimum required capacity.
|
||||
* If the minimum capacity is negative then this throws an OutOfMemoryError as no array
|
||||
* can be allocated.
|
||||
*
|
||||
* @param minCapacity the minimum capacity
|
||||
* @return the capacity
|
||||
* @throws OutOfMemoryError if the {@code minCapacity} is negative
|
||||
*/
|
||||
private static int createPositiveCapacity(final int minCapacity) {
|
||||
if (minCapacity < 0) {
|
||||
// overflow
|
||||
throw new OutOfMemoryError("Unable to allocate array size: " + (minCapacity & 0xffffffffL));
|
||||
}
|
||||
// This is called when we require buffer expansion to a very big array.
|
||||
// Use the conservative maximum buffer size if possible, otherwise the biggest required.
|
||||
//
|
||||
// Note: In this situation JDK 1.8 java.util.ArrayList returns Integer.MAX_VALUE.
|
||||
// This excludes some VMs that can exceed MAX_BUFFER_SIZE but not allocate a full
|
||||
// Integer.MAX_VALUE length array.
|
||||
// The result is that we may have to allocate an array of this size more than once if
|
||||
// the capacity must be expanded again.
|
||||
return (minCapacity > MAX_BUFFER_SIZE) ?
|
||||
minCapacity :
|
||||
MAX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a copy of the chunk separator per RFC 2045 section 2.1.
|
||||
*
|
||||
* @return the chunk separator
|
||||
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
|
||||
* @since 1.15
|
||||
*/
|
||||
public static byte[] getChunkSeparator() {
|
||||
return CHUNK_SEPARATOR.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a byte value is whitespace or not.
|
||||
* Whitespace is taken to mean: space, tab, CR, LF
|
||||
* @param byteToCheck
|
||||
* the byte to check
|
||||
* @return true if byte is whitespace, false otherwise
|
||||
*/
|
||||
protected static boolean isWhiteSpace(final byte byteToCheck) {
|
||||
switch (byteToCheck) {
|
||||
case ' ' :
|
||||
case '\n' :
|
||||
case '\r' :
|
||||
case '\t' :
|
||||
return true;
|
||||
default :
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases our buffer by the {@link #DEFAULT_BUFFER_RESIZE_FACTOR}.
|
||||
* @param context the context to be used
|
||||
* @param minCapacity the minimum required capacity
|
||||
* @return the resized byte[] buffer
|
||||
* @throws OutOfMemoryError if the {@code minCapacity} is negative
|
||||
*/
|
||||
private static byte[] resizeBuffer(final Context context, final int minCapacity) {
|
||||
// Overflow-conscious code treats the min and new capacity as unsigned.
|
||||
final int oldCapacity = context.buffer.length;
|
||||
int newCapacity = oldCapacity * DEFAULT_BUFFER_RESIZE_FACTOR;
|
||||
if (compareUnsigned(newCapacity, minCapacity) < 0) {
|
||||
newCapacity = minCapacity;
|
||||
}
|
||||
if (compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) {
|
||||
newCapacity = createPositiveCapacity(minCapacity);
|
||||
}
|
||||
|
||||
final byte[] b = new byte[newCapacity];
|
||||
System.arraycopy(context.buffer, 0, b, 0, context.buffer.length);
|
||||
context.buffer = b;
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #pad}. Will be removed in 2.0.
|
||||
*/
|
||||
@Deprecated
|
||||
protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later
|
||||
|
||||
protected final byte pad; // instance variable just in case it needs to vary later
|
||||
|
||||
/** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */
|
||||
private final int unencodedBlockSize;
|
||||
|
||||
/** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */
|
||||
private final int encodedBlockSize;
|
||||
|
||||
/**
|
||||
* Chunksize for encoding. Not used when decoding.
|
||||
* A value of zero or less implies no chunking of the encoded data.
|
||||
* Rounded down to nearest multiple of encodedBlockSize.
|
||||
*/
|
||||
protected final int lineLength;
|
||||
|
||||
/**
|
||||
* Size of chunk separator. Not used unless {@link #lineLength} > 0.
|
||||
*/
|
||||
private final int chunkSeparatorLength;
|
||||
|
||||
/**
|
||||
* Defines the decoding behavior when the input bytes contain leftover trailing bits that
|
||||
* cannot be created by a valid encoding. These can be bits that are unused from the final
|
||||
* character or entire characters. The default mode is lenient decoding. Set this to
|
||||
* {@code true} to enable strict decoding.
|
||||
* <ul>
|
||||
* <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible.
|
||||
* The remainder are discarded.
|
||||
* <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits
|
||||
* are not part of a valid encoding. Any unused bits from the final character must
|
||||
* be zero. Impossible counts of entire final characters are not allowed.
|
||||
* </ul>
|
||||
*
|
||||
* <p>When strict decoding is enabled it is expected that the decoded bytes will be re-encoded
|
||||
* to a byte array that matches the original, i.e. no changes occur on the final
|
||||
* character. This requires that the input bytes use the same padding and alphabet
|
||||
* as the encoder.
|
||||
*/
|
||||
private final CodecPolicy decodingPolicy;
|
||||
|
||||
/**
|
||||
* Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size.
|
||||
* If {@code chunkSeparatorLength} is zero, then chunking is disabled.
|
||||
* @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
|
||||
* @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
|
||||
* @param lineLength if > 0, use chunking with a length {@code lineLength}
|
||||
* @param chunkSeparatorLength the chunk separator length, if relevant
|
||||
*/
|
||||
protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize,
|
||||
final int lineLength, final int chunkSeparatorLength) {
|
||||
this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, PAD_DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size.
|
||||
* If {@code chunkSeparatorLength} is zero, then chunking is disabled.
|
||||
* @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
|
||||
* @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
|
||||
* @param lineLength if > 0, use chunking with a length {@code lineLength}
|
||||
* @param chunkSeparatorLength the chunk separator length, if relevant
|
||||
* @param pad byte used as padding byte.
|
||||
*/
|
||||
protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize,
|
||||
final int lineLength, final int chunkSeparatorLength, final byte pad) {
|
||||
this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, pad, CodecPolicy.LENIANT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size.
|
||||
* If {@code chunkSeparatorLength} is zero, then chunking is disabled.
|
||||
* @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3)
|
||||
* @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4)
|
||||
* @param lineLength if > 0, use chunking with a length {@code lineLength}
|
||||
* @param chunkSeparatorLength the chunk separator length, if relevant
|
||||
* @param pad byte used as padding byte.
|
||||
* @param decodingPolicy Decoding policy.
|
||||
* @since 1.15
|
||||
*/
|
||||
protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize,
|
||||
final int lineLength, final int chunkSeparatorLength, final byte pad, final CodecPolicy decodingPolicy) {
|
||||
this.unencodedBlockSize = unencodedBlockSize;
|
||||
this.encodedBlockSize = encodedBlockSize;
|
||||
final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0;
|
||||
this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
|
||||
this.chunkSeparatorLength = chunkSeparatorLength;
|
||||
this.pad = pad;
|
||||
this.decodingPolicy = decodingPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of buffered data available for reading.
|
||||
*
|
||||
* @param context the context to be used
|
||||
* @return The amount of buffered data available for reading.
|
||||
*/
|
||||
int available(final Context context) { // package protected for access from I/O streams
|
||||
return context.buffer != null ? context.pos - context.readPos : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a given byte array to see if it contains any characters within the alphabet or PAD.
|
||||
*
|
||||
* Intended for use in checking line-ending arrays
|
||||
*
|
||||
* @param arrayOctet
|
||||
* byte array to test
|
||||
* @return {@code true} if any byte is a valid character in the alphabet or PAD; {@code false} otherwise
|
||||
*/
|
||||
protected boolean containsAlphabetOrPad(final byte[] arrayOctet) {
|
||||
if (arrayOctet == null) {
|
||||
return false;
|
||||
}
|
||||
for (final byte element : arrayOctet) {
|
||||
if (pad == element || isInAlphabet(element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a byte[] containing characters in the Base-N alphabet.
|
||||
*
|
||||
* @param pArray
|
||||
* A byte array containing Base-N character data
|
||||
* @return a byte array containing binary data
|
||||
*/
|
||||
public byte[] decode(final byte[] pArray) {
|
||||
if (pArray == null || pArray.length == 0) {
|
||||
return pArray;
|
||||
}
|
||||
final Context context = new Context();
|
||||
decode(pArray, 0, pArray.length, context);
|
||||
decode(pArray, 0, EOF, context); // Notify decoder of EOF.
|
||||
final byte[] result = new byte[context.pos];
|
||||
readResults(result, 0, result.length, context);
|
||||
return result;
|
||||
}
|
||||
|
||||
// package protected for access from I/O streams
|
||||
abstract void decode(byte[] pArray, int i, int length, Context context);
|
||||
|
||||
/**
|
||||
* Decodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of
|
||||
* the Decoder interface, and will throw a DecoderException if the supplied object is not of type byte[] or String.
|
||||
*
|
||||
* @param obj
|
||||
* Object to decode
|
||||
* @return An object (of type byte[]) containing the binary data which corresponds to the byte[] or String
|
||||
* supplied.
|
||||
* @throws DecoderException
|
||||
* if the parameter supplied is not of type byte[]
|
||||
*/
|
||||
public Object decode(final Object obj) {
|
||||
if (obj instanceof byte[]) {
|
||||
return decode((byte[]) obj);
|
||||
} else if (obj instanceof String) {
|
||||
return decode((String) obj);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a String containing characters in the Base-N alphabet.
|
||||
*
|
||||
* @param pArray
|
||||
* A String containing Base-N character data
|
||||
* @return a byte array containing binary data
|
||||
*/
|
||||
public byte[] decode(final String pArray) {
|
||||
return decode(pArray.getBytes(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet.
|
||||
*
|
||||
* @param pArray
|
||||
* a byte array containing binary data
|
||||
* @return A byte array containing only the base N alphabetic character data
|
||||
*/
|
||||
public byte[] encode(final byte[] pArray) {
|
||||
if (pArray == null || pArray.length == 0) {
|
||||
return pArray;
|
||||
}
|
||||
return encode(pArray, 0, pArray.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a byte[] containing binary data, into a byte[] containing
|
||||
* characters in the alphabet.
|
||||
*
|
||||
* @param pArray
|
||||
* a byte array containing binary data
|
||||
* @param offset
|
||||
* initial offset of the subarray.
|
||||
* @param length
|
||||
* length of the subarray.
|
||||
* @return A byte array containing only the base N alphabetic character data
|
||||
* @since 1.11
|
||||
*/
|
||||
public byte[] encode(final byte[] pArray, final int offset, final int length) {
|
||||
if (pArray == null || pArray.length == 0) {
|
||||
return pArray;
|
||||
}
|
||||
final Context context = new Context();
|
||||
encode(pArray, offset, length, context);
|
||||
encode(pArray, offset, EOF, context); // Notify encoder of EOF.
|
||||
final byte[] buf = new byte[context.pos - context.readPos];
|
||||
readResults(buf, 0, buf.length, context);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// package protected for access from I/O streams
|
||||
abstract void encode(byte[] pArray, int i, int length, Context context);
|
||||
|
||||
/**
|
||||
* Encodes an Object using the Base-N algorithm. This method is provided in order to satisfy the requirements of
|
||||
* the Encoder interface, and will throw an EncoderException if the supplied object is not of type byte[].
|
||||
*
|
||||
* @param obj
|
||||
* Object to encode
|
||||
* @return An object (of type byte[]) containing the Base-N encoded data which corresponds to the byte[] supplied.
|
||||
* @throws EncoderException
|
||||
* if the parameter supplied is not of type byte[]
|
||||
*/
|
||||
public Object encode(final Object obj) {
|
||||
return encode((byte[]) obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a byte[] containing binary data, into a String containing characters in the appropriate alphabet.
|
||||
* Uses UTF8 encoding.
|
||||
*
|
||||
* @param pArray a byte array containing binary data
|
||||
* @return String containing only character data in the appropriate alphabet.
|
||||
* @since 1.5
|
||||
* This is a duplicate of {@link #encodeToString(byte[])}; it was merged during refactoring.
|
||||
*/
|
||||
public String encodeAsString(final byte[] pArray){
|
||||
return new String(encode(pArray), Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a byte[] containing binary data, into a String containing characters in the Base-N alphabet.
|
||||
* Uses UTF8 encoding.
|
||||
*
|
||||
* @param pArray
|
||||
* a byte array containing binary data
|
||||
* @return A String containing only Base-N character data
|
||||
*/
|
||||
public String encodeToString(final byte[] pArray) {
|
||||
return new String(encode(pArray), Charset.forName("UTF-8"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the buffer has room for {@code size} bytes
|
||||
*
|
||||
* @param size minimum spare space required
|
||||
* @param context the context to be used
|
||||
* @return the buffer
|
||||
*/
|
||||
protected byte[] ensureBufferSize(final int size, final Context context){
|
||||
if (context.buffer == null) {
|
||||
context.buffer = new byte[Math.max(size, getDefaultBufferSize())];
|
||||
context.pos = 0;
|
||||
context.readPos = 0;
|
||||
|
||||
// Overflow-conscious:
|
||||
// x + y > z == x + y - z > 0
|
||||
} else if (context.pos + size - context.buffer.length > 0) {
|
||||
return resizeBuffer(context, context.pos + size);
|
||||
}
|
||||
return context.buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the decoding behavior policy.
|
||||
*
|
||||
* <p>
|
||||
* The default is lenient. If the decoding policy is strict, then decoding will raise an
|
||||
* {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. Decoding will compose
|
||||
* trailing bits into 8-bit bytes and discard the remainder.
|
||||
* </p>
|
||||
*
|
||||
* @return true if using strict decoding
|
||||
* @since 1.15
|
||||
*/
|
||||
public CodecPolicy getCodecPolicy() {
|
||||
return decodingPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default buffer size. Can be overridden.
|
||||
*
|
||||
* @return the default buffer size.
|
||||
*/
|
||||
protected int getDefaultBufferSize() {
|
||||
return DEFAULT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of space needed to encode the supplied array.
|
||||
*
|
||||
* @param pArray byte[] array which will later be encoded
|
||||
*
|
||||
* @return amount of space needed to encoded the supplied array.
|
||||
* Returns a long since a max-len array will require > Integer.MAX_VALUE
|
||||
*/
|
||||
public long getEncodedLength(final byte[] pArray) {
|
||||
// Calculate non-chunked size - rounded up to allow for padding
|
||||
// cast to long is needed to avoid possibility of overflow
|
||||
long len = ((pArray.length + unencodedBlockSize-1) / unencodedBlockSize) * (long) encodedBlockSize;
|
||||
if (lineLength > 0) { // We're using chunking
|
||||
// Round up to nearest multiple
|
||||
len += ((len + lineLength-1) / lineLength) * chunkSeparatorLength;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this object has buffered data for reading.
|
||||
*
|
||||
* @param context the context to be used
|
||||
* @return true if there is data still available for reading.
|
||||
*/
|
||||
boolean hasData(final Context context) { // package protected for access from I/O streams
|
||||
return context.buffer != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the {@code octet} is in the current alphabet.
|
||||
* Does not allow whitespace or pad.
|
||||
*
|
||||
* @param value The value to test
|
||||
*
|
||||
* @return {@code true} if the value is defined in the current alphabet, {@code false} otherwise.
|
||||
*/
|
||||
protected abstract boolean isInAlphabet(byte value);
|
||||
|
||||
/**
|
||||
* Tests a given byte array to see if it contains only valid characters within the alphabet.
|
||||
* The method optionally treats whitespace and pad as valid.
|
||||
*
|
||||
* @param arrayOctet byte array to test
|
||||
* @param allowWSPad if {@code true}, then whitespace and PAD are also allowed
|
||||
*
|
||||
* @return {@code true} if all bytes are valid characters in the alphabet or if the byte array is empty;
|
||||
* {@code false}, otherwise
|
||||
*/
|
||||
public boolean isInAlphabet(final byte[] arrayOctet, final boolean allowWSPad) {
|
||||
for (final byte octet : arrayOctet) {
|
||||
if (!isInAlphabet(octet) &&
|
||||
(!allowWSPad || (octet != pad) && !isWhiteSpace(octet))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a given String to see if it contains only valid characters within the alphabet.
|
||||
* The method treats whitespace and PAD as valid.
|
||||
*
|
||||
* @param basen String to test
|
||||
* @return {@code true} if all characters in the String are valid characters in the alphabet or if
|
||||
* the String is empty; {@code false}, otherwise
|
||||
* @see #isInAlphabet(byte[], boolean)
|
||||
*/
|
||||
public boolean isInAlphabet(final String basen) {
|
||||
return isInAlphabet(basen.getBytes(Charset.forName("UTF-8")), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if decoding behavior is strict. Decoding will raise an {@link IllegalArgumentException} if trailing
|
||||
* bits are not part of a valid encoding.
|
||||
*
|
||||
* <p>
|
||||
* The default is false for lenient decoding. Decoding will compose trailing bits into 8-bit bytes and discard the
|
||||
* remainder.
|
||||
* </p>
|
||||
*
|
||||
* @return true if using strict decoding
|
||||
* @since 1.15
|
||||
*/
|
||||
public boolean isStrictDecoding() {
|
||||
return decodingPolicy == CodecPolicy.STRICT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts buffered data into the provided byte[] array, starting at position bPos, up to a maximum of bAvail
|
||||
* bytes. Returns how many bytes were actually extracted.
|
||||
* <p>
|
||||
* Package protected for access from I/O streams.
|
||||
*
|
||||
* @param b
|
||||
* byte[] array to extract the buffered data into.
|
||||
* @param bPos
|
||||
* position in byte[] array to start extraction at.
|
||||
* @param bAvail
|
||||
* amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
|
||||
* @param context
|
||||
* the context to be used
|
||||
* @return The number of bytes successfully extracted into the provided byte[] array.
|
||||
*/
|
||||
int readResults(final byte[] b, final int bPos, final int bAvail, final Context context) {
|
||||
if (context.buffer != null) {
|
||||
final int len = Math.min(available(context), bAvail);
|
||||
System.arraycopy(context.buffer, context.readPos, b, bPos, len);
|
||||
context.readPos += len;
|
||||
if (context.readPos >= context.pos) {
|
||||
context.buffer = null; // so hasData() will return false, and this method can return -1
|
||||
}
|
||||
return len;
|
||||
}
|
||||
return context.eof ? EOF : 0;
|
||||
}
|
||||
}
|
||||
30
src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java
Normal file
30
src/main/java/net/lax1dude/eaglercraft/ConfigConstants.java
Normal file
@@ -0,0 +1,30 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConfigConstants {
|
||||
|
||||
public static boolean profanity = false;
|
||||
|
||||
public static final String version = "1.5.2-sp2.01";
|
||||
public static final String mainMenuString = "eaglercraft " + version;
|
||||
|
||||
public static final String forkMe = null;
|
||||
|
||||
public static String ayonullTitle = null;
|
||||
public static String ayonullLink = null;
|
||||
|
||||
public static String mainMenuItemLine0 = null;
|
||||
public static String mainMenuItemLine1 = null;
|
||||
public static String mainMenuItemLine2 = null;
|
||||
public static String mainMenuItemLink = null;
|
||||
|
||||
public static List<String> splashTexts = null;
|
||||
|
||||
public static List<RelayEntry> relays = null;
|
||||
|
||||
public static boolean eaglercraftTitleLogo = false;
|
||||
|
||||
public static boolean panoramaBlur = true;
|
||||
|
||||
}
|
||||
81
src/main/java/net/lax1dude/eaglercraft/DebugIconImpl.java
Normal file
81
src/main/java/net/lax1dude/eaglercraft/DebugIconImpl.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.Icon;
|
||||
|
||||
public class DebugIconImpl implements Icon {
|
||||
|
||||
private final int sheetW;
|
||||
private final int sheetH;
|
||||
|
||||
public DebugIconImpl() {
|
||||
this(1024, 1024);
|
||||
}
|
||||
|
||||
public DebugIconImpl(int sheetW, int sheetH) {
|
||||
this.sheetW = sheetW;
|
||||
this.sheetH = sheetH;
|
||||
}
|
||||
|
||||
public int getOriginX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getOriginY() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinU() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxU() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInterpolatedU(double var1) {
|
||||
return (float)var1 / 16.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinV() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxV() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInterpolatedV(double var1) {
|
||||
return (float)var1 / 16.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconName() {
|
||||
return "debug_icon";
|
||||
}
|
||||
|
||||
public int getSheetWidth() {
|
||||
return sheetW;
|
||||
}
|
||||
|
||||
public int getSheetHeight() {
|
||||
return sheetH;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
729
src/main/java/net/lax1dude/eaglercraft/DefaultSkinRenderer.java
Normal file
729
src/main/java/net/lax1dude/eaglercraft/DefaultSkinRenderer.java
Normal file
@@ -0,0 +1,729 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.lax1dude.eaglercraft.EaglerProfile.EaglerProfileCape;
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.EntityClientPlayerMP;
|
||||
import net.minecraft.src.EntityOtherPlayerMP;
|
||||
import net.minecraft.src.EntityPlayer;
|
||||
import net.minecraft.src.ModelBiped;
|
||||
import net.minecraft.src.ModelBlaze;
|
||||
import net.minecraft.src.ModelEnderman;
|
||||
import net.minecraft.src.ModelSkeleton;
|
||||
import net.minecraft.src.ModelVillager;
|
||||
import net.minecraft.src.ModelZombie;
|
||||
import net.minecraft.src.OpenGlHelper;
|
||||
import net.minecraft.src.Packet250CustomPayload;
|
||||
import net.minecraft.src.RenderEnderman;
|
||||
import net.minecraft.src.RenderHelper;
|
||||
|
||||
public class DefaultSkinRenderer {
|
||||
|
||||
public static final TextureLocation[] defaultVanillaSkins = new TextureLocation[] {
|
||||
new TextureLocation("/skins/01.default_steve.png"),
|
||||
new TextureLocation("/skins/02.default_alex.png"),
|
||||
new TextureLocation("/skins/03.tennis_steve.png"),
|
||||
new TextureLocation("/skins/04.tennis_alex.png"),
|
||||
new TextureLocation("/skins/05.tuxedo_steve.png"),
|
||||
new TextureLocation("/skins/06.tuxedo_alex.png"),
|
||||
new TextureLocation("/skins/07.athlete_steve.png"),
|
||||
new TextureLocation("/skins/08.athlete_alex.png"),
|
||||
new TextureLocation("/skins/09.cyclist_steve.png"),
|
||||
new TextureLocation("/skins/10.cyclist_alex.png"),
|
||||
new TextureLocation("/skins/11.boxer_steve.png"),
|
||||
new TextureLocation("/skins/12.boxer_alex.png"),
|
||||
new TextureLocation("/skins/13.prisoner_steve.png"),
|
||||
new TextureLocation("/skins/14.prisoner_alex.png"),
|
||||
new TextureLocation("/skins/15.scottish_steve.png"),
|
||||
new TextureLocation("/skins/16.scottish_alex.png"),
|
||||
new TextureLocation("/skins/17.dev_steve.png"),
|
||||
new TextureLocation("/skins/18.dev_alex.png"),
|
||||
new TextureLocation("/skins/19.herobrine.png"),
|
||||
new TextureLocation("/mob/enderman.png"),
|
||||
new TextureLocation("/mob/skeleton.png"),
|
||||
new TextureLocation("/mob/fire.png"),
|
||||
new TextureLocation("/skins/20.barney.png"),
|
||||
new TextureLocation("/skins/21.slime.png"),
|
||||
new TextureLocation("/skins/22.noob.png"),
|
||||
new TextureLocation("/skins/23.trump.png"),
|
||||
new TextureLocation("/skins/24.notch.png"),
|
||||
new TextureLocation("/skins/25.creeper.png"),
|
||||
new TextureLocation("/skins/26.zombie.png"),
|
||||
new TextureLocation("/skins/27.pig.png"),
|
||||
new TextureLocation("/skins/28.squid.png"),
|
||||
new TextureLocation("/skins/29.mooshroom.png"),
|
||||
new TextureLocation("/mob/villager/villager.png"),
|
||||
null, null, null, null, null
|
||||
};
|
||||
|
||||
public static final TextureLocation[] defaultVanillaCapes = new TextureLocation[] {
|
||||
null,
|
||||
new TextureLocation("/skins/c01.minecon_2011.png"),
|
||||
new TextureLocation("/skins/c02.minecon_2012.png"),
|
||||
new TextureLocation("/skins/c03.minecon_2013.png"),
|
||||
new TextureLocation("/skins/c04.minecon_2015.png"),
|
||||
new TextureLocation("/skins/c05.minecon_2016.png"),
|
||||
new TextureLocation("/skins/c06.microsoft_account.png"),
|
||||
new TextureLocation("/skins/c07.mapmaker.png"),
|
||||
new TextureLocation("/skins/c08.mojang_old.png"),
|
||||
new TextureLocation("/skins/c09.mojang_new.png"),
|
||||
new TextureLocation("/skins/c10.jira_mod.png"),
|
||||
new TextureLocation("/skins/c11.mojang_very_old.png"),
|
||||
new TextureLocation("/skins/c12.scrolls.png"),
|
||||
new TextureLocation("/skins/c13.cobalt.png"),
|
||||
new TextureLocation("/skins/c14.translator.png"),
|
||||
new TextureLocation("/skins/c15.millionth_account.png"),
|
||||
new TextureLocation("/skins/c16.prismarine.png"),
|
||||
new TextureLocation("/skins/c17.snowman.png"),
|
||||
new TextureLocation("/skins/c18.spade.png"),
|
||||
new TextureLocation("/skins/c19.birthday.png"),
|
||||
new TextureLocation("/skins/c20.db.png")
|
||||
};
|
||||
|
||||
public static final HighPolySkin[] defaultHighPoly = new HighPolySkin[] {
|
||||
null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null,
|
||||
HighPolySkin.LONG_ARMS, HighPolySkin.WEIRD_CLIMBER_DUDE, HighPolySkin.LAXATIVE_DUDE,
|
||||
HighPolySkin.BABY_CHARLES, HighPolySkin.BABY_WINSTON
|
||||
};
|
||||
|
||||
public static final boolean[] defaultVanillaSkinClassicOrSlimVariants = new boolean[] {
|
||||
false, true,
|
||||
false, true,
|
||||
false, true,
|
||||
false, true,
|
||||
false, true,
|
||||
false, true,
|
||||
false, true,
|
||||
false, true,
|
||||
false, true
|
||||
};
|
||||
|
||||
private static final HashMap<Integer,EntityOtherPlayerMP> skinCookies = new HashMap<>();
|
||||
private static final HashMap<EntityOtherPlayerMP,Integer> skinGLUnits = new HashMap<>();
|
||||
private static final HashMap<EntityOtherPlayerMP,Integer> capeGLUnits = new HashMap<>();
|
||||
private static final HashMap<EntityOtherPlayerMP,Long> skinGLTimeout = new HashMap<>();
|
||||
|
||||
private static long lastClean = 0l;
|
||||
|
||||
public static void deleteOldSkins() {
|
||||
long now = EaglerAdapter.steadyTimeMillis();
|
||||
if(now - lastClean > 60000l) {
|
||||
lastClean = now;
|
||||
Iterator<Entry<EntityOtherPlayerMP,Long>> itr = skinGLTimeout.entrySet().iterator();
|
||||
while(itr.hasNext()) {
|
||||
Entry<EntityOtherPlayerMP,Long> ee = itr.next();
|
||||
if(now - ee.getValue() > 80000l) {
|
||||
itr.remove();
|
||||
if(skinGLUnits.containsKey(ee.getKey())) {
|
||||
Minecraft.getMinecraft().renderEngine.deleteTexture(skinGLUnits.remove(ee.getKey()));
|
||||
}
|
||||
if(capeGLUnits.containsKey(ee.getKey())) {
|
||||
Minecraft.getMinecraft().renderEngine.deleteTexture(capeGLUnits.remove(ee.getKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Iterator<Entry<Integer, EntityOtherPlayerMP>> itr2 = skinCookies.entrySet().iterator();
|
||||
while(itr2.hasNext()) {
|
||||
Entry<Integer, EntityOtherPlayerMP> e = itr2.next();
|
||||
if(e.getValue().isDead) {
|
||||
itr2.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean bindSyncedSkin(EntityPlayer p) {
|
||||
if(p instanceof EntityClientPlayerMP) {
|
||||
return false;
|
||||
}else if(p instanceof EntityOtherPlayerMP) {
|
||||
EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p;
|
||||
if(pp.skinPacket != null) {
|
||||
int type = ((int)pp.skinPacket[0] & 0xFF);
|
||||
if(type != 4 && type >= 0 && type < EaglerProfile.SKIN_DATA_SIZE.length) {
|
||||
if(!skinGLUnits.containsKey(pp)) {
|
||||
byte[] skinToLoad = new byte[EaglerProfile.SKIN_DATA_SIZE[type]];
|
||||
System.arraycopy(pp.skinPacket, 1, skinToLoad, 0, skinToLoad.length);
|
||||
int w, h;
|
||||
|
||||
switch((int)pp.skinPacket[0] & 0xFF) {
|
||||
default:
|
||||
case 0:
|
||||
w = 64;
|
||||
h = 32;
|
||||
break;
|
||||
case 1:
|
||||
case 5:
|
||||
w = 64;
|
||||
h = 64;
|
||||
break;
|
||||
}
|
||||
|
||||
if(skinToLoad.length / 4 == w * h) {
|
||||
skinGLUnits.put(pp, Minecraft.getMinecraft().renderEngine.setupTextureRaw(skinToLoad, w, h));
|
||||
}
|
||||
}
|
||||
skinGLTimeout.put(pp, EaglerAdapter.steadyTimeMillis());
|
||||
Integer i = skinGLUnits.get(pp);
|
||||
if(i != null && i.intValue() > 0) {
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(i.intValue());
|
||||
}else {
|
||||
defaultVanillaSkins[0].bindTexture();
|
||||
}
|
||||
}else {
|
||||
int type2 = (int)pp.skinPacket[1] & 0xFF;
|
||||
if(type2 < defaultVanillaSkins.length) {
|
||||
TextureLocation loc = defaultVanillaSkins[type2];
|
||||
if(loc != null) {
|
||||
loc.bindTexture();
|
||||
}else {
|
||||
if(defaultHighPoly[type2] != null) {
|
||||
defaultHighPoly[type2].fallbackTexture.bindTexture();
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}else {
|
||||
requestSkin(pp);
|
||||
}
|
||||
return false;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean bindSyncedCape(EntityPlayer p) {
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE);
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW);
|
||||
if(p instanceof EntityClientPlayerMP) {
|
||||
if(EaglerProfile.presetCapeId < 0) {
|
||||
EaglerProfileCape cp = EaglerProfile.capes.get(EaglerProfile.customCapeId);
|
||||
if(cp != null) {
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(cp.glTex);
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE);
|
||||
EaglerAdapter.glScalef(2.0f, 1.0f, 1.0f);
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW);
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}else {
|
||||
if(EaglerProfile.presetCapeId < defaultVanillaCapes.length) {
|
||||
TextureLocation loc = defaultVanillaCapes[EaglerProfile.presetCapeId];
|
||||
if(loc == null) {
|
||||
return false;
|
||||
}else {
|
||||
loc.bindTexture();
|
||||
return true;
|
||||
}
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}else if(p instanceof EntityOtherPlayerMP) {
|
||||
EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p;
|
||||
if(pp.skinPacket != null) {
|
||||
int tp = ((int)pp.skinPacket[0] & 0xFF);
|
||||
if(tp >= 0 && tp < EaglerProfile.SKIN_DATA_SIZE.length) {
|
||||
int offset = 1 + EaglerProfile.SKIN_DATA_SIZE[tp];
|
||||
if(pp.skinPacket.length > offset + 1) {
|
||||
int capeType = (int)pp.skinPacket[offset] & 0xFF;
|
||||
if(capeType >= 0 && capeType < EaglerProfile.CAPE_DATA_SIZE.length) {
|
||||
int len = EaglerProfile.CAPE_DATA_SIZE[capeType];
|
||||
if(pp.skinPacket.length > offset + len + 1) {
|
||||
if(capeType != 2) {
|
||||
if(!capeGLUnits.containsKey(pp)) {
|
||||
byte[] dataToLoad = new byte[len];
|
||||
System.arraycopy(pp.skinPacket, offset + 2, dataToLoad, 0, len);
|
||||
int w, h;
|
||||
switch(capeType) {
|
||||
case 0:
|
||||
default:
|
||||
w = 32;
|
||||
h = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
if(dataToLoad.length / 4 == w * h) {
|
||||
capeGLUnits.put(pp, Minecraft.getMinecraft().renderEngine.setupTextureRaw(dataToLoad, w, h));
|
||||
}
|
||||
}
|
||||
skinGLTimeout.put(pp, EaglerAdapter.steadyTimeMillis());
|
||||
Integer i = capeGLUnits.get(pp);
|
||||
if(i != null && i.intValue() > 0) {
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE);
|
||||
EaglerAdapter.glScalef(2.0f, 1.0f, 1.0f);
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW);
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(i.intValue());
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}else {
|
||||
int preset = (int)pp.skinPacket[offset + 2] & 0xFF;
|
||||
if(preset < defaultVanillaCapes.length) {
|
||||
TextureLocation loc = defaultVanillaCapes[preset];
|
||||
if(loc == null) {
|
||||
return false;
|
||||
}else {
|
||||
loc.bindTexture();
|
||||
return true;
|
||||
}
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}else {
|
||||
requestSkin(pp);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getSkinLayerByte(EntityPlayer p) {
|
||||
if(p instanceof EntityClientPlayerMP) {
|
||||
return Minecraft.getMinecraft().gameSettings.getSkinLayers();
|
||||
}else if(p instanceof EntityOtherPlayerMP) {
|
||||
EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p;
|
||||
if(pp.skinPacket != null) {
|
||||
int tp = ((int)pp.skinPacket[0] & 0xFF);
|
||||
if(tp >= 0 && tp < EaglerProfile.SKIN_DATA_SIZE.length) {
|
||||
int offset = 1 + EaglerProfile.SKIN_DATA_SIZE[tp];
|
||||
if(pp.skinPacket.length > offset + 1) {
|
||||
return (int)pp.skinPacket[offset + 1] & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
public static void updateSkinLayerByte(int skinFlags, byte[] pkt) {
|
||||
if(pkt.length > 0) {
|
||||
int tp = ((int)pkt[0] & 0xFF);
|
||||
if(tp >= 0 && tp < EaglerProfile.SKIN_DATA_SIZE.length) {
|
||||
int offset = 1 + EaglerProfile.SKIN_DATA_SIZE[tp];
|
||||
if(pkt.length > offset + 1) {
|
||||
pkt[offset + 1] = (byte)skinFlags;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void requestSkin(EntityOtherPlayerMP pp) {
|
||||
if(!skinCookies.containsValue(pp)) {
|
||||
int cookie = (int)(System.nanoTime() % 65536);
|
||||
skinCookies.put(cookie, pp);
|
||||
byte[] n = pp.username.getBytes();
|
||||
byte[] pkt = new byte[n.length + 2];
|
||||
System.arraycopy(n, 0, pkt, 2, n.length);
|
||||
pkt[0] = (byte)(cookie & 0xFF);
|
||||
pkt[1] = (byte)((cookie >> 8) & 0xFF);
|
||||
Minecraft.getMinecraft().getNetHandler().addToSendQueue(new Packet250CustomPayload("EAG|FetchSkin", pkt));
|
||||
}
|
||||
}
|
||||
|
||||
public static void skinResponse(byte[] data) {
|
||||
int cookie = ((int)data[0] & 0xFF) | (((int)data[1] & 0xFF) << 8);
|
||||
if(skinCookies.containsKey(cookie) && (data.length > 3)) {
|
||||
EntityOtherPlayerMP p = skinCookies.remove(cookie);
|
||||
byte[] packet = new byte[data.length - 2];
|
||||
System.arraycopy(data, 2, packet, 0, packet.length);
|
||||
p.skinPacket = packet;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isNewSkin(int id) {
|
||||
return !(id == 0 || id == 2 || id == 4 || id == 6 || id == 8 || id == 10 || id == 12 || id == 14 || id == 18 || id == 28) && !isHighPoly(id);
|
||||
}
|
||||
|
||||
public static boolean isAlexSkin(int id) {
|
||||
return id < defaultVanillaSkinClassicOrSlimVariants.length && defaultVanillaSkinClassicOrSlimVariants[id];
|
||||
}
|
||||
|
||||
public static boolean isStandardModel(int id) {
|
||||
return !isZombieModel(id) && !(id == 19 || id == 20 || id == 21 || id == 32 || id == 33 || id == 34) && !isHighPoly(id);
|
||||
}
|
||||
|
||||
public static boolean isZombieModel(int id) {
|
||||
return id == 18 || id == 28;
|
||||
}
|
||||
|
||||
public static boolean isHighPoly(int id) {
|
||||
return !(defaultVanillaSkins.length > id && id >= 0) ? false : defaultHighPoly[id] != null;
|
||||
}
|
||||
|
||||
public static boolean isPlayerNewSkin(EntityPlayer p) {
|
||||
if(p instanceof EntityClientPlayerMP) {
|
||||
if(EaglerProfile.presetSkinId <= -1) {
|
||||
int type = EaglerProfile.getSkinSize(EaglerProfile.skins.get(EaglerProfile.customSkinId).data.length);
|
||||
return (type == 1 || type == 3);
|
||||
}else {
|
||||
return isNewSkin(EaglerProfile.presetSkinId);
|
||||
}
|
||||
}else if(p instanceof EntityOtherPlayerMP) {
|
||||
EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p;
|
||||
if(pp.skinPacket != null) {
|
||||
if(pp.skinPacket[0] != (byte)4) {
|
||||
return (pp.skinPacket[0] == (byte)1) || (pp.skinPacket[0] == (byte)3) || (pp.skinPacket[0] == (byte)5) || (pp.skinPacket[0] == (byte)6);
|
||||
}else {
|
||||
return isNewSkin((int)pp.skinPacket[1] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isPlayerNewSkinSlim(EntityPlayer p) {
|
||||
if(p instanceof EntityClientPlayerMP) {
|
||||
if(EaglerProfile.presetSkinId == -1) {
|
||||
return EaglerProfile.skins.get(EaglerProfile.customSkinId).slim;
|
||||
}else {
|
||||
return isAlexSkin(EaglerProfile.presetSkinId);
|
||||
}
|
||||
}else if(p instanceof EntityOtherPlayerMP) {
|
||||
EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p;
|
||||
if(pp.skinPacket != null) {
|
||||
if(pp.skinPacket[0] != (byte)4) {
|
||||
return (pp.skinPacket[0] == (byte)5) || (pp.skinPacket[0] == (byte)6);
|
||||
}else {
|
||||
return isAlexSkin((int)pp.skinPacket[1] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isPlayerHighPoly(EntityPlayer p) {
|
||||
if(p instanceof EntityClientPlayerMP) {
|
||||
if(EaglerProfile.presetSkinId == -1) {
|
||||
return false;
|
||||
}else {
|
||||
return isHighPoly(EaglerProfile.presetSkinId);
|
||||
}
|
||||
}else if(p instanceof EntityOtherPlayerMP) {
|
||||
EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p;
|
||||
if(pp.skinPacket != null) {
|
||||
if(pp.skinPacket[0] != (byte)4) {
|
||||
return false;
|
||||
}else {
|
||||
return isHighPoly((int)pp.skinPacket[1] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isPlayerStandard(EntityPlayer p) {
|
||||
if(p instanceof EntityClientPlayerMP) {
|
||||
if(EaglerProfile.presetSkinId == -1) {
|
||||
return true;
|
||||
}else {
|
||||
return isStandardModel(EaglerProfile.presetSkinId);
|
||||
}
|
||||
}else if(p instanceof EntityOtherPlayerMP) {
|
||||
EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p;
|
||||
if(pp.skinPacket != null) {
|
||||
if(pp.skinPacket[0] != (byte)4) {
|
||||
return true;
|
||||
}else {
|
||||
return isStandardModel((int)pp.skinPacket[1] & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int getPlayerRenderer(EntityPlayer p) {
|
||||
if(p instanceof EntityClientPlayerMP) {
|
||||
if(EaglerProfile.presetSkinId == -1) {
|
||||
return 0;
|
||||
}else {
|
||||
return EaglerProfile.presetSkinId;
|
||||
}
|
||||
}else if(p instanceof EntityOtherPlayerMP) {
|
||||
EntityOtherPlayerMP pp = (EntityOtherPlayerMP) p;
|
||||
if(pp.skinPacket != null) {
|
||||
if(pp.skinPacket[0] != (byte)4) {
|
||||
return 0;
|
||||
}else {
|
||||
if(((int)pp.skinPacket[1] & 0xFF) >= DefaultSkinRenderer.defaultVanillaSkins.length) {
|
||||
return 0;
|
||||
}else {
|
||||
return (int)pp.skinPacket[1] & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static ModelBiped oldSkinRenderer = null;
|
||||
public static ModelBipedNewSkins newSkinRenderer = null;
|
||||
public static ModelBipedNewSkins newSkinRendererSlim = null;
|
||||
public static ModelZombie zombieRenderer = null;
|
||||
public static ModelVillager villagerRenderer = null;
|
||||
public static ModelEnderman endermanRenderer = null;
|
||||
public static ModelBlaze blazeRenderer = null;
|
||||
public static ModelSkeleton skeletonRenderer = null;
|
||||
|
||||
public static void renderPlayerPreview(int x, int y, int mx, int my, int id2) {
|
||||
boolean capeMode = (id2 & 0x10000) == 0x10000;
|
||||
if(capeMode) {
|
||||
id2 -= 0x10000;
|
||||
}
|
||||
int id = id2 - EaglerProfile.skins.size();
|
||||
boolean highPoly = isHighPoly(id);
|
||||
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
|
||||
if(highPoly) {
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_CULL_FACE);
|
||||
}else {
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_CULL_FACE);
|
||||
}
|
||||
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glTranslatef((float) x, (float) (y - 80), 100.0F);
|
||||
EaglerAdapter.glScalef(50.0f, 50.0f, 50.0f);
|
||||
EaglerAdapter.glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_RESCALE_NORMAL);
|
||||
EaglerAdapter.glScalef(1.0F, -1.0F, 1.0F);
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
EaglerAdapter.glTranslatef(0.0F, 1.0F, 0.0F);
|
||||
if(capeMode) {
|
||||
EaglerAdapter.glRotatef(140.0f, 0.0f, 1.0f, 0.0f);
|
||||
mx = x - (x - mx) - 20;
|
||||
EaglerAdapter.glRotatef(((y - my) * -0.02f), 1.0f, 0.0f, 0.0f);
|
||||
}else {
|
||||
EaglerAdapter.glRotatef(((y - my) * -0.06f), 1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
EaglerAdapter.glRotatef(((x - mx) * 0.06f), 0.0f, 1.0f, 0.0f);
|
||||
EaglerAdapter.glTranslatef(0.0F, -1.0F, 0.0F);
|
||||
|
||||
if(highPoly) {
|
||||
EaglerAdapter.flipLightMatrix();
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
|
||||
EaglerAdapter.glTranslatef(0.0f, -1.5f, 0.0f);
|
||||
EaglerAdapter.glScalef(HighPolySkin.highPolyScale, HighPolySkin.highPolyScale, HighPolySkin.highPolyScale);
|
||||
HighPolySkin msh = defaultHighPoly[id];
|
||||
msh.texture.bindTexture();
|
||||
|
||||
if(msh.bodyModel != null) {
|
||||
EaglerAdapter.drawHighPoly(msh.bodyModel.getModel());
|
||||
}
|
||||
|
||||
if(msh.headModel != null) {
|
||||
EaglerAdapter.drawHighPoly(msh.headModel.getModel());
|
||||
}
|
||||
|
||||
if(msh.limbsModel != null && msh.limbsModel.length > 0) {
|
||||
for(int i = 0; i < msh.limbsModel.length; ++i) {
|
||||
float offset = 0.0f;
|
||||
if(msh.limbsOffset != null) {
|
||||
if(msh.limbsOffset.length == 1) {
|
||||
offset = msh.limbsOffset[0];
|
||||
}else {
|
||||
offset = msh.limbsOffset[i];
|
||||
}
|
||||
}
|
||||
if(offset != 0.0f || msh.limbsInitialRotation != 0.0f) {
|
||||
EaglerAdapter.glPushMatrix();
|
||||
if(offset != 0.0f) {
|
||||
EaglerAdapter.glTranslatef(0.0f, offset, 0.0f);
|
||||
}
|
||||
if(msh.limbsInitialRotation != 0.0f) {
|
||||
EaglerAdapter.glRotatef(msh.limbsInitialRotation, 1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
EaglerAdapter.drawHighPoly(msh.limbsModel[i].getModel());
|
||||
|
||||
if(offset != 0.0f || msh.limbsInitialRotation != 0.0f) {
|
||||
EaglerAdapter.glPopMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EaglerAdapter.glPopMatrix();
|
||||
EaglerAdapter.flipLightMatrix();
|
||||
}else {
|
||||
if(id < 0) {
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(EaglerProfile.skins.get(id2).glTex);
|
||||
}else {
|
||||
defaultVanillaSkins[id].bindTexture();
|
||||
}
|
||||
|
||||
boolean gonnaShowCape = false;
|
||||
if(isStandardModel(id) || id < 0) {
|
||||
if(oldSkinRenderer == null) oldSkinRenderer = new ModelBiped(0.0F, 0.0F, 64, 32);
|
||||
if(newSkinRenderer == null) newSkinRenderer = new ModelBipedNewSkins(0.0F, false);
|
||||
if(newSkinRendererSlim == null) newSkinRendererSlim = new ModelBipedNewSkins(0.0F, true);
|
||||
oldSkinRenderer.isChild = false;
|
||||
newSkinRenderer.isChild = false;
|
||||
newSkinRendererSlim.isChild = false;
|
||||
boolean isNew = isNewSkin(id);
|
||||
if(id < 0) {
|
||||
int type = EaglerProfile.getSkinSize(EaglerProfile.skins.get(id2).data.length);
|
||||
isNew = (type == 1 || type == 3);
|
||||
}
|
||||
if(isNew) {
|
||||
if((id < 0 && EaglerProfile.skins.get(id2).slim) || (id >= 0 && isAlexSkin(id))) {
|
||||
newSkinRendererSlim.blockTransparentSkin = true;
|
||||
newSkinRendererSlim.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
newSkinRendererSlim.blockTransparentSkin = false;
|
||||
}else {
|
||||
newSkinRenderer.blockTransparentSkin = true;
|
||||
newSkinRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
newSkinRenderer.blockTransparentSkin = false;
|
||||
}
|
||||
}else {
|
||||
oldSkinRenderer.blockTransparentSkin = true;
|
||||
oldSkinRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
oldSkinRenderer.blockTransparentSkin = false;
|
||||
}
|
||||
gonnaShowCape = capeMode;
|
||||
}else if(isZombieModel(id)) {
|
||||
if(zombieRenderer == null) zombieRenderer = new ModelZombie(0.0F, true);
|
||||
zombieRenderer.isChild = false;
|
||||
zombieRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
gonnaShowCape = capeMode;
|
||||
}else if(id == 32) {
|
||||
if(villagerRenderer == null) villagerRenderer = new ModelVillager(0.0F);
|
||||
villagerRenderer.isChild = false;
|
||||
villagerRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
}else if(id == 19) {
|
||||
if(endermanRenderer == null) endermanRenderer = new ModelEnderman();
|
||||
endermanRenderer.isChild = false;
|
||||
endermanRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
EaglerAdapter.glColor4f(1.4f, 1.4f, 1.4f, 1.0f);
|
||||
//EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
|
||||
//EaglerAdapter.glDisable(EaglerAdapter.GL_ALPHA_TEST);
|
||||
//EaglerAdapter.glBlendFunc(EaglerAdapter.GL_ONE, EaglerAdapter.GL_ONE);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_LIGHTING);
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_DEPTH_TEST);
|
||||
RenderEnderman.tex_eyes.bindTexture();
|
||||
endermanRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA);
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST);
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_DEPTH_TEST);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_TEXTURE_2D);
|
||||
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}else if(id == 20) {
|
||||
if(skeletonRenderer == null) skeletonRenderer = new ModelSkeleton(0.0F);
|
||||
skeletonRenderer.isChild = false;
|
||||
skeletonRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
}else if(id == 21) {
|
||||
if(blazeRenderer == null) blazeRenderer = new ModelBlaze();
|
||||
blazeRenderer.isChild = false;
|
||||
EaglerAdapter.glColor4f(1.5f, 1.5f, 1.5f, 1.0f);
|
||||
blazeRenderer.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
}
|
||||
if(gonnaShowCape && !(EaglerProfile.presetCapeId >= 0 && defaultVanillaCapes[EaglerProfile.presetCapeId] == null)) {
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glTranslatef(0.0F, 0.0F, 0.150F);
|
||||
EaglerAdapter.glRotatef(180.0F, 0.0F, 1.0F, 0.0F);
|
||||
EaglerAdapter.glRotatef(-6.0F, 1.0F, 0.0F, 0.0F);
|
||||
|
||||
if(EaglerProfile.presetCapeId < 0) {
|
||||
Minecraft.getMinecraft().renderEngine.bindTexture(EaglerProfile.capes.get(EaglerProfile.customCapeId).glTex);
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE);
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glScalef(2.0f, 1.0f, 1.0f);
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW);
|
||||
}else {
|
||||
defaultVanillaCapes[EaglerProfile.presetCapeId].bindTexture();
|
||||
}
|
||||
|
||||
if(oldSkinRenderer == null) oldSkinRenderer = new ModelBiped(0.0F, 0.0F, 64, 32);
|
||||
oldSkinRenderer.bipedCloak.render(0.0625F);
|
||||
|
||||
if(EaglerProfile.presetCapeId < 0) {
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_TEXTURE);
|
||||
EaglerAdapter.glPopMatrix();
|
||||
EaglerAdapter.glMatrixMode(EaglerAdapter.GL_MODELVIEW);
|
||||
}
|
||||
|
||||
EaglerAdapter.glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
EaglerAdapter.glPopMatrix();
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_RESCALE_NORMAL);
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_TEXTURE_2D);
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_LIGHTING);
|
||||
}
|
||||
|
||||
public static void renderAlexOrSteve(int x, int y, int mx, int my, boolean alex) {
|
||||
ModelBipedNewSkins bp;
|
||||
if(alex) {
|
||||
if(newSkinRendererSlim == null) {
|
||||
newSkinRendererSlim = new ModelBipedNewSkins(0.0F, true);
|
||||
}
|
||||
bp = newSkinRendererSlim;
|
||||
}else {
|
||||
if(newSkinRenderer == null) {
|
||||
newSkinRenderer = new ModelBipedNewSkins(0.0F, false);
|
||||
}
|
||||
bp = newSkinRenderer;
|
||||
}
|
||||
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_TEXTURE_2D);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_CULL_FACE);
|
||||
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glTranslatef((float) x, (float) (y - 80), 100.0F);
|
||||
EaglerAdapter.glScalef(50.0f, 50.0f, 50.0f);
|
||||
EaglerAdapter.glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_RESCALE_NORMAL);
|
||||
EaglerAdapter.glScalef(1.0F, -1.0F, 1.0F);
|
||||
RenderHelper.enableGUIStandardItemLighting();
|
||||
EaglerAdapter.glTranslatef(0.0F, 1.0F, 0.0F);
|
||||
EaglerAdapter.glRotatef(((y - my) * -0.06f), 1.0f, 0.0f, 0.0f);
|
||||
EaglerAdapter.glRotatef(((x - mx) * 0.06f), 0.0f, 1.0f, 0.0f);
|
||||
EaglerAdapter.glTranslatef(0.0F, -1.0F, 0.0F);
|
||||
|
||||
bp.isChild = false;
|
||||
bp.render(null, 0.0f, 0.0f, (float)(EaglerAdapter.steadyTimeMillis() % 100000) / 50f, ((x - mx) * 0.06f), ((y - my) * -0.1f), 0.0625F);
|
||||
|
||||
EaglerAdapter.glPopMatrix();
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_RESCALE_NORMAL);
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_TEXTURE_2D);
|
||||
OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_LIGHTING);
|
||||
}
|
||||
|
||||
public static boolean isPlayerPreviewNew(int id2) {
|
||||
int id = id2 - EaglerProfile.skins.size();
|
||||
if(id < 0) {
|
||||
return EaglerProfile.skins.get(id2).data.length == EaglerProfile.SKIN_DATA_SIZE[1] || EaglerProfile.skins.get(id2).data.length == EaglerProfile.SKIN_DATA_SIZE[3];
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
151
src/main/java/net/lax1dude/eaglercraft/EPK2Compiler.java
Normal file
151
src/main/java/net/lax1dude/eaglercraft/EPK2Compiler.java
Normal file
@@ -0,0 +1,151 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
import com.jcraft.jzlib.CRC32;
|
||||
|
||||
public class EPK2Compiler {
|
||||
|
||||
private final ByteArrayOutputStream os;
|
||||
private final CRC32 checkSum = new CRC32();
|
||||
private int lengthIntegerOffset = 0;
|
||||
private int totalFileCount = 0;
|
||||
|
||||
public EPK2Compiler() {
|
||||
String name = "__TEXTUREPACK__";
|
||||
String owner = "__INTERNAL__";
|
||||
String type = "epk/resources";
|
||||
os = new ByteArrayOutputStream(0x200000);
|
||||
try {
|
||||
|
||||
os.write(new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)36,(byte)36}); // EAGPKG$$
|
||||
os.write(new byte[]{(byte)6,(byte)118,(byte)101,(byte)114,(byte)50,(byte)46,(byte)48}); // 6 + ver2.0
|
||||
Date d = new Date();
|
||||
|
||||
byte[] filename = (name + ".epk").getBytes(StandardCharsets.UTF_8);
|
||||
os.write(filename.length);
|
||||
os.write(filename);
|
||||
|
||||
byte[] comment = ("\n\n # Eagler EPK v2.0\n\n")
|
||||
.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
os.write((comment.length >> 8) & 255);
|
||||
os.write(comment.length & 255);
|
||||
os.write(comment);
|
||||
|
||||
writeLong(d.getTime(), os);
|
||||
|
||||
lengthIntegerOffset = os.size();
|
||||
os.write(new byte[]{(byte)255,(byte)255,(byte)255,(byte)255}); // this will be replaced with the file count
|
||||
|
||||
os.write('0'); // compression type: none
|
||||
|
||||
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
|
||||
os.write(new byte[]{(byte)9,(byte)102,(byte)105,(byte)108,(byte)101,(byte)45,(byte)116,(byte)121,
|
||||
(byte)112,(byte)101}); // 9 + file-type
|
||||
|
||||
byte[] typeBytes = type.getBytes(StandardCharsets.UTF_8);
|
||||
writeInt(typeBytes.length, os);
|
||||
os.write(typeBytes); // write type
|
||||
os.write('>');
|
||||
|
||||
++totalFileCount;
|
||||
|
||||
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
|
||||
os.write(new byte[]{(byte)10,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)110,
|
||||
(byte)97,(byte)109,(byte)101}); // 10 + name
|
||||
|
||||
byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
|
||||
writeInt(nameBytes.length, os);
|
||||
os.write(nameBytes); // write name
|
||||
os.write('>');
|
||||
|
||||
++totalFileCount;
|
||||
|
||||
os.write(new byte[]{(byte)72,(byte)69,(byte)65,(byte)68}); // HEAD
|
||||
os.write(new byte[]{(byte)11,(byte)119,(byte)111,(byte)114,(byte)108,(byte)100,(byte)45,(byte)111,
|
||||
(byte)119,(byte)110,(byte)101,(byte)114}); // 11 + owner
|
||||
|
||||
byte[] ownerBytes = owner.getBytes(StandardCharsets.UTF_8);
|
||||
writeInt(ownerBytes.length, os);
|
||||
os.write(ownerBytes); // write owner
|
||||
os.write('>');
|
||||
|
||||
++totalFileCount;
|
||||
|
||||
}catch(IOException ex) {
|
||||
throw new RuntimeException("This happened somehow", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void append(String name, byte[] dat) {
|
||||
try {
|
||||
|
||||
checkSum.reset();
|
||||
checkSum.update(dat, 0, dat.length);
|
||||
long sum = checkSum.getValue();
|
||||
|
||||
os.write(new byte[]{(byte)70,(byte)73,(byte)76,(byte)69}); // FILE
|
||||
|
||||
byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(nameBytes.length);
|
||||
os.write(nameBytes);
|
||||
|
||||
writeInt(dat.length + 5, os);
|
||||
writeInt((int)sum, os);
|
||||
|
||||
os.write(dat);
|
||||
|
||||
os.write(':');
|
||||
os.write('>');
|
||||
|
||||
++totalFileCount;
|
||||
|
||||
}catch(IOException ex) {
|
||||
throw new RuntimeException("This happened somehow", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] complete() {
|
||||
try {
|
||||
|
||||
os.write(new byte[]{(byte)69,(byte)78,(byte)68,(byte)36}); // END$
|
||||
os.write(new byte[]{(byte)58,(byte)58,(byte)58,(byte)89,(byte)69,(byte)69,(byte)58,(byte)62}); // :::YEE:>
|
||||
|
||||
byte[] ret = os.toByteArray();
|
||||
|
||||
ret[lengthIntegerOffset] = (byte)((totalFileCount >> 24) & 0xFF);
|
||||
ret[lengthIntegerOffset + 1] = (byte)((totalFileCount >> 16) & 0xFF);
|
||||
ret[lengthIntegerOffset + 2] = (byte)((totalFileCount >> 8) & 0xFF);
|
||||
ret[lengthIntegerOffset + 3] = (byte)(totalFileCount & 0xFF);
|
||||
|
||||
return ret;
|
||||
|
||||
}catch(IOException ex) {
|
||||
throw new RuntimeException("This happened somehow", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeInt(int i, OutputStream os) throws IOException {
|
||||
os.write((i >> 24) & 0xFF);
|
||||
os.write((i >> 16) & 0xFF);
|
||||
os.write((i >> 8) & 0xFF);
|
||||
os.write(i & 0xFF);
|
||||
}
|
||||
|
||||
public static void writeLong(long i, OutputStream os) throws IOException {
|
||||
os.write((int)((i >> 56) & 0xFF));
|
||||
os.write((int)((i >> 48) & 0xFF));
|
||||
os.write((int)((i >> 40) & 0xFF));
|
||||
os.write((int)((i >> 32) & 0xFF));
|
||||
os.write((int)((i >> 24) & 0xFF));
|
||||
os.write((int)((i >> 16) & 0xFF));
|
||||
os.write((int)((i >> 8) & 0xFF));
|
||||
os.write((int)(i & 0xFF));
|
||||
}
|
||||
|
||||
}
|
||||
216
src/main/java/net/lax1dude/eaglercraft/EPKDecompiler.java
Normal file
216
src/main/java/net/lax1dude/eaglercraft/EPKDecompiler.java
Normal file
@@ -0,0 +1,216 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.jcraft.jzlib.CRC32;
|
||||
import com.jcraft.jzlib.GZIPInputStream;
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
|
||||
public class EPKDecompiler {
|
||||
|
||||
public static class FileEntry {
|
||||
public final String type;
|
||||
public final String name;
|
||||
public final byte[] data;
|
||||
protected FileEntry(String type, String name, byte[] data) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
private EaglerInputStream in2;
|
||||
private DataInputStream in;
|
||||
private InputStream zis;
|
||||
private SHA1Digest dg;
|
||||
private CRC32 crc32;
|
||||
private int numFiles;
|
||||
private boolean isFinished = false;
|
||||
private boolean isOldFormat = false;
|
||||
|
||||
public EPKDecompiler(byte[] data) throws IOException {
|
||||
in2 = new EaglerInputStream(data);
|
||||
|
||||
byte[] header = new byte[8];
|
||||
in2.read(header);
|
||||
|
||||
if(Arrays.equals(header, new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)36,(byte)36})) {
|
||||
byte[] endCode = new byte[] { (byte)':', (byte)':', (byte)':', (byte)'Y',
|
||||
(byte)'E', (byte)'E', (byte)':', (byte)'>' };
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
if(data[data.length - 8 + i] != endCode[i]) {
|
||||
throw new IOException("EPK file is missing EOF code (:::YEE:>)");
|
||||
}
|
||||
}
|
||||
in2 = new EaglerInputStream(data, 8, data.length - 16);
|
||||
initNew();
|
||||
}else if(Arrays.equals(header, new byte[]{(byte)69,(byte)65,(byte)71,(byte)80,(byte)75,(byte)71,(byte)33,(byte)33})) {
|
||||
initOld();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isOld() {
|
||||
return isOldFormat;
|
||||
}
|
||||
|
||||
public FileEntry readFile() throws IOException {
|
||||
if(!isOldFormat) {
|
||||
return readFileNew();
|
||||
}else {
|
||||
return readFileOld();
|
||||
}
|
||||
}
|
||||
|
||||
private void initNew() throws IOException {
|
||||
InputStream is = in2;
|
||||
|
||||
String vers = readASCII(is);
|
||||
if(!vers.startsWith("ver2.")) {
|
||||
throw new IOException("Unknown or invalid EPK version: " + vers);
|
||||
}
|
||||
|
||||
is.skip(is.read()); // skip filename
|
||||
is.skip(loadShort(is)); // skip comment
|
||||
is.skip(8); // skip millis date
|
||||
|
||||
numFiles = loadInt(is);
|
||||
|
||||
char compressionType = (char)is.read();
|
||||
|
||||
switch(compressionType) {
|
||||
case 'G':
|
||||
zis = new GZIPInputStream(is);
|
||||
break;
|
||||
case 'Z':
|
||||
zis = new InflaterInputStream(is);
|
||||
break;
|
||||
case '0':
|
||||
zis = is;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Invalid or unsupported EPK compression: " + compressionType);
|
||||
}
|
||||
|
||||
crc32 = new CRC32();
|
||||
|
||||
}
|
||||
|
||||
private FileEntry readFileNew() throws IOException {
|
||||
if(isFinished) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] typeBytes = new byte[4];
|
||||
zis.read(typeBytes);
|
||||
String type = readASCII(typeBytes);
|
||||
|
||||
if(numFiles == 0) {
|
||||
if(!"END$".equals(type)) {
|
||||
throw new IOException("EPK file is missing END code (END$)");
|
||||
}
|
||||
isFinished = true;
|
||||
return null;
|
||||
}else {
|
||||
if("END$".equals(type)) {
|
||||
throw new IOException("Unexpected END when there are still " + numFiles + " files remaining");
|
||||
}else {
|
||||
String name = readASCII(zis);
|
||||
int len = loadInt(zis);
|
||||
byte[] data;
|
||||
|
||||
if("FILE".equals(type)) {
|
||||
if(len < 5) {
|
||||
throw new IOException("File '" + name + "' is incomplete (no crc)");
|
||||
}
|
||||
|
||||
int loadedCrc = loadInt(zis);
|
||||
|
||||
data = new byte[len - 5];
|
||||
zis.read(data);
|
||||
|
||||
crc32.reset();
|
||||
crc32.update(data, 0, data.length);
|
||||
if((int)crc32.getValue() != loadedCrc) {
|
||||
throw new IOException("File '" + name + "' has an invalid checksum");
|
||||
}
|
||||
|
||||
if(zis.read() != ':') {
|
||||
throw new IOException("File '" + name + "' is incomplete");
|
||||
}
|
||||
}else {
|
||||
data = new byte[len];
|
||||
zis.read(data);
|
||||
}
|
||||
|
||||
if(zis.read() != '>') {
|
||||
throw new IOException("Object '" + name + "' is incomplete");
|
||||
}
|
||||
|
||||
--numFiles;
|
||||
return new FileEntry(type, name, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final int loadShort(InputStream is) throws IOException {
|
||||
return (is.read() << 8) | is.read();
|
||||
}
|
||||
|
||||
private static final int loadInt(InputStream is) throws IOException {
|
||||
return (is.read() << 24) | (is.read() << 16) | (is.read() << 8) | is.read();
|
||||
}
|
||||
|
||||
public static final String readASCII(byte[] bytesIn) throws IOException {
|
||||
char[] charIn = new char[bytesIn.length];
|
||||
for(int i = 0; i < bytesIn.length; ++i) {
|
||||
charIn[i] = (char)((int)bytesIn[i] & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
private static final String readASCII(InputStream bytesIn) throws IOException {
|
||||
int len = bytesIn.read();
|
||||
char[] charIn = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
charIn[i] = (char)(bytesIn.read() & 0xFF);
|
||||
}
|
||||
return new String(charIn);
|
||||
}
|
||||
|
||||
private void initOld() throws IOException {
|
||||
isOldFormat = true;
|
||||
dg = new SHA1Digest();
|
||||
in = new DataInputStream(in2);
|
||||
in.readUTF();
|
||||
in = new DataInputStream(new InflaterInputStream(in2));
|
||||
}
|
||||
|
||||
private FileEntry readFileOld() throws IOException {
|
||||
if(isFinished) {
|
||||
return null;
|
||||
}
|
||||
String s = in.readUTF();
|
||||
if(s.equals(" end")) {
|
||||
isFinished = true;
|
||||
return null;
|
||||
}else if(!s.equals("<file>")) {
|
||||
throw new IOException("invalid epk file");
|
||||
}
|
||||
String path = in.readUTF();
|
||||
byte[] digest = new byte[20];
|
||||
byte[] digest2 = new byte[20];
|
||||
in.read(digest);
|
||||
int len = in.readInt();
|
||||
byte[] file = new byte[len];
|
||||
in.read(file);
|
||||
dg.update(file, 0, len); dg.doFinal(digest2, 0);
|
||||
if(!Arrays.equals(digest, digest2)) throw new IOException("invalid file hash for "+path);
|
||||
if(!"</file>".equals(in.readUTF())) throw new IOException("invalid epk file");
|
||||
return new FileEntry("FILE", path, file);
|
||||
}
|
||||
|
||||
}
|
||||
11
src/main/java/net/lax1dude/eaglercraft/EaglerAdapter.java
Normal file
11
src/main/java/net/lax1dude/eaglercraft/EaglerAdapter.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.glemu.EaglerAdapterGL30;
|
||||
|
||||
public class EaglerAdapter extends EaglerAdapterGL30 {
|
||||
|
||||
/*
|
||||
* YOU EAGLR!
|
||||
*/
|
||||
|
||||
}
|
||||
44
src/main/java/net/lax1dude/eaglercraft/EaglerImage.java
Normal file
44
src/main/java/net/lax1dude/eaglercraft/EaglerImage.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public class EaglerImage {
|
||||
|
||||
public final int[] data;
|
||||
public final int w;
|
||||
public final int h;
|
||||
public final boolean alpha;
|
||||
|
||||
public EaglerImage(int pw, int ph, boolean palpha) {
|
||||
this.w = pw;
|
||||
this.h = ph;
|
||||
this.alpha = palpha;
|
||||
this.data = new int[pw * ph];
|
||||
}
|
||||
|
||||
public EaglerImage(int[] pdata, int pw, int ph, boolean palpha) {
|
||||
if(pdata.length != pw*ph) {
|
||||
throw new IllegalArgumentException("array size does not equal image size");
|
||||
}
|
||||
this.w = pw;
|
||||
this.h = ph;
|
||||
this.alpha = palpha;
|
||||
if(!palpha) {
|
||||
for(int i = 0; i < pdata.length; ++i) {
|
||||
pdata[i] = pdata[i] | 0xFF000000;
|
||||
}
|
||||
}
|
||||
this.data = pdata;
|
||||
}
|
||||
|
||||
public static final EaglerImage loadImage(byte[] file) {
|
||||
return EaglerAdapter.loadPNG(file);
|
||||
}
|
||||
|
||||
public EaglerImage getSubImage(int x, int y, int pw, int ph) {
|
||||
int[] img = new int[pw * ph];
|
||||
for(int i = 0; i < ph; ++i) {
|
||||
System.arraycopy(data, (i + y) * this.w + x, img, i * pw, pw);
|
||||
}
|
||||
return new EaglerImage(img, pw, ph, alpha);
|
||||
}
|
||||
|
||||
}
|
||||
167
src/main/java/net/lax1dude/eaglercraft/EaglerInputStream.java
Normal file
167
src/main/java/net/lax1dude/eaglercraft/EaglerInputStream.java
Normal file
@@ -0,0 +1,167 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EaglerInputStream extends InputStream {
|
||||
|
||||
protected byte buf[];
|
||||
protected int pos;
|
||||
protected int mark = 0;
|
||||
protected int count;
|
||||
|
||||
public EaglerInputStream(byte[] buf) {
|
||||
this.buf = buf;
|
||||
this.pos = 0;
|
||||
this.count = buf.length;
|
||||
}
|
||||
|
||||
public EaglerInputStream(byte buf[], int offset, int length) {
|
||||
this.buf = buf;
|
||||
this.pos = offset;
|
||||
this.count = Math.min(offset + length, buf.length);
|
||||
this.mark = offset;
|
||||
}
|
||||
|
||||
public int read() {
|
||||
return (pos < count) ? (buf[pos++] & 0xff) : -1;
|
||||
}
|
||||
|
||||
public int read(byte b[], int off, int len) {
|
||||
if (pos >= count) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int avail = count - pos;
|
||||
if (len > avail) {
|
||||
len = avail;
|
||||
}
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
System.arraycopy(buf, pos, b, off, len);
|
||||
pos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
public byte[] readAllBytes() {
|
||||
byte[] result = Arrays.copyOfRange(buf, pos, count);
|
||||
pos = count;
|
||||
return result;
|
||||
}
|
||||
|
||||
public int readNBytes(byte[] b, int off, int len) {
|
||||
int n = read(b, off, len);
|
||||
return n == -1 ? 0 : n;
|
||||
}
|
||||
|
||||
public long transferTo(OutputStream out) throws IOException {
|
||||
int len = count - pos;
|
||||
out.write(buf, pos, len);
|
||||
pos = count;
|
||||
return len;
|
||||
}
|
||||
|
||||
public static byte[] inputStreamToBytesQuiet(InputStream is) {
|
||||
if (is == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return inputStreamToBytes(is);
|
||||
} catch (IOException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public long skip(long n) {
|
||||
long k = count - pos;
|
||||
if (n < k) {
|
||||
k = n < 0 ? 0 : n;
|
||||
}
|
||||
|
||||
pos += k;
|
||||
return k;
|
||||
}
|
||||
|
||||
public int available() {
|
||||
return count - pos;
|
||||
}
|
||||
|
||||
public boolean markSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void mark(int readAheadLimit) {
|
||||
mark = pos;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
pos = mark;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
}
|
||||
|
||||
public static byte[] inputStreamToBytes(InputStream is) throws IOException {
|
||||
try {
|
||||
if (is instanceof EaglerInputStream) {
|
||||
return ((EaglerInputStream) is).getAsArray();
|
||||
} else if (is instanceof ByteArrayInputStream) {
|
||||
byte[] ret = new byte[is.available()];
|
||||
is.read(ret);
|
||||
return ret;
|
||||
} else {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
|
||||
byte[] buf = new byte[1024];
|
||||
int i;
|
||||
while ((i = is.read(buf)) != -1) {
|
||||
os.write(buf, 0, i);
|
||||
}
|
||||
return os.toByteArray();
|
||||
}
|
||||
}finally {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] inputStreamToBytesNoClose(InputStream is) throws IOException {
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
|
||||
byte[] buf = new byte[1024];
|
||||
int i;
|
||||
while ((i = is.read(buf)) != -1) {
|
||||
os.write(buf, 0, i);
|
||||
}
|
||||
return os.toByteArray();
|
||||
}
|
||||
|
||||
public byte[] getAsArray() {
|
||||
if (pos == 0 && count == buf.length) {
|
||||
return buf;
|
||||
} else {
|
||||
byte[] ret = new byte[count];
|
||||
System.arraycopy(buf, pos, ret, 0, count);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canUseArrayDirectly() {
|
||||
return pos == 0 && count == buf.length;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public int getMark() {
|
||||
return mark;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
28
src/main/java/net/lax1dude/eaglercraft/EaglerMisc.java
Normal file
28
src/main/java/net/lax1dude/eaglercraft/EaglerMisc.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import com.jcraft.jzlib.InflaterInputStream;
|
||||
|
||||
public class EaglerMisc {
|
||||
|
||||
public static byte[] uncompress(byte[] input) throws IOException {
|
||||
return EaglerInputStream.inputStreamToBytes(new InflaterInputStream(new EaglerInputStream(input)));
|
||||
}
|
||||
|
||||
public static String bytesToString(byte[] bb) {
|
||||
if (bb == null)
|
||||
return "";
|
||||
return new String(bb, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String[] bytesToLines(byte[] bb) {
|
||||
String contents = bytesToString(bb);
|
||||
if (contents.isEmpty()) {
|
||||
return new String[0];
|
||||
} else {
|
||||
return contents.replace("\r\n", "\n").split("[\r\n]");
|
||||
}
|
||||
}
|
||||
}
|
||||
254
src/main/java/net/lax1dude/eaglercraft/EaglerProfile.java
Normal file
254
src/main/java/net/lax1dude/eaglercraft/EaglerProfile.java
Normal file
@@ -0,0 +1,254 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.NBTBase;
|
||||
import net.minecraft.src.NBTTagByteArray;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
|
||||
public class EaglerProfile {
|
||||
|
||||
public static class EaglerProfileSkin {
|
||||
public String name;
|
||||
public byte[] data;
|
||||
public boolean slim;
|
||||
public int glTex;
|
||||
public EaglerProfileSkin(String name, byte[] data, boolean slim, int glTex) {
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
this.slim = slim;
|
||||
this.glTex = glTex;
|
||||
}
|
||||
}
|
||||
|
||||
public static class EaglerProfileCape {
|
||||
public String name;
|
||||
public byte[] data;
|
||||
public int glTex;
|
||||
public EaglerProfileCape(String name, byte[] data, int glTex) {
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
this.glTex = glTex;
|
||||
}
|
||||
}
|
||||
|
||||
public static String username;
|
||||
public static int presetSkinId;
|
||||
public static int customSkinId;
|
||||
public static int presetCapeId;
|
||||
public static int customCapeId;
|
||||
|
||||
public static int newSkinNotificationIndex = 0;
|
||||
|
||||
public static final int[] SKIN_DATA_SIZE = new int[] { 64*32*4, 64*64*4, -9, -9, 1, 64*64*4, -9 };
|
||||
public static final int[] CAPE_DATA_SIZE = new int[] { 32*32*4, -9, 1 };
|
||||
|
||||
public static ArrayList<EaglerProfileSkin> skins = new ArrayList<>();
|
||||
public static ArrayList<EaglerProfileCape> capes = new ArrayList<>();
|
||||
|
||||
public static final EaglercraftRandom rand;
|
||||
|
||||
public static int getSkinSize(int len) {
|
||||
for(int i = 0; i < SKIN_DATA_SIZE.length; ++i) {
|
||||
if(len == SKIN_DATA_SIZE[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int getCapeSize(int len) {
|
||||
for(int i = 0; i < CAPE_DATA_SIZE.length; ++i) {
|
||||
if(len == CAPE_DATA_SIZE[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static byte[] getSkinPacket() {
|
||||
if(presetSkinId == -1) {
|
||||
byte[] d = skins.get(customSkinId).data;
|
||||
if(d == null) {
|
||||
return new byte[] { (byte)4, (byte)0 };
|
||||
}
|
||||
byte[] d2 = new byte[1 + d.length];
|
||||
int sz = getSkinSize(d.length);
|
||||
if(sz < 0) {
|
||||
return new byte[] { (byte)4, (byte)0 };
|
||||
}
|
||||
d2[0] = (byte) sz;
|
||||
if(d2[0] == (byte)1 && skins.get(customSkinId).slim) {
|
||||
d2[0] = (byte)5;
|
||||
}
|
||||
if(d2[0] == (byte)3 && skins.get(customSkinId).slim) {
|
||||
d2[0] = (byte)6;
|
||||
}
|
||||
System.arraycopy(d, 0, d2, 1, d.length);
|
||||
return d2;
|
||||
}else {
|
||||
return new byte[] { (byte)4, (byte)presetSkinId };
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] getCapePacket() {
|
||||
int sf = Minecraft.getMinecraft().gameSettings.getSkinLayers();
|
||||
if(presetCapeId == -1) {
|
||||
byte[] d = capes.get(customCapeId).data;
|
||||
if(d == null) {
|
||||
return new byte[] { (byte)2, (byte)sf, (byte)0 };
|
||||
}
|
||||
byte[] d2 = new byte[2 + d.length];
|
||||
int sz = getCapeSize(d.length);
|
||||
if(sz < 0) {
|
||||
return new byte[] { (byte)2, (byte)sf, (byte)0 };
|
||||
}
|
||||
d2[0] = (byte) sz;
|
||||
d2[1] = (byte) sf;
|
||||
System.arraycopy(d, 0, d2, 2, d.length);
|
||||
return d2;
|
||||
}else {
|
||||
return new byte[] { (byte)2, (byte)sf, (byte)presetCapeId };
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] concatArrays(String[] a, String[] b) {
|
||||
String[] r = new String[a.length + b.length];
|
||||
System.arraycopy(a, 0, r, 0, a.length);
|
||||
System.arraycopy(b, 0, r, a.length, b.length);
|
||||
return r;
|
||||
}
|
||||
|
||||
public static int addSkin(String name, byte[] data, boolean slim) {
|
||||
int i = -1;
|
||||
for(int j = 0, l = skins.size(); j < l; ++j) {
|
||||
if(skins.get(j).name.equalsIgnoreCase(name)) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int t = getSkinSize(data.length);
|
||||
|
||||
if(t == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int w, h;
|
||||
|
||||
switch(t) {
|
||||
default:
|
||||
case 0:
|
||||
w = 64;
|
||||
h = 32;
|
||||
break;
|
||||
case 1:
|
||||
case 5:
|
||||
w = 64;
|
||||
h = 64;
|
||||
break;
|
||||
}
|
||||
|
||||
int im = Minecraft.getMinecraft().renderEngine.setupTextureRaw(data, w, h);
|
||||
if(i == -1) {
|
||||
i = skins.size();
|
||||
skins.add(new EaglerProfileSkin(name, data, slim, im));
|
||||
}else {
|
||||
skins.get(i).glTex = im;
|
||||
skins.get(i).data = data;
|
||||
skins.get(i).slim = slim;
|
||||
}
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
public static int addCape(String name, byte[] data) {
|
||||
int i = -1;
|
||||
for(int j = 0, l = capes.size(); j < l; ++j) {
|
||||
if(capes.get(j).name.equalsIgnoreCase(name)) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int t = getCapeSize(data.length);
|
||||
|
||||
if(t == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int w, h;
|
||||
|
||||
switch(t) {
|
||||
default:
|
||||
case 0:
|
||||
w = 32;
|
||||
h = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
int im = Minecraft.getMinecraft().renderEngine.setupTextureRaw(data, w, h);
|
||||
if(i == -1) {
|
||||
i = capes.size();
|
||||
capes.add(new EaglerProfileCape(name, data, im));
|
||||
}else {
|
||||
capes.get(i).glTex = im;
|
||||
capes.get(i).data = data;
|
||||
}
|
||||
return i;
|
||||
|
||||
}
|
||||
|
||||
static {
|
||||
String[] usernameDefaultWords = ConfigConstants.profanity ? new String[] {
|
||||
"Eagler", "Eagler", "Bitch", "Cock", "Milf", "Milf", "Yeer", "Groon",
|
||||
"Eag", "Deevis", "Chode", "Deev", "Deev", "Fucker", "Fucking",
|
||||
"Dumpster", "Dumpster", "Cum", "Chad", "Egg", "Fudgler", "Fudgli",
|
||||
"Yee", "Yee", "Yee", "Yeet", "Flumpter", "Darvy", "Darver", "Darver",
|
||||
"Fuck", "Fuck", "Frick", "Eagler", "Vigg", "Vigg", "Cunt", "Darvig"
|
||||
} : new String[] {
|
||||
"Yeeish", "Yeeish", "Yee", "Yee", "Yeer", "Yeeler", "Eagler", "Eagl",
|
||||
"Darver", "Darvler", "Vool", "Vigg", "Vigg", "Deev", "Yigg", "Yeeg"
|
||||
};
|
||||
|
||||
rand = new EaglercraftRandom();
|
||||
|
||||
do {
|
||||
username = usernameDefaultWords[rand.nextInt(usernameDefaultWords.length)] + usernameDefaultWords[rand.nextInt(usernameDefaultWords.length)] + (10 + rand.nextInt(90));
|
||||
}while(username.length() > 16);
|
||||
|
||||
presetSkinId = rand.nextInt(GuiScreenEditProfile.defaultOptions.length);
|
||||
customSkinId = -1;
|
||||
}
|
||||
|
||||
public static void loadFromStorage() {
|
||||
if(!LocalStorageManager.profileSettingsStorage.hasNoTags()) {
|
||||
presetSkinId = LocalStorageManager.profileSettingsStorage.getInteger("ps");
|
||||
customSkinId = LocalStorageManager.profileSettingsStorage.getInteger("cs");
|
||||
presetCapeId = LocalStorageManager.profileSettingsStorage.getInteger("pc");
|
||||
customCapeId = LocalStorageManager.profileSettingsStorage.getInteger("cc");
|
||||
username = LocalStorageManager.profileSettingsStorage.getString("name");
|
||||
newSkinNotificationIndex = LocalStorageManager.profileSettingsStorage.getInteger("nsi");
|
||||
if(newSkinNotificationIndex == 0) {
|
||||
newSkinNotificationIndex = GuiScreenEditProfile.newDefaultNotice;
|
||||
}
|
||||
NBTTagCompound n = LocalStorageManager.profileSettingsStorage.getCompoundTag("skins");
|
||||
for(Object s : NBTTagCompound.getTagMap(n).keySet()) {
|
||||
String s2 = (String)s;
|
||||
NBTBase k = n.getTag(s2);
|
||||
if(k.getId() == (byte)7) {
|
||||
addSkin(s2, ((NBTTagByteArray)k).byteArray, false);
|
||||
}else if(k.getId() == (byte)10) {
|
||||
addSkin(s2, ((NBTTagCompound)k).getByteArray("data"), ((NBTTagCompound)k).getBoolean("slim"));
|
||||
}
|
||||
}
|
||||
n = LocalStorageManager.profileSettingsStorage.getCompoundTag("capes");
|
||||
for(Object s : NBTTagCompound.getTagMap(n).keySet()) {
|
||||
NBTTagCompound ct = n.getCompoundTag((String)s);
|
||||
addCape((String)s, ct.getByteArray("data"));
|
||||
}
|
||||
}else {
|
||||
newSkinNotificationIndex = GuiScreenEditProfile.newDefaultNotice;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public class EaglercraftRandom {
|
||||
|
||||
private static final long multiplier = 0x5DEECE66DL;
|
||||
private static final long addend = 0xBL;
|
||||
private static final long mask = (1L << 48) - 1;
|
||||
|
||||
private static final double DOUBLE_UNIT = 0x1.0p-53;
|
||||
private long seed = 69;
|
||||
|
||||
public EaglercraftRandom() {
|
||||
this(System.nanoTime());
|
||||
}
|
||||
|
||||
public EaglercraftRandom(long seed) {
|
||||
setSeed(seed);
|
||||
}
|
||||
|
||||
public void setSeed(long yeed) {
|
||||
seed = yeed;
|
||||
}
|
||||
|
||||
protected int next(int bits) {
|
||||
seed = (seed * multiplier + addend) & mask;
|
||||
return (int)(seed >>> (48 - bits));
|
||||
}
|
||||
|
||||
public void nextBytes(byte[] bytes) {
|
||||
for (int i = 0, len = bytes.length; i < len; )
|
||||
for (int rnd = nextInt(),
|
||||
n = Math.min(len - i, Integer.SIZE/Byte.SIZE);
|
||||
n-- > 0; rnd >>= Byte.SIZE)
|
||||
bytes[i++] = (byte)rnd;
|
||||
}
|
||||
public int nextInt() {
|
||||
return next(32);
|
||||
}
|
||||
public int nextInt(int bound) {
|
||||
int r = next(31);
|
||||
int m = bound - 1;
|
||||
if ((bound & m) == 0) // i.e., bound is a power of 2
|
||||
r = (int)((bound * (long)r) >> 31);
|
||||
else {
|
||||
for (int u = r;
|
||||
u - (r = u % bound) + m < 0;
|
||||
u = next(31))
|
||||
;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
public long nextLong() {
|
||||
return ((long)(next(32)) << 32) + next(32);
|
||||
}
|
||||
public boolean nextBoolean() {
|
||||
return next(1) != 0;
|
||||
}
|
||||
public float nextFloat() {
|
||||
return next(24) / ((float)(1 << 24));
|
||||
}
|
||||
public double nextDouble() {
|
||||
return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
|
||||
}
|
||||
private double nextNextGaussian;
|
||||
private boolean haveNextNextGaussian = false;
|
||||
public double nextGaussian() {
|
||||
// See Knuth, ACP, Section 3.4.1 Algorithm C.
|
||||
if (haveNextNextGaussian) {
|
||||
haveNextNextGaussian = false;
|
||||
return nextNextGaussian;
|
||||
} else {
|
||||
double v1, v2, s;
|
||||
do {
|
||||
v1 = 2 * nextDouble() - 1; // between -1 and 1
|
||||
v2 = 2 * nextDouble() - 1; // between -1 and 1
|
||||
s = v1 * v1 + v2 * v2;
|
||||
} while (s >= 1 || s == 0);
|
||||
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
|
||||
nextNextGaussian = v2 * multiplier;
|
||||
haveNextNextGaussian = true;
|
||||
return v1 * multiplier;
|
||||
}
|
||||
}
|
||||
}
|
||||
171
src/main/java/net/lax1dude/eaglercraft/EarlyLoadScreen.java
Normal file
171
src/main/java/net/lax1dude/eaglercraft/EarlyLoadScreen.java
Normal file
@@ -0,0 +1,171 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import static net.lax1dude.eaglercraft.EaglerAdapter.*;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.BufferArrayGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.BufferGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ProgramGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ShaderGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.TextureGL;
|
||||
import net.minecraft.src.GLAllocation;
|
||||
|
||||
public class EarlyLoadScreen {
|
||||
|
||||
public static final String loadScreen = "iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAHx0lEQVR42u3da27jIBRAYbfqFp1FuovM/GLEMIDBhsRJviNVapsYY8y5vPz4ut/v9wX4UL4VAQgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAMBr86MI3ovf39/i/9Z1XdZ1VUgEeN/Kf7vdqt8hgC7QW6OCE+CjK/+2bcv9fieCLtDjux9x/1t/u1xOveWSlisBXmQASoB/+fr6+vv7/X7vHteE8hxZrrpAkyo/2mU42soSgAAfN8YZ3aoSQOV/GNu2ZX9vGdjPEuBnVmXIVYqePly8famCne0TtuS1tt/a9kfSbWnqZw2u9yQesc91XZv7/iO2a+I+iG3b7uu63pdl2f1Z17WaTksaaXrbtk3JaynvR/O5l6/WtPaON3d8tf3v7e9d+RkVPeIVyDRKpREtfL+nGdxL7/f3d9m2bTdS5VZL4/Rz0fcRszm32604jZrLUyi/UXlb1/WlunKhTE63iCMif0tkao1IaXqlqFWKlr2RsTUPpXRLrUnYpqVlircfdby9LUCpbHpa1lyeW8tgL51SmZ9N+2dE5GqJlrkI0xJxaumV0ixt0xrd07TDdrl+aDoeGNnfbzne0RE1HqSOaF3SljptyXP7qF3QN3zi4Yw9LdF0r5+Zs7u175mLirU85KJiLbK3pt2bj1qZ1CJaz356WoD0u2ejaq11XNf1708uf73jqqeOAXotbIlgZ/t0tfSPRulZ050j0jubRjz2CGU/clyRRvvwv1LPIR4X5r6TtlJPmwY9W5la54vfea5+Zhm2dnniyj+j3GtdxCsMzL+vWAmuyujK2dLXnVGGYSZsduXPlV0625Vbk0nlnFlXhrYAezdjPFOa2sD4GRetlY5hdhnmpoHjKcXZlb927Llp4JCvWYHy8leDxpHgbCH0zBo9s3vyiLK8QiBIxwiPaHWnjwFGZbjl9r5RAtxut92Fp5GLTqPHP735qpXDrK5QbjFz27b/Wp802IXu2Yz6cGoadDmwCHV0enVJFpbCfkqLQ6Mvg9g7riPToEfyfrYMl4ZLOUadw1rZh33H/ytNjcbnunfavakeX02As3P1rZVoT4KeVdBXESDN05HV4pFXDaQrxqkE6TnISfC0dYAZA5PSSu3orkeYiSil/Sl3cm3b9t+NKbMHxHtTpenvcT7C33Gez+b1e3QFvvrUY2nhZ/Qi0KtMC+f6/KWpytnnsjWoXuKWyNaZkyud/HTh55mVvTYt++h8zDiXlTFnkwS1wfhlBZgxj917acNe9H9mZWuJvjPuez0azJ5RPj1T3kMe/zJyUNMzkMpdJts6MNybyckNXo/cwLI0XtZ8ZkaldBwt2x65RHvGMRwZoO9dWLh3CfqofC0zZhtKU5fpiWkVIE4n3b423Zemf0SA5cQdVenxt9x70FJ+8TEfkbxUuXqDytnp0L2p0kewzJjeOnMSWtKKt92rQCNageXEDTot05xH1iZy5Xf2lsra9iMrZDjW2dG9ha/7wLuNS5ctpDevt9y2WBu0ptvnxh2l75YutOrtu+/1m+N8tw66022PlGHrcfVuP+NCwNrg+2ETFPcPI45yLSu8s1Yg8UY3xb8K6WP2WualrzJjhDl8f2Ll721iPeiWAG8hwMw+LQhw6co/cpWaPO/DR4wBchU23APQMiMy43EhuAZDp0FfaQxwRCJjAQK8xTigp0uk4hPgowbH+vkEAD4GL8gAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAK7NJR6M9S6PLQzPHZr1sulSuXmCxQu3APHz+sNP6wOspr09/CL76ym3Tzr2t2sBHhk13+UYwgsmnvFeXwI8qUtRinZxZNq27e/3tm3Lvg8gjWRpxc09Rj3eb2l/ufTiZ5CG78Sfn305eO7durX8tH4W8pB+Pz32vTQJcGAcED+0Nv5//Pbw9GTl+sKh8sVRMo2WoWkPJy0WpiRB6XVFpa5IvF28v3RfvX36mpylBwKXPktbkjiI1I69liYBTg6E4wqTkyOWolRB4nTSE5XuszaI3dvfngRppM1F+9auTG4fuW1raeXendYiWk+aBBjQf44jZW/TWoriV3gRddwi9L57IPfY9lA5Q3nF6YZyq33WIkLt/NTSJMCAcUD4/Wzhxt2o3Hjg0a3emSdPt7Q2t9vtn3KrfXY0L7U091rWo599xBggjSgh0pSa79aTl4ugaR8913qU9ld6vWlvd6bn+7mB+96MUHpcLULtHftemlqAAwKEwVd6MtNBbK4C7kWLuMkuDT5zA+za/nKzMC0VOu0CtXQhal2UeKCfG2PUPsvNZrUcey3NV8Dj0Z/cvctNQ77DmogWAM0S7M0gQQvwluS6HFZ0CQA8DJdDgwAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAQACAAQACAAQACAAQACAAAABAAIABAAIABAAIABAAIAAAAEAAgAEAAgAEAAgAEAAgAAAAYBlWf4A1W4Hx65cJAoAAAAASUVORK5CYII=";
|
||||
public static final String enableScreen = "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAC4jAAAuIwF4pT92AAAEAklEQVR42u2dvXbjIBBG7T0+xw+gTp06v//LmE6dO/VR5a3wGZNh+BGSFeveJgkIBrDy8TGKds8/Pz/PExyW8/P55AY4MP9YgmNzmeeZVUABAA8AKADgAQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAY7LOI7fpQDX65VPtZCt18w5d7rdbigAbOgBxnE8DcPwJnnDMCTrNJlsUVcizTnj9HWxeVvINfN9y361OdTEk30551ZZt3PsvYDYxOSChoPQ6sJ21mRLBm61jY0lpy61gDKWNdfcNcv5wErWLbfPF88I9/s9WtayzopXS85YtPqcMeT23SqedV1pucal1V4iTUooV/IaWSfbWHU5JmkvpmzrsayaB9DqfJnVTpMff72sc869/WzVlcjjOI7mOOVYfBzfT05exLfT5pqae008a71Ly6tPASV79CfPylvFjpm+teLH+tXiF5nA2LOAUMpCibckWpPBUOJT20btFuDjyK8p+S45Z4fX+ti+LDb3pef62PosWbfkDbBW8mFPhB/gt8Vr7gG+kZK9+C/GM2+ArffnnKRHbT5gSdJoK0+ydrziGyCW115LolLxnHOr59q3lt89b6U8Czg4pgdI5bUtKY3VzfOclGBtTLVSmmqn1cdyC7Iud+5791KX1MLJDz3Mg2s59pK6sM/asdTmLrRx5pzjS+e+awWw9lstVeuv1/a10rqwT8sn5LQr8RzaMVfmKrR2qfnFjs57/puLS0nyoTZp0fL8XGq+ap8v4AES+3Msx74kN2/tmblewWoXPl9o+RykZH5/5hTQYv+y+vj084XcPHpJbHmt1s7yGbV1q+UBnHO/gnoZje2RmuzK/Vr2F3sWEF6TGkvutqH5CG08qTmk5u77tLyK5Qtq62rgxRA8AO8FHBkygQeHLQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAQAPACgA4AEABQA8AKAAgAcAFAC+3gNM03Tqum7VQSyN4dtvMdZDKcBWC9oqhr8JoIEHeDwep77vf5VJfL0vl9fLa/u+f+vPfx9eszSGNXZo5AH6vlcXW36gsqykrzViwAIPYL3r3nXd63v5m6i9J2+VaT8viWGNHZQbYE97+KdjHPIGKH0XPSyL7eXSjPk2YZlsN03Tq21OjLAs598ZggIT2MpMbW3IMICFN0Dsv4xpfUbfAvIAK9wAcOAtAMgDwJHzAIACAB4AUADAAwAKAHgAQAEADwAoAOABAAUAPACgAIAHABQA8ACAAgAeAFAAwAMACgB4AEABAA8AKADgAQAFADwAoACABwAUAPAAgAIAHgBQAMADAAoAeABAAQAPACgA4AEABQA8AKAAgAcAFADwANCe/0of1jQ8XY5YAAAAAElFTkSuQmCC";
|
||||
|
||||
private static BufferGL vbo = null;
|
||||
private static ProgramGL program = null;
|
||||
|
||||
public static void paintScreen() {
|
||||
|
||||
TextureGL tex = _wglGenTextures();
|
||||
_wglActiveTexture(_wGL_TEXTURE0);
|
||||
glBindTexture(_wGL_TEXTURE_2D, tex);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_NEAREST);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_NEAREST);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_CLAMP);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_CLAMP);
|
||||
//EaglerImage img = EaglerImage.loadImage(Base64.decodeBase64(loadScreen));
|
||||
EaglerImage img = EaglerAdapter.loadPNG(Base64.decodeBase64(loadScreen));
|
||||
IntBuffer upload = GLAllocation.createDirectIntBuffer(192*192);
|
||||
upload.put(img.data);
|
||||
upload.flip();
|
||||
_wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA, 192, 192, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, upload);
|
||||
|
||||
upload.clear();
|
||||
upload.put(Float.floatToIntBits(0.0f)); upload.put(Float.floatToIntBits(0.0f));
|
||||
upload.put(Float.floatToIntBits(0.0f)); upload.put(Float.floatToIntBits(1.0f));
|
||||
upload.put(Float.floatToIntBits(1.0f)); upload.put(Float.floatToIntBits(0.0f));
|
||||
upload.put(Float.floatToIntBits(1.0f)); upload.put(Float.floatToIntBits(0.0f));
|
||||
upload.put(Float.floatToIntBits(0.0f)); upload.put(Float.floatToIntBits(1.0f));
|
||||
upload.put(Float.floatToIntBits(1.0f)); upload.put(Float.floatToIntBits(1.0f));
|
||||
upload.flip();
|
||||
|
||||
vbo = _wglCreateBuffer();
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, vbo);
|
||||
_wglBufferData0(_wGL_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW);
|
||||
|
||||
ShaderGL vert = _wglCreateShader(_wGL_VERTEX_SHADER);
|
||||
_wglShaderSource(vert, _wgetShaderHeader()+"\nprecision lowp float; in vec2 a_pos; out vec2 v_pos; void main() { gl_Position = vec4(((v_pos = a_pos) - 0.5) * vec2(2.0, -2.0), 0.0, 1.0); }");
|
||||
_wglCompileShader(vert);
|
||||
|
||||
ShaderGL frag = _wglCreateShader(_wGL_FRAGMENT_SHADER);
|
||||
_wglShaderSource(frag, _wgetShaderHeader()+"\nprecision lowp float; in vec2 v_pos; out vec4 fragColor; uniform sampler2D tex; uniform vec2 aspect; void main() { fragColor = vec4(texture(tex, clamp(v_pos * aspect - ((aspect - 1.0) * 0.5), 0.02, 0.98)).rgb, 1.0); }");
|
||||
_wglCompileShader(frag);
|
||||
|
||||
program = _wglCreateProgram();
|
||||
|
||||
_wglAttachShader(program, vert);
|
||||
_wglAttachShader(program, frag);
|
||||
_wglBindAttributeLocation(program, 0, "a_pos");
|
||||
_wglLinkProgram(program);
|
||||
_wglDetachShader(program, vert);
|
||||
_wglDetachShader(program, frag);
|
||||
_wglDeleteShader(vert);
|
||||
_wglDeleteShader(frag);
|
||||
|
||||
sleep(50);
|
||||
|
||||
_wglUseProgram(program);
|
||||
_wglUniform1i(_wglGetUniformLocation(program, "tex"), 0);
|
||||
|
||||
int width = getCanvasWidth();
|
||||
int height = getCanvasHeight();
|
||||
float x, y;
|
||||
if(width > height) {
|
||||
x = (float)width / (float)height;
|
||||
y = 1.0f;
|
||||
}else {
|
||||
x = 1.0f;
|
||||
y = (float)height / (float)width;
|
||||
}
|
||||
|
||||
_wglActiveTexture(_wGL_TEXTURE0);
|
||||
glBindTexture(_wGL_TEXTURE_2D, tex);
|
||||
|
||||
_wglViewport(0, 0, width, height);
|
||||
_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
_wglClear(_wGL_COLOR_BUFFER_BIT | _wGL_DEPTH_BUFFER_BIT);
|
||||
|
||||
_wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y);
|
||||
|
||||
BufferArrayGL vao = _wglCreateVertexArray();
|
||||
_wglBindVertexArray0(vao);
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 2, _wGL_FLOAT, false, 8, 0);
|
||||
_wglDrawArrays(_wGL_TRIANGLES, 0, 6);
|
||||
_wglDisableVertexAttribArray(0);
|
||||
_wglFlush();
|
||||
updateDisplay(0, false);
|
||||
sleep(20);
|
||||
|
||||
_wglUseProgram(null);
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, null);
|
||||
glBindTexture(_wGL_TEXTURE_2D, null);
|
||||
_wglDeleteTextures(tex);
|
||||
_wglDeleteVertexArray(vao);
|
||||
}
|
||||
|
||||
public static void paintEnable() {
|
||||
|
||||
TextureGL tex = _wglGenTextures();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(_wGL_TEXTURE_2D, tex);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_NEAREST);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_NEAREST);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_CLAMP);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_CLAMP);
|
||||
//EaglerImage img = EaglerImage.loadImage(Base64.decodeBase64(enableScreen));
|
||||
EaglerImage img = EaglerAdapter.loadPNG(Base64.decodeBase64(enableScreen));
|
||||
IntBuffer upload = GLAllocation.createDirectIntBuffer(128*128);
|
||||
upload.put(img.data);
|
||||
upload.flip();
|
||||
_wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA, 128, 128, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, upload);
|
||||
|
||||
sleep(50);
|
||||
|
||||
_wglUseProgram(program);
|
||||
|
||||
int width = getCanvasWidth();
|
||||
int height = getCanvasHeight();
|
||||
float x, y;
|
||||
if(width > height) {
|
||||
x = (float)width / (float)height;
|
||||
y = 1.0f;
|
||||
}else {
|
||||
x = 1.0f;
|
||||
y = (float)height / (float)width;
|
||||
}
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(_wGL_TEXTURE_2D, tex);
|
||||
|
||||
_wglViewport(0, 0, width, height);
|
||||
_wglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
_wglClear(_wGL_COLOR_BUFFER_BIT | _wGL_DEPTH_BUFFER_BIT);
|
||||
|
||||
_wglUniform2f(_wglGetUniformLocation(program, "aspect"), x, y);
|
||||
|
||||
BufferArrayGL vao = _wglCreateVertexArray();
|
||||
_wglBindVertexArray0(vao);
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, vbo);
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 2, _wGL_FLOAT, false, 8, 0);
|
||||
_wglDrawArrays(_wGL_TRIANGLES, 0, 6);
|
||||
_wglDisableVertexAttribArray(0);
|
||||
_wglFlush();
|
||||
updateDisplay(0, false);
|
||||
sleep(20);
|
||||
|
||||
_wglUseProgram(null);
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, null);
|
||||
glBindTexture(_wGL_TEXTURE_2D, null);
|
||||
_wglDeleteTextures(tex);
|
||||
_wglDeleteVertexArray(vao);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
47
src/main/java/net/lax1dude/eaglercraft/EnumBrowser.java
Normal file
47
src/main/java/net/lax1dude/eaglercraft/EnumBrowser.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public enum EnumBrowser {
|
||||
|
||||
DESKTOP("Desktop"), CHROME("Chrome"), EDGE("Edge"), IE("IE"), FIREFOX("Firefox"), SAFARI("Safari"), OPERA("Opera"), WEBKIT("WebKit"), GECKO("Gecko"), UNKNOWN("Unknown");
|
||||
|
||||
public final String name;
|
||||
|
||||
private EnumBrowser(String string) {
|
||||
this.name = string;
|
||||
}
|
||||
|
||||
private static EnumBrowser identifiedBrowser = null;
|
||||
|
||||
public static EnumBrowser getBrowser() {
|
||||
if(identifiedBrowser == null) {
|
||||
String ua = " " + EaglerAdapter.getUserAgent().toLowerCase();
|
||||
if(ua.contains(" edg/")) {
|
||||
identifiedBrowser = EDGE;
|
||||
}else if(ua.contains(" opr/")) {
|
||||
identifiedBrowser = OPERA;
|
||||
}else if(ua.contains(" chrome/")) {
|
||||
identifiedBrowser = CHROME;
|
||||
}else if(ua.contains(" firefox/")) {
|
||||
identifiedBrowser = FIREFOX;
|
||||
}else if(ua.contains(" safari/")) {
|
||||
identifiedBrowser = SAFARI;
|
||||
}else if(ua.contains(" trident/") || ua.contains(" msie")) {
|
||||
identifiedBrowser = IE;
|
||||
}else if(ua.contains(" webkit/")) {
|
||||
identifiedBrowser = WEBKIT;
|
||||
}else if(ua.contains(" gecko/")) {
|
||||
identifiedBrowser = GECKO;
|
||||
}else if(ua.contains(" desktop/")) {
|
||||
identifiedBrowser = DESKTOP;
|
||||
}else {
|
||||
identifiedBrowser = UNKNOWN;
|
||||
}
|
||||
}
|
||||
return identifiedBrowser;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
71
src/main/java/net/lax1dude/eaglercraft/ExpiringSet.java
Normal file
71
src/main/java/net/lax1dude/eaglercraft/ExpiringSet.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
// note that there's a few things not implemented, but I don't care.
|
||||
|
||||
public class ExpiringSet<T> extends HashSet<T> {
|
||||
private final long expiration;
|
||||
private final ExpiringEvent<T> event;
|
||||
|
||||
private final Map<T, Long> timestamps = new HashMap<>();
|
||||
|
||||
public ExpiringSet(long expiration) {
|
||||
this.expiration = expiration;
|
||||
this.event = null;
|
||||
}
|
||||
|
||||
public ExpiringSet(long expiration, ExpiringEvent<T> event) {
|
||||
this.expiration = expiration;
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public interface ExpiringEvent<T> {
|
||||
void onExpiration(T item);
|
||||
}
|
||||
|
||||
public void checkForExpirations() {
|
||||
Iterator<T> iterator = this.timestamps.keySet().iterator();
|
||||
long now = EaglerAdapter.steadyTimeMillis();
|
||||
while (iterator.hasNext()) {
|
||||
T element = iterator.next();
|
||||
if (super.contains(element)) {
|
||||
if (this.timestamps.get(element) + this.expiration < now) {
|
||||
if (this.event != null) this.event.onExpiration(element);
|
||||
iterator.remove();
|
||||
super.remove(element);
|
||||
}
|
||||
} else {
|
||||
iterator.remove();
|
||||
super.remove(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean add(T o) {
|
||||
checkForExpirations();
|
||||
boolean success = super.add(o);
|
||||
if (success) timestamps.put(o, EaglerAdapter.steadyTimeMillis());
|
||||
return success;
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
checkForExpirations();
|
||||
boolean success = super.remove(o);
|
||||
if (success) timestamps.remove(o);
|
||||
return success;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.timestamps.clear();
|
||||
super.clear();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
checkForExpirations();
|
||||
return super.contains(o);
|
||||
}
|
||||
}
|
||||
124
src/main/java/net/lax1dude/eaglercraft/GeneralDigest.java
Normal file
124
src/main/java/net/lax1dude/eaglercraft/GeneralDigest.java
Normal file
@@ -0,0 +1,124 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
/**
|
||||
* base implementation of MD4 family style digest as outlined in
|
||||
* "Handbook of Applied Cryptography", pages 344 - 347.
|
||||
*/
|
||||
public abstract class GeneralDigest {
|
||||
private byte[] xBuf;
|
||||
private int xBufOff;
|
||||
|
||||
private long byteCount;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*/
|
||||
protected GeneralDigest()
|
||||
{
|
||||
xBuf = new byte[4];
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. We are using copy constructors in place
|
||||
* of the Object.clone() interface as this interface is not
|
||||
* supported by J2ME.
|
||||
*/
|
||||
protected GeneralDigest(GeneralDigest t)
|
||||
{
|
||||
xBuf = new byte[t.xBuf.length];
|
||||
System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
|
||||
|
||||
xBufOff = t.xBufOff;
|
||||
byteCount = t.byteCount;
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte in)
|
||||
{
|
||||
xBuf[xBufOff++] = in;
|
||||
|
||||
if (xBufOff == xBuf.length)
|
||||
{
|
||||
processWord(xBuf, 0);
|
||||
xBufOff = 0;
|
||||
}
|
||||
|
||||
byteCount++;
|
||||
}
|
||||
|
||||
public void update(
|
||||
byte[] in,
|
||||
int inOff,
|
||||
int len)
|
||||
{
|
||||
//
|
||||
// fill the current word
|
||||
//
|
||||
while ((xBufOff != 0) && (len > 0))
|
||||
{
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
|
||||
//
|
||||
// process whole words.
|
||||
//
|
||||
while (len > xBuf.length)
|
||||
{
|
||||
processWord(in, inOff);
|
||||
|
||||
inOff += xBuf.length;
|
||||
len -= xBuf.length;
|
||||
byteCount += xBuf.length;
|
||||
}
|
||||
|
||||
//
|
||||
// load in the remainder.
|
||||
//
|
||||
while (len > 0)
|
||||
{
|
||||
update(in[inOff]);
|
||||
|
||||
inOff++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
public void finish()
|
||||
{
|
||||
long bitLength = (byteCount << 3);
|
||||
|
||||
//
|
||||
// add the pad bytes.
|
||||
//
|
||||
update((byte)128);
|
||||
|
||||
while (xBufOff != 0)
|
||||
{
|
||||
update((byte)0);
|
||||
}
|
||||
|
||||
processLength(bitLength);
|
||||
|
||||
processBlock();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
byteCount = 0;
|
||||
|
||||
xBufOff = 0;
|
||||
for ( int i = 0; i < xBuf.length; i++ ) {
|
||||
xBuf[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void processWord(byte[] in, int inOff);
|
||||
|
||||
protected abstract void processLength(long bitLength);
|
||||
|
||||
protected abstract void processBlock();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.EnumChatFormatting;
|
||||
import net.minecraft.src.Gui;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiNetworkSettingsButton extends Gui {
|
||||
|
||||
private final GuiScreen screen;
|
||||
private final String text;
|
||||
private final Minecraft mc;
|
||||
|
||||
public GuiNetworkSettingsButton(GuiScreen screen) {
|
||||
this.screen = screen;
|
||||
this.text = StringTranslate.getInstance().translateKey("directConnect.lanWorldRelay");
|
||||
this.mc = Minecraft.getMinecraft();
|
||||
}
|
||||
|
||||
public void drawScreen(int xx, int yy) {
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
|
||||
|
||||
int w = mc.fontRenderer.getStringWidth(text);
|
||||
boolean hover = xx > 1 && yy > 1 && xx < (w * 3 / 4) + 7 && yy < 12;
|
||||
|
||||
drawString(mc.fontRenderer, EnumChatFormatting.UNDERLINE + text, 5, 5, hover ? 0xFFEEEE22 : 0xFFCCCCCC);
|
||||
|
||||
EaglerAdapter.glPopMatrix();
|
||||
}
|
||||
|
||||
public void mouseClicked(int xx, int yy, int btn) {
|
||||
int w = mc.fontRenderer.getStringWidth(text);
|
||||
if(xx > 2 && yy > 2 && xx < (w * 3 / 4) + 5 && yy < 12) {
|
||||
mc.displayGuiScreen(new GuiScreenRelay(screen));
|
||||
mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
128
src/main/java/net/lax1dude/eaglercraft/GuiScreenAddRelay.java
Normal file
128
src/main/java/net/lax1dude/eaglercraft/GuiScreenAddRelay.java
Normal file
@@ -0,0 +1,128 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiTextField;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenAddRelay extends GuiScreen {
|
||||
|
||||
/** This GUI's parent GUI. */
|
||||
private GuiScreenRelay parentGui;
|
||||
private GuiTextField serverAddress;
|
||||
private GuiTextField serverName;
|
||||
|
||||
public GuiScreenAddRelay(GuiScreenRelay par1GuiScreen) {
|
||||
this.parentGui = par1GuiScreen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the main game loop to update the screen.
|
||||
*/
|
||||
public void updateScreen() {
|
||||
this.serverName.updateCursorCounter();
|
||||
this.serverAddress.updateCursorCounter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the buttons (and other controls) to the screen in question.
|
||||
*/
|
||||
public void initGui() {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
EaglerAdapter.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
this.parentGui.addNewName = IntegratedServer.relayManager.makeNewRelayName();
|
||||
this.parentGui.addNewAddr = "";
|
||||
this.parentGui.addNewPrimary = IntegratedServer.relayManager.count() == 0;
|
||||
int sslOff = EaglerAdapter.isSSLPage() ? 36 : 0;
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12 + sslOff, var1.translateKey("addRelay.add")));
|
||||
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12 + sslOff, var1.translateKey("gui.cancel")));
|
||||
this.buttonList.add(new GuiButton(2, this.width / 2 - 100, 142, var1.translateKey("addRelay.primary") + ": " + (this.parentGui.addNewPrimary ? var1.translateKey("gui.yes") : var1.translateKey("gui.no"))));
|
||||
this.serverName = new GuiTextField(this.fontRenderer, this.width / 2 - 100, 106, 200, 20);
|
||||
this.serverAddress = new GuiTextField(this.fontRenderer, this.width / 2 - 100, 66, 200, 20);
|
||||
this.serverAddress.setMaxStringLength(128);
|
||||
this.serverAddress.setFocused(true);
|
||||
((GuiButton) this.buttonList.get(0)).enabled = this.serverAddress.getText().length() > 0 && this.serverAddress.getText().split(":").length > 0 && this.serverName.getText().length() > 0;
|
||||
this.serverName.setText(this.parentGui.addNewName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the screen is unloaded. Used to disable keyboard repeat events
|
||||
*/
|
||||
public void onGuiClosed() {
|
||||
EaglerAdapter.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a control is clicked. This is the equivalent of
|
||||
* ActionListener.actionPerformed(ActionEvent e).
|
||||
*/
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if (par1GuiButton.enabled) {
|
||||
if (par1GuiButton.id == 1) {
|
||||
this.parentGui.confirmClicked(false, 0);
|
||||
} else if (par1GuiButton.id == 0) {
|
||||
this.parentGui.addNewName = this.serverName.getText();
|
||||
this.parentGui.addNewAddr = this.serverAddress.getText();
|
||||
this.parentGui.confirmClicked(true, 0);
|
||||
} else if (par1GuiButton.id == 2) {
|
||||
StringTranslate var2 = StringTranslate.getInstance();
|
||||
this.parentGui.addNewPrimary = !this.parentGui.addNewPrimary;
|
||||
((GuiButton) this.buttonList.get(2)).displayString = var2.translateKey("addRelay.primary") + ": " + (this.parentGui.addNewPrimary ? var2.translateKey("gui.yes") : var2.translateKey("gui.no"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a key is typed. This is the equivalent of
|
||||
* KeyListener.keyTyped(KeyEvent e).
|
||||
*/
|
||||
protected void keyTyped(char par1, int par2) {
|
||||
this.serverName.textboxKeyTyped(par1, par2);
|
||||
this.serverAddress.textboxKeyTyped(par1, par2);
|
||||
|
||||
if (par1 == 9) {
|
||||
if (this.serverName.isFocused()) {
|
||||
this.serverName.setFocused(false);
|
||||
this.serverAddress.setFocused(true);
|
||||
} else {
|
||||
this.serverName.setFocused(true);
|
||||
this.serverAddress.setFocused(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (par1 == 13) {
|
||||
this.actionPerformed((GuiButton) this.buttonList.get(0));
|
||||
}
|
||||
|
||||
((GuiButton) this.buttonList.get(0)).enabled = this.serverAddress.getText().length() > 0 && this.serverAddress.getText().split(":").length > 0 && this.serverName.getText().length() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mouse is clicked.
|
||||
*/
|
||||
protected void mouseClicked(int par1, int par2, int par3) {
|
||||
super.mouseClicked(par1, par2, par3);
|
||||
this.serverAddress.mouseClicked(par1, par2, par3);
|
||||
this.serverName.mouseClicked(par1, par2, par3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the screen and all the components in it.
|
||||
*/
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("addRelay.title"), this.width / 2, 17, 16777215);
|
||||
this.drawString(this.fontRenderer, var4.translateKey("addRelay.address"), this.width / 2 - 100, 53, 10526880);
|
||||
this.drawString(this.fontRenderer, var4.translateKey("addRelay.name"), this.width / 2 - 100, 94, 10526880);
|
||||
if(EaglerAdapter.isSSLPage()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("addServer.SSLWarn1"), this.width / 2, 169, 0xccccff);
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("addServer.SSLWarn2"), this.width / 2, 181, 0xccccff);
|
||||
}
|
||||
this.serverName.drawTextBox();
|
||||
this.serverAddress.drawTextBox();
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
}
|
||||
109
src/main/java/net/lax1dude/eaglercraft/GuiScreenBackupWorld.java
Normal file
109
src/main/java/net/lax1dude/eaglercraft/GuiScreenBackupWorld.java
Normal file
@@ -0,0 +1,109 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.ipc.IPCPacket05RequestData;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiCreateWorld;
|
||||
import net.minecraft.src.GuiRenameWorld;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiYesNo;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
import net.minecraft.src.WorldInfo;
|
||||
|
||||
public class GuiScreenBackupWorld extends GuiScreen {
|
||||
|
||||
private GuiScreen selectWorld;
|
||||
|
||||
private GuiButton worldRecreate = null;
|
||||
private GuiButton worldDuplicate = null;
|
||||
private GuiButton worldExport = null;
|
||||
private GuiButton worldConvert = null;
|
||||
private GuiButton worldBackup = null;
|
||||
private long worldSeed;
|
||||
private NBTTagCompound levelDat;
|
||||
|
||||
private String worldName;
|
||||
|
||||
public GuiScreenBackupWorld(GuiScreen selectWorld, String worldName, NBTTagCompound levelDat) {
|
||||
this.selectWorld = selectWorld;
|
||||
this.worldName = worldName;
|
||||
this.levelDat = levelDat;
|
||||
this.worldSeed = levelDat.getCompoundTag("Data").getLong("RandomSeed");
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
this.buttonList.add(worldRecreate = new GuiButton(1, this.width / 2 - 100, this.height / 5 + 15, var1.translateKey("selectWorld.backup.recreate")));
|
||||
this.buttonList.add(worldDuplicate = new GuiButton(2, this.width / 2 - 100, this.height / 5 + 40, var1.translateKey("selectWorld.backup.duplicate")));
|
||||
this.buttonList.add(worldExport = new GuiButton(3, this.width / 2 - 100, this.height / 5 + 90, var1.translateKey("selectWorld.backup.export")));
|
||||
this.buttonList.add(worldConvert = new GuiButton(4, this.width / 2 - 100, this.height / 5 + 115, var1.translateKey("selectWorld.backup.vanilla")));
|
||||
this.buttonList.add(worldBackup = new GuiButton(5, this.width / 2 - 100, this.height / 5 + 146, var1.translateKey("selectWorld.backup.clearPlayerData")));
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 165, var1.translateKey("gui.cancel")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
this.drawDefaultBackground();
|
||||
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.title") + " '" + worldName + "'", this.width / 2, this.height / 5 - 25, 16777215);
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.seed") + " " + worldSeed, this.width / 2, this.height / 5 + 72, 0xAAAAFF);
|
||||
|
||||
int toolTipColor = 0xDDDDAA;
|
||||
if(worldRecreate.func_82252_a()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.recreate.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor);
|
||||
}else if(worldDuplicate.func_82252_a()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.duplicate.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor);
|
||||
}else if(worldExport.func_82252_a()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.export.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor);
|
||||
}else if(worldConvert.func_82252_a()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.vanilla.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor);
|
||||
}else if(worldBackup.func_82252_a()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.backup.clearPlayerData.tooltip"), this.width / 2, this.height / 5 - 2, toolTipColor);
|
||||
}
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
this.mc.displayGuiScreen(selectWorld);
|
||||
}else if(par1GuiButton.id == 1) {
|
||||
GuiCreateWorld cw = new GuiCreateWorld(selectWorld);
|
||||
cw.func_82286_a(new WorldInfo(this.levelDat.getCompoundTag("Data")));
|
||||
this.mc.displayGuiScreen(cw);
|
||||
}else if(par1GuiButton.id == 2) {
|
||||
this.mc.displayGuiScreen(new GuiRenameWorld(this.selectWorld, this.worldName, true));
|
||||
}else if(par1GuiButton.id == 3) {
|
||||
IntegratedServer.exportWorld(worldName, IPCPacket05RequestData.REQUEST_LEVEL_EAG);
|
||||
this.mc.displayGuiScreen(new GuiScreenSingleplayerLoading(selectWorld, "selectWorld.progress.exporting.1", () -> {
|
||||
byte[] b = IntegratedServer.getExportResponse();
|
||||
if(b != null) {
|
||||
EaglerAdapter.downloadBytes(worldName + ".epk", b);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
}else if(par1GuiButton.id == 4) {
|
||||
IntegratedServer.exportWorld(worldName, IPCPacket05RequestData.REQUEST_LEVEL_MCA);
|
||||
this.mc.displayGuiScreen(new GuiScreenSingleplayerLoading(selectWorld, "selectWorld.progress.exporting.2", () -> {
|
||||
byte[] b = IntegratedServer.getExportResponse();
|
||||
if(b != null) {
|
||||
EaglerAdapter.downloadBytes(worldName + ".zip", b);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
}else if(par1GuiButton.id == 5) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
this.mc.displayGuiScreen(new GuiYesNo(this, var4.translateKey("selectWorld.backup.clearPlayerData.warning1"),
|
||||
var4.translateKey("selectWorld.backup.clearPlayerData.warning2").replace("$world$", worldName).replace("$player$", EaglerProfile.username), 0));
|
||||
}
|
||||
}
|
||||
|
||||
public void confirmClicked(boolean par1, int par2) {
|
||||
if(par1) {
|
||||
IntegratedServer.clearPlayerData(worldName);
|
||||
}
|
||||
mc.displayGuiScreen(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiSlider2;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenChangeRelayTimeout extends GuiScreen {
|
||||
|
||||
private GuiScreen parent;
|
||||
private GuiSlider2 slider;
|
||||
private String title;
|
||||
|
||||
public GuiScreenChangeRelayTimeout(GuiScreen parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
StringTranslate ts = StringTranslate.getInstance();
|
||||
title = ts.translateKey("networkSettings.relayTimeoutTitle");
|
||||
buttonList.clear();
|
||||
buttonList.add(new GuiButton(0, width / 2 - 100, height / 3 + 55, ts.translateKey("gui.done")));
|
||||
buttonList.add(new GuiButton(1, width / 2 - 100, height / 3 + 85, ts.translateKey("gui.cancel")));
|
||||
slider = new GuiSlider2(0, width / 2 - 100, height / 3 + 10, 200, 20, (mc.gameSettings.relayTimeout - 1) / 14.0f, 1.0f) {
|
||||
public boolean mousePressed(Minecraft par1Minecraft, int par2, int par3) {
|
||||
if(super.mousePressed(par1Minecraft, par2, par3)) {
|
||||
this.displayString = "" + (int)((sliderValue * 14.0f) + 1.0f) + "s";
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void mouseDragged(Minecraft par1Minecraft, int par2, int par3) {
|
||||
super.mouseDragged(par1Minecraft, par2, par3);
|
||||
this.displayString = "" + (int)((sliderValue * 14.0f) + 1.0f) + "s";
|
||||
}
|
||||
};
|
||||
slider.displayString = "" + mc.gameSettings.relayTimeout + "s";
|
||||
}
|
||||
|
||||
public void actionPerformed(GuiButton btn) {
|
||||
if(btn.id == 0) {
|
||||
mc.gameSettings.relayTimeout = (int)((slider.sliderValue * 14.0f) + 1.0f);
|
||||
mc.gameSettings.saveOptions();
|
||||
mc.displayGuiScreen(parent);
|
||||
}else if(btn.id == 1) {
|
||||
mc.displayGuiScreen(parent);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
drawDefaultBackground();
|
||||
drawCenteredString(fontRenderer, title, width / 2, height / 3 - 20, 0xFFFFFF);
|
||||
slider.drawButton(mc, par1, par2);
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
public void mouseClicked(int mx, int my, int button) {
|
||||
slider.mousePressed(mc, mx, my);
|
||||
super.mouseClicked(mx, my, button);
|
||||
}
|
||||
|
||||
public void mouseMovedOrUp(int par1, int par2, int par3) {
|
||||
if(par3 == 0) {
|
||||
slider.mouseReleased(par1, par2);
|
||||
}
|
||||
super.mouseMovedOrUp(par1, par2, par3);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiMultiplayer;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiScreenDirectConnect;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenConnectOption extends GuiScreen {
|
||||
|
||||
private final GuiMultiplayer guiScreen;
|
||||
private String title;
|
||||
private String prompt;
|
||||
|
||||
private final GuiNetworkSettingsButton relaysButton;
|
||||
|
||||
public GuiScreenConnectOption(GuiMultiplayer guiScreen) {
|
||||
this.guiScreen = guiScreen;
|
||||
this.relaysButton = new GuiNetworkSettingsButton(this);
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
title = var1.translateKey("selectServer.direct");
|
||||
prompt = var1.translateKey("directConnect.prompt");
|
||||
buttonList.clear();
|
||||
buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 - 60 + 90, var1.translateKey("directConnect.serverJoin")));
|
||||
buttonList.add(new GuiButton(2, this.width / 2 - 100, this.height / 4 - 60 + 115, var1.translateKey("directConnect.lanWorld")));
|
||||
buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 - 60 + 155, var1.translateKey("gui.cancel")));
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
mc.displayGuiScreen(guiScreen);
|
||||
}else if(par1GuiButton.id == 1) {
|
||||
mc.displayGuiScreen(new GuiScreenDirectConnect(guiScreen, guiScreen.getTheServerData()));
|
||||
}else if(par1GuiButton.id == 2) {
|
||||
GuiScreen scn = new GuiScreenLANConnect(guiScreen);
|
||||
if(IntegratedServer.relayManager.count() == 0) {
|
||||
mc.displayGuiScreen(new GuiScreenNoRelays(guiScreen, "noRelay.title"));
|
||||
}else {
|
||||
mc.displayGuiScreen(scn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(this.fontRenderer, title, this.width / 2, this.height / 4 - 60 + 20, 16777215);
|
||||
this.drawCenteredString(this.fontRenderer, prompt, this.width / 2, this.height / 4 - 60 + 55, 0x999999);
|
||||
super.drawScreen(par1, par2, par3);
|
||||
relaysButton.drawScreen(par1, par2);
|
||||
}
|
||||
|
||||
protected void mouseClicked(int par1, int par2, int par3) {
|
||||
relaysButton.mouseClicked(par1, par2, par3);
|
||||
super.mouseClicked(par1, par2, par3);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiCreateWorld;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenCreateWorldSelection extends GuiScreen {
|
||||
|
||||
private GuiScreen mainmenu;
|
||||
private GuiButton worldCreate = null;
|
||||
private GuiButton worldImport = null;
|
||||
private GuiButton worldVanilla = null;
|
||||
private boolean isImportingEPK = false;
|
||||
private boolean isImportingMCA = false;
|
||||
|
||||
public GuiScreenCreateWorldSelection(GuiScreen mainmenu) {
|
||||
this.mainmenu = mainmenu;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
this.buttonList.add(worldCreate = new GuiButton(1, this.width / 2 - 100, this.height / 4 + 40, var1.translateKey("selectWorld.create.create")));
|
||||
this.buttonList.add(worldImport = new GuiButton(2, this.width / 2 - 100, this.height / 4 + 65, var1.translateKey("selectWorld.create.import")));
|
||||
this.buttonList.add(worldVanilla = new GuiButton(3, this.width / 2 - 100, this.height / 4 + 90, var1.translateKey("selectWorld.create.vanilla")));
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 130, var1.translateKey("gui.cancel")));
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
if(EaglerAdapter.getFileChooserResultAvailable() && (isImportingEPK || isImportingMCA)) {
|
||||
this.mc.displayGuiScreen(new GuiScreenNameWorldImport(mainmenu, EaglerAdapter.getFileChooserResultName(), isImportingEPK ? 0 : (isImportingMCA ? 1 : -1)));
|
||||
isImportingEPK = isImportingMCA = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
this.drawDefaultBackground();
|
||||
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.create.title"), this.width / 2, this.height / 4, 16777215);
|
||||
|
||||
int toolTipColor = 0xDDDDAA;
|
||||
if(worldCreate.func_82252_a()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.create.create.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor);
|
||||
}else if(worldImport.func_82252_a()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.create.import.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor);
|
||||
}else if(worldVanilla.func_82252_a()) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.create.vanilla.tooltip"), this.width / 2, this.height / 4 + 20, toolTipColor);
|
||||
}
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
this.mc.displayGuiScreen(mainmenu);
|
||||
}else if(par1GuiButton.id == 1) {
|
||||
this.mc.displayGuiScreen(new GuiCreateWorld(mainmenu));
|
||||
}else if(par1GuiButton.id == 2) {
|
||||
isImportingEPK = true;
|
||||
EaglerAdapter.openFileChooser("epk", null);
|
||||
}else if(par1GuiButton.id == 3) {
|
||||
isImportingMCA = true;
|
||||
EaglerAdapter.openFileChooser("zip", null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
308
src/main/java/net/lax1dude/eaglercraft/GuiScreenEditCape.java
Normal file
308
src/main/java/net/lax1dude/eaglercraft/GuiScreenEditCape.java
Normal file
@@ -0,0 +1,308 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.EaglerProfile.EaglerProfileCape;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenEditCape extends GuiScreen {
|
||||
|
||||
private boolean dropDownOpen = false;
|
||||
private String[] dropDownOptions;
|
||||
private int slotsVisible = 0;
|
||||
private int selectedSlot = 0;
|
||||
private int scrollPos = -1;
|
||||
private int skinsHeight = 0;
|
||||
private boolean dragging = false;
|
||||
private int mousex = 0;
|
||||
private int mousey = 0;
|
||||
|
||||
public static final String[] defaultVanillaCapeNames = new String[] {
|
||||
"No Cape",
|
||||
"Minecon 2011",
|
||||
"Minecon 2012",
|
||||
"Minecon 2013",
|
||||
"Minecon 2015",
|
||||
"Minecon 2016",
|
||||
"Microsoft Account",
|
||||
"Realms Mapmaker",
|
||||
"Mojang Old",
|
||||
"Mojang New",
|
||||
"Jira Moderator",
|
||||
"Mojang Very Old",
|
||||
"Scrolls",
|
||||
"Cobalt",
|
||||
"Lang Translator",
|
||||
"Millionth Player",
|
||||
"Prismarine",
|
||||
"Snowman",
|
||||
"Spade",
|
||||
"Birthday",
|
||||
"dB"
|
||||
};
|
||||
|
||||
protected String screenTitle = "Select Cape";
|
||||
|
||||
private GuiScreen parent;
|
||||
private int skinToShow;
|
||||
|
||||
public GuiScreenEditCape(GuiScreen parent, int skinToShow) {
|
||||
this.parent = parent;
|
||||
this.skinToShow = skinToShow;
|
||||
reconcatDD();
|
||||
this.selectedSlot = EaglerProfile.presetCapeId < 0 ? EaglerProfile.customCapeId : (EaglerProfile.presetCapeId + EaglerProfile.capes.size());
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
EaglerAdapter.enableRepeatEvents(true);
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
screenTitle = var1.translateKey("profile.capeTitle");
|
||||
this.buttonList.add(new GuiButton(200, this.width / 2 - 100, this.height / 6 + 168, var1.translateKey("gui.done")));
|
||||
this.buttonList.add(new GuiButton(2, this.width / 2 - 21, this.height / 6 + 81, 71, 20, var1.translateKey("profile.addCape")));
|
||||
this.buttonList.add(new GuiButton(3, this.width / 2 - 21 + 71, this.height / 6 + 81, 72, 20, var1.translateKey("profile.clearSkin")));
|
||||
}
|
||||
|
||||
public void onGuiClosed() {
|
||||
EaglerAdapter.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
private void reconcatDD() {
|
||||
String[] n = new String[EaglerProfile.capes.size()];
|
||||
for(int i = 0; i < n.length; ++i) {
|
||||
n[i] = EaglerProfile.capes.get(i).name;
|
||||
}
|
||||
|
||||
this.dropDownOptions = EaglerProfile.concatArrays(n, defaultVanillaCapeNames);
|
||||
}
|
||||
|
||||
private static final TextureLocation gui = new TextureLocation("/gui/gui.png");
|
||||
|
||||
public void drawScreen(int mx, int my, float par3) {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
this.drawDefaultBackground();
|
||||
|
||||
this.drawCenteredString(this.fontRenderer, this.screenTitle, this.width / 2, 15, 16777215);
|
||||
|
||||
this.drawString(this.fontRenderer, "Player Cape", this.width / 2 - 20, this.height / 6 + 37, 10526880);
|
||||
mousex = mx;
|
||||
mousey = my;
|
||||
|
||||
int skinX = this.width / 2 - 120;
|
||||
int skinY = this.height / 6 + 8;
|
||||
int skinWidth = 80;
|
||||
int skinHeight = 130;
|
||||
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336);
|
||||
drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, 0xff000015);
|
||||
|
||||
if(dropDownOpen) {
|
||||
super.drawScreen(-1, -1, par3);
|
||||
}else {
|
||||
super.drawScreen(mx, my, par3);
|
||||
}
|
||||
|
||||
skinX = this.width / 2 - 20;
|
||||
skinY = this.height / 6 + 53;
|
||||
skinWidth = 140;
|
||||
skinHeight = 22;
|
||||
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336);
|
||||
drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 21, skinY + skinHeight - 1, -16777216);
|
||||
drawRect(skinX + skinWidth - 20, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216);
|
||||
|
||||
EaglerAdapter.glColor4f(1f, 1f, 1f, 1f);
|
||||
gui.bindTexture();
|
||||
drawTexturedModalRect(skinX + skinWidth - 18, skinY + 3, 0, 240, 16, 16);
|
||||
|
||||
this.fontRenderer.drawStringWithShadow(dropDownOptions[selectedSlot], skinX + 5, skinY + 7, 14737632);
|
||||
|
||||
EaglerProfile.customCapeId = (selectedSlot < EaglerProfile.capes.size()) ? selectedSlot : -1;
|
||||
EaglerProfile.presetCapeId = EaglerProfile.customCapeId < 0 ? (selectedSlot - EaglerProfile.capes.size()) : -1;
|
||||
|
||||
skinX = this.width / 2 - 20;
|
||||
skinY = this.height / 6 + 74;
|
||||
skinWidth = 140;
|
||||
skinHeight = (this.height - skinY - 4);
|
||||
slotsVisible = (skinHeight / 10);
|
||||
if(slotsVisible > dropDownOptions.length) slotsVisible = dropDownOptions.length;
|
||||
skinHeight = slotsVisible * 10 + 7;
|
||||
skinsHeight = skinHeight;
|
||||
if(scrollPos == -1) {
|
||||
scrollPos = selectedSlot - 2;
|
||||
}
|
||||
if(scrollPos > (dropDownOptions.length - slotsVisible)) {
|
||||
scrollPos = (dropDownOptions.length - slotsVisible);
|
||||
}
|
||||
if(scrollPos < 0) {
|
||||
scrollPos = 0;
|
||||
}
|
||||
if(dropDownOpen) {
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336);
|
||||
drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216);
|
||||
for(int i = 0; i < slotsVisible; i++) {
|
||||
if(i + scrollPos < dropDownOptions.length) {
|
||||
int idx = i + scrollPos - EaglerProfile.capes.size();
|
||||
if(selectedSlot == i + scrollPos) {
|
||||
drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x77ffffff);
|
||||
}else if(mx >= skinX && mx < (skinX + skinWidth - 10) && my >= (skinY + i*10 + 5) && my < (skinY + i*10 + 15)) {
|
||||
drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x55ffffff);
|
||||
}
|
||||
this.fontRenderer.drawStringWithShadow(dropDownOptions[i + scrollPos], skinX + 5, skinY + 5 + i*10, 14737632);
|
||||
}
|
||||
}
|
||||
int scrollerSize = skinHeight * slotsVisible / dropDownOptions.length;
|
||||
int scrollerPos = skinHeight * scrollPos / dropDownOptions.length;
|
||||
drawRect(skinX + skinWidth - 4, skinY + scrollerPos + 1, skinX + skinWidth - 1, skinY + scrollerPos + scrollerSize, 0xff888888);
|
||||
}
|
||||
|
||||
int xx = this.width / 2 - 80;
|
||||
int yy = this.height / 6 + 130;
|
||||
|
||||
DefaultSkinRenderer.renderPlayerPreview(xx, yy, mx, my, skinToShow | 0x10000);
|
||||
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(!dropDownOpen) {
|
||||
if(par1GuiButton.id == 200) {
|
||||
mc.displayGuiScreen(parent);
|
||||
}else if(par1GuiButton.id == 2) {
|
||||
EaglerAdapter.openFileChooser("png", "image/png");
|
||||
}else if(par1GuiButton.id == 3) {
|
||||
for(EaglerProfileCape i : EaglerProfile.capes) {
|
||||
this.mc.renderEngine.deleteTexture(i.glTex);
|
||||
}
|
||||
EaglerProfile.capes.clear();
|
||||
this.dropDownOptions = defaultVanillaCapeNames;
|
||||
this.selectedSlot = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
if(dropDownOpen) {
|
||||
if(EaglerAdapter.mouseIsButtonDown(0)) {
|
||||
int skinX = this.width / 2 - 20;
|
||||
int skinY = this.height / 6 + 74;
|
||||
int skinWidth = 140;
|
||||
if(mousex >= (skinX + skinWidth - 10) && mousex < (skinX + skinWidth) && mousey >= skinY && mousey < (skinY + skinsHeight)) {
|
||||
dragging = true;
|
||||
}
|
||||
if(dragging) {
|
||||
int scrollerSize = skinsHeight * slotsVisible / dropDownOptions.length;
|
||||
scrollPos = (mousey - skinY - (scrollerSize / 2)) * dropDownOptions.length / skinsHeight;
|
||||
}
|
||||
}else {
|
||||
dragging = false;
|
||||
}
|
||||
}else {
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
byte[] b;
|
||||
if((b = EaglerAdapter.getFileChooserResult()) != null && b.length > 0) {
|
||||
EaglerImage img = EaglerImage.loadImage(b);
|
||||
|
||||
if(!((img.w == 32 && img.h == 32) || (img.w == 64 && img.h == 32))) return;
|
||||
|
||||
int[] loadSkin = img.data;
|
||||
if(img.w == 64 && img.h == 32) {
|
||||
loadSkin = grabPiece(loadSkin, 32, 32, 64);
|
||||
}
|
||||
|
||||
byte[] rawSkin = new byte[loadSkin.length * 4];
|
||||
for(int i = 0; i < loadSkin.length; i++) {
|
||||
int i2 = i * 4; int i3 = loadSkin[i];
|
||||
rawSkin[i2] = (byte)(i3);
|
||||
rawSkin[i2 + 1] = (byte)(i3 >> 8);
|
||||
rawSkin[i2 + 2] = (byte)(i3 >> 16);
|
||||
rawSkin[i2 + 3] = (byte)(i3 >> 24);
|
||||
}
|
||||
String name = EaglerAdapter.getFileChooserResultName();
|
||||
if(name.length() > 32) {
|
||||
name = name.substring(0, 32);
|
||||
}
|
||||
int k;
|
||||
if((k = EaglerProfile.addCape(name, rawSkin)) != -1) {
|
||||
selectedSlot = k;
|
||||
reconcatDD();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int[] grabPiece(int[] input, int w, int h, int sw) {
|
||||
int[] ret = new int[w * h];
|
||||
for(int i = 0; i < h; ++i) {
|
||||
System.arraycopy(input, i * sw, ret, i * w, w);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void handleMouseInput() {
|
||||
super.handleMouseInput();
|
||||
if(dropDownOpen) {
|
||||
int var1 = EaglerAdapter.mouseGetEventDWheel();
|
||||
if(var1 < 0) {
|
||||
scrollPos += 3;
|
||||
}
|
||||
if(var1 > 0) {
|
||||
scrollPos -= 3;
|
||||
if(scrollPos < 0) {
|
||||
scrollPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void keyTyped(char par1, int par2) {
|
||||
if(par2 == 200 && selectedSlot > 0) {
|
||||
--selectedSlot;
|
||||
scrollPos = selectedSlot - 2;
|
||||
}
|
||||
if(par2 == 208 && selectedSlot < (dropDownOptions.length - 1)) {
|
||||
++selectedSlot;
|
||||
scrollPos = selectedSlot - 2;
|
||||
}
|
||||
}
|
||||
|
||||
protected void mouseClicked(int par1, int par2, int par3) {
|
||||
super.mouseClicked(par1, par2, par3);
|
||||
|
||||
if (par3 == 0) {
|
||||
int skinX = this.width / 2 + 140 - 40;
|
||||
int skinY = this.height / 6 + 53;
|
||||
|
||||
if(par1 >= skinX && par1 < (skinX + 20) && par2 >= skinY && par2 < (skinY + 22)) {
|
||||
dropDownOpen = !dropDownOpen;
|
||||
}
|
||||
|
||||
skinX = this.width / 2 - 20;
|
||||
skinY = this.height / 6 + 53;
|
||||
int skinWidth = 140;
|
||||
int skinHeight = skinsHeight;
|
||||
|
||||
if(!(par1 >= skinX && par1 < (skinX + skinWidth) && par2 >= skinY && par2 < (skinY + skinHeight + 22))) {
|
||||
dropDownOpen = false;
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
skinY += 21;
|
||||
|
||||
if(dropDownOpen && !dragging) {
|
||||
for(int i = 0; i < slotsVisible; i++) {
|
||||
if(i + scrollPos < dropDownOptions.length) {
|
||||
if(selectedSlot != i + scrollPos) {
|
||||
if(par1 >= skinX && par1 < (skinX + skinWidth - 10) && par2 >= (skinY + i*10 + 5) && par2 < (skinY + i*10 + 15) && selectedSlot != i + scrollPos) {
|
||||
selectedSlot = i + scrollPos;
|
||||
dropDownOpen = false;
|
||||
dragging = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
547
src/main/java/net/lax1dude/eaglercraft/GuiScreenEditProfile.java
Normal file
547
src/main/java/net/lax1dude/eaglercraft/GuiScreenEditProfile.java
Normal file
@@ -0,0 +1,547 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.EaglerProfile.EaglerProfileSkin;
|
||||
import net.minecraft.src.EnumChatFormatting;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiTextField;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenEditProfile extends GuiScreen {
|
||||
|
||||
private GuiScreen parent;
|
||||
private GuiTextField username;
|
||||
|
||||
private boolean dropDownOpen = false;
|
||||
private String[] dropDownOptions;
|
||||
private int slotsVisible = 0;
|
||||
private int selectedSlot = 0;
|
||||
private int newSkinNotificationIndexCurrent = 0;
|
||||
private int scrollPos = -1;
|
||||
private int skinsHeight = 0;
|
||||
private boolean dragging = false;
|
||||
private int mousex = 0;
|
||||
private int mousey = 0;
|
||||
|
||||
private boolean newSkinWaitSteveOrAlex = false;
|
||||
|
||||
private static final TextureLocation gui = new TextureLocation("/gui/gui.png");
|
||||
|
||||
public static final String[] defaultOptions = new String[] {
|
||||
"Default Steve",
|
||||
"Default Alex",
|
||||
"Tennis Steve",
|
||||
"Tennis Alex",
|
||||
"Tuxedo Steve",
|
||||
"Tuxedo Alex",
|
||||
"Athlete Steve",
|
||||
"Athlete Alex",
|
||||
"Cyclist Steve",
|
||||
"Cyclist Alex",
|
||||
"Boxer Steve",
|
||||
"Boxer Alex",
|
||||
"Prisoner Steve",
|
||||
"Prisoner Alex",
|
||||
"Scottish Steve",
|
||||
"Scottish Alex",
|
||||
"Developer Steve",
|
||||
"Developer Alex",
|
||||
"Herobrine",
|
||||
"Enderman",
|
||||
"Skeleton",
|
||||
"Blaze",
|
||||
"Barney",
|
||||
"Slime",
|
||||
"Noob",
|
||||
"Trump",
|
||||
"Notch",
|
||||
"Creeper",
|
||||
"Zombie",
|
||||
"Pig",
|
||||
"Squid",
|
||||
"Mooshroom",
|
||||
"Villager",
|
||||
"Long Arms",
|
||||
"Weird Climber",
|
||||
"Laxative Dude",
|
||||
"Baby Charles",
|
||||
"Baby Winston"
|
||||
};
|
||||
|
||||
public static final int newDefaultNotice = defaultOptions.length - 5;
|
||||
|
||||
protected String screenTitle = "Edit Profile";
|
||||
|
||||
public GuiScreenEditProfile(GuiScreen parent) {
|
||||
this.parent = parent;
|
||||
newSkinNotificationIndexCurrent = EaglerProfile.newSkinNotificationIndex;
|
||||
reconcatDD();
|
||||
}
|
||||
|
||||
private void reconcatDD() {
|
||||
String[] n = new String[EaglerProfile.skins.size()];
|
||||
for(int i = 0; i < n.length; ++i) {
|
||||
n[i] = EaglerProfile.skins.get(i).name;
|
||||
}
|
||||
|
||||
this.dropDownOptions = EaglerProfile.concatArrays(n, defaultOptions);
|
||||
}
|
||||
|
||||
private GuiButton button0, button1, button2, button10, button11, button12;
|
||||
|
||||
public void initGui() {
|
||||
super.initGui();
|
||||
EaglerAdapter.enableRepeatEvents(true);
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
this.screenTitle = var1.translateKey("profile.title");
|
||||
this.username = new GuiTextField(this.fontRenderer, this.width / 2 - 20 + 1, this.height / 6 + 24 + 1, 138, 20);
|
||||
this.username.setFocused(true);
|
||||
this.username.setText(EaglerProfile.username);
|
||||
selectedSlot = EaglerProfile.presetSkinId == -1 ? EaglerProfile.customSkinId : (EaglerProfile.presetSkinId + EaglerProfile.skins.size());
|
||||
//this.buttonList.add(new GuiButton(0, this.width / 2 - 100, 140, "eeeee"));
|
||||
this.buttonList.add(button0 = new GuiButton(200, this.width / 2 - 100, this.height / 6 + 168, var1.translateKey("gui.done")));
|
||||
this.buttonList.add(button1 = new GuiButton(2, this.width / 2 - 21, this.height / 6 + 110, 71, 20, var1.translateKey("profile.addSkin")));
|
||||
this.buttonList.add(button2 = new GuiButton(3, this.width / 2 - 21 + 71, this.height / 6 + 110, 72, 20, var1.translateKey("profile.clearSkin")));
|
||||
//this.buttonList.add(new GuiButton(200, this.width / 2, this.height / 6 + 72, 150, 20, var1.translateKey("gui.done")));
|
||||
}
|
||||
|
||||
public void drawScreen(int mx, int my, float par3) {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(this.fontRenderer, this.screenTitle, this.width / 2, 15, 16777215);
|
||||
this.drawString(this.fontRenderer, var1.translateKey("profile.screenname"), this.width / 2 - 20, this.height / 6 + 8, 10526880);
|
||||
|
||||
newSkinNotificationIndexCurrent = 23948923;
|
||||
int cnt = defaultOptions.length - newSkinNotificationIndexCurrent;
|
||||
if(cnt <= 0) {
|
||||
this.drawString(this.fontRenderer, var1.translateKey("profile.playerSkin"), this.width / 2 - 20, this.height / 6 + 66, 10526880);
|
||||
}
|
||||
mousex = mx;
|
||||
mousey = my;
|
||||
|
||||
int skinX = this.width / 2 - 120;
|
||||
int skinY = this.height / 6 + 8;
|
||||
int skinWidth = 80;
|
||||
int skinHeight = 130;
|
||||
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336);
|
||||
drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, 0xff000015);
|
||||
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glTranslatef(skinX + 2, skinY - 9, 0.0f);
|
||||
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
|
||||
|
||||
int skid = selectedSlot - EaglerProfile.skins.size();
|
||||
if(skid < 0) {
|
||||
skid = 0;
|
||||
}
|
||||
if(DefaultSkinRenderer.isStandardModel(skid) || DefaultSkinRenderer.isZombieModel(skid)) {
|
||||
String capesText = var1.translateKey("profile.capes");
|
||||
int color = 10526880;
|
||||
if(mx > skinX - 10 && my > skinY - 16 && mx < skinX + (fontRenderer.getStringWidth(capesText) / 0.75f) + 10 && my < skinY + 7) {
|
||||
color = 0xFFCCCC44;
|
||||
}
|
||||
this.drawString(this.fontRenderer, EnumChatFormatting.UNDERLINE + capesText, 0, 0, color);
|
||||
}
|
||||
|
||||
EaglerAdapter.glPopMatrix();
|
||||
|
||||
this.username.drawTextBox();
|
||||
if(dropDownOpen || newSkinWaitSteveOrAlex) {
|
||||
super.drawScreen(0, 0, par3);
|
||||
}else {
|
||||
super.drawScreen(mx, my, par3);
|
||||
}
|
||||
|
||||
skinX = this.width / 2 - 20;
|
||||
skinY = this.height / 6 + 82;
|
||||
skinWidth = 140;
|
||||
skinHeight = 22;
|
||||
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336);
|
||||
drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 21, skinY + skinHeight - 1, -16777216);
|
||||
drawRect(skinX + skinWidth - 20, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216);
|
||||
|
||||
EaglerAdapter.glColor4f(1f, 1f, 1f, 1f);
|
||||
gui.bindTexture();
|
||||
drawTexturedModalRect(skinX + skinWidth - 18, skinY + 3, 0, 240, 16, 16);
|
||||
|
||||
this.fontRenderer.drawStringWithShadow(dropDownOptions[selectedSlot], skinX + 5, skinY + 7, 14737632);
|
||||
|
||||
if(cnt > 0) {
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glTranslatef(skinX, skinY - 11, 0.0f);
|
||||
EaglerAdapter.glScalef(0.9f, 0.9f, 0.9f);
|
||||
drawString(fontRenderer, "" + cnt + " new skin" + (cnt != 1 ? "" : "s") + " have been added:", 0, 0, 0xFFDDDDAA);
|
||||
EaglerAdapter.glPopMatrix();
|
||||
}
|
||||
|
||||
skinX = this.width / 2 - 20;
|
||||
skinY = this.height / 6 + 103;
|
||||
skinWidth = 140;
|
||||
skinHeight = (this.height - skinY - 10);
|
||||
slotsVisible = (skinHeight / 10);
|
||||
if(slotsVisible > dropDownOptions.length) slotsVisible = dropDownOptions.length;
|
||||
skinHeight = slotsVisible * 10 + 7;
|
||||
skinsHeight = skinHeight;
|
||||
if(scrollPos == -1) {
|
||||
scrollPos = selectedSlot - 2;
|
||||
}
|
||||
if(scrollPos > (dropDownOptions.length - slotsVisible)) {
|
||||
scrollPos = (dropDownOptions.length - slotsVisible);
|
||||
}
|
||||
if(scrollPos < 0) {
|
||||
scrollPos = 0;
|
||||
}
|
||||
if(dropDownOpen) {
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, -6250336);
|
||||
drawRect(skinX + 1, skinY + 1, skinX + skinWidth - 1, skinY + skinHeight - 1, -16777216);
|
||||
for(int i = 0; i < slotsVisible; i++) {
|
||||
if(i + scrollPos < dropDownOptions.length) {
|
||||
int idx = i + scrollPos - EaglerProfile.skins.size();
|
||||
if(idx >= newSkinNotificationIndexCurrent) {
|
||||
drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x77ffdd88);
|
||||
}
|
||||
if(selectedSlot == i + scrollPos) {
|
||||
drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x77ffffff);
|
||||
}else if(mx >= skinX && mx < (skinX + skinWidth - 10) && my >= (skinY + i*10 + 5) && my < (skinY + i*10 + 15)) {
|
||||
drawRect(skinX + 1, skinY + i*10 + 4, skinX + skinWidth - 1, skinY + i*10 + 14, 0x55ffffff);
|
||||
}
|
||||
this.fontRenderer.drawStringWithShadow(dropDownOptions[i + scrollPos], skinX + 5, skinY + 5 + i*10, 14737632);
|
||||
if(EaglerProfile.newSkinNotificationIndex <= idx) {
|
||||
EaglerProfile.newSkinNotificationIndex = idx + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
int scrollerSize = skinHeight * slotsVisible / dropDownOptions.length;
|
||||
int scrollerPos = skinHeight * scrollPos / dropDownOptions.length;
|
||||
drawRect(skinX + skinWidth - 4, skinY + scrollerPos + 1, skinX + skinWidth - 1, skinY + scrollerPos + scrollerSize, 0xff888888);
|
||||
}
|
||||
|
||||
int xx = this.width / 2 - 80;
|
||||
int yy = this.height / 6 + 130;
|
||||
|
||||
if(newSkinWaitSteveOrAlex && selectedSlot < EaglerProfile.skins.size()) {
|
||||
skinWidth = 70;
|
||||
skinHeight = 120;
|
||||
|
||||
EaglerProfile.EaglerProfileSkin eee = EaglerProfile.skins.get(selectedSlot);
|
||||
|
||||
EaglerAdapter.glClear(EaglerAdapter.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
skinX = this.width / 2 - 90;
|
||||
skinY = this.height / 4;
|
||||
xx = skinX + 35;
|
||||
yy = skinY + 117;
|
||||
|
||||
boolean mouseOver = mx >= skinX && my >= skinY && mx < skinX + skinWidth && my < skinY + skinHeight;
|
||||
int cc = mouseOver ? 0xFFDDDD99 : 0xFF555555;
|
||||
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
|
||||
EaglerAdapter.glBlendFunc(EaglerAdapter.GL_SRC_ALPHA, EaglerAdapter.GL_ONE_MINUS_SRC_ALPHA);
|
||||
drawRect(0, 0, width, height, 0xbb000000);
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, 0xbb000000);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
|
||||
|
||||
drawRect(skinX, skinY, skinX + 1, skinY + skinHeight, cc);
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + 1, cc);
|
||||
drawRect(skinX + skinWidth - 1, skinY, skinX + skinWidth, skinY + skinHeight, cc);
|
||||
drawRect(skinX, skinY + skinHeight - 1, skinX + skinWidth, skinY + skinHeight, cc);
|
||||
|
||||
if(mouseOver) {
|
||||
drawCenteredString(fontRenderer, "Steve", skinX + skinWidth / 2, skinY + skinHeight + 6, cc);
|
||||
}
|
||||
|
||||
this.mc.renderEngine.bindTexture(eee.glTex);
|
||||
DefaultSkinRenderer.renderAlexOrSteve(xx, yy, mx, my, false);
|
||||
|
||||
skinX = this.width / 2 + 20;
|
||||
skinY = this.height / 4;
|
||||
xx = skinX + 35;
|
||||
yy = skinY + 117;
|
||||
|
||||
mouseOver = mx >= skinX && my >= skinY && mx < skinX + skinWidth && my < skinY + skinHeight;
|
||||
cc = mouseOver ? 0xFFDDDD99 : 0xFF555555;
|
||||
|
||||
EaglerAdapter.glEnable(EaglerAdapter.GL_BLEND);
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + skinHeight, 0xbb000000);
|
||||
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
|
||||
|
||||
drawRect(skinX, skinY, skinX + 1, skinY + skinHeight, cc);
|
||||
drawRect(skinX, skinY, skinX + skinWidth, skinY + 1, cc);
|
||||
drawRect(skinX + skinWidth - 1, skinY, skinX + skinWidth, skinY + skinHeight, cc);
|
||||
drawRect(skinX, skinY + skinHeight - 1, skinX + skinWidth, skinY + skinHeight, cc);
|
||||
|
||||
if(mouseOver) {
|
||||
drawCenteredString(fontRenderer, "Alex", skinX + skinWidth / 2, skinY + skinHeight + 8, cc);
|
||||
}
|
||||
|
||||
this.mc.renderEngine.bindTexture(eee.glTex);
|
||||
DefaultSkinRenderer.renderAlexOrSteve(xx, yy, mx, my, true);
|
||||
}else {
|
||||
skinX = this.width / 2 - 120;
|
||||
skinY = this.height / 6 + 8;
|
||||
skinWidth = 80;
|
||||
skinHeight = 130;
|
||||
if(DefaultSkinRenderer.isPlayerPreviewNew(selectedSlot)) {
|
||||
int w = fontRenderer.getStringWidth("1.8") + 4;
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
|
||||
drawString(fontRenderer, "1.8", (int)((skinX + skinWidth) / 0.75f) - w, (int)((skinY + skinHeight) / 0.75f) - 12, 0xFFBBBB66);
|
||||
EaglerAdapter.glPopMatrix();
|
||||
}
|
||||
DefaultSkinRenderer.renderPlayerPreview(xx, yy, newSkinWaitSteveOrAlex ? width / 2 : mx, newSkinWaitSteveOrAlex ? height / 2 : my, selectedSlot);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void handleMouseInput() {
|
||||
super.handleMouseInput();
|
||||
if(dropDownOpen) {
|
||||
int var1 = EaglerAdapter.mouseGetEventDWheel();
|
||||
if(var1 < 0) {
|
||||
scrollPos += 3;
|
||||
}
|
||||
if(var1 > 0) {
|
||||
scrollPos -= 3;
|
||||
if(scrollPos < 0) {
|
||||
scrollPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void save() {
|
||||
EaglerProfile.username = this.username.getText().length() == 0 ? "null" : this.username.getText();
|
||||
EaglerProfile.presetSkinId = selectedSlot - EaglerProfile.skins.size();
|
||||
if(EaglerProfile.presetSkinId < 0) {
|
||||
EaglerProfile.presetSkinId = -1;
|
||||
EaglerProfile.customSkinId = selectedSlot;
|
||||
}else {
|
||||
EaglerProfile.customSkinId = -1;
|
||||
}
|
||||
|
||||
LocalStorageManager.profileSettingsStorage.setInteger("ps", EaglerProfile.presetSkinId);
|
||||
LocalStorageManager.profileSettingsStorage.setInteger("cs", EaglerProfile.customSkinId);
|
||||
LocalStorageManager.profileSettingsStorage.setInteger("pc", EaglerProfile.presetCapeId);
|
||||
LocalStorageManager.profileSettingsStorage.setInteger("cc", EaglerProfile.customCapeId);
|
||||
LocalStorageManager.profileSettingsStorage.setInteger("nsi", EaglerProfile.newSkinNotificationIndex);
|
||||
LocalStorageManager.profileSettingsStorage.setString("name", EaglerProfile.username);
|
||||
|
||||
NBTTagCompound skins = new NBTTagCompound();
|
||||
for(int i = 0, l = EaglerProfile.skins.size(); i < l; i++) {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setByteArray("data", EaglerProfile.skins.get(i).data);
|
||||
nbt.setBoolean("slim", EaglerProfile.skins.get(i).slim);
|
||||
skins.setTag(EaglerProfile.skins.get(i).name, nbt);
|
||||
}
|
||||
LocalStorageManager.profileSettingsStorage.setCompoundTag("skins", skins);
|
||||
|
||||
NBTTagCompound capes = new NBTTagCompound();
|
||||
for(int i = 0, l = EaglerProfile.capes.size(); i < l; i++) {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setByteArray("data", EaglerProfile.capes.get(i).data);
|
||||
capes.setTag(EaglerProfile.capes.get(i).name, nbt);
|
||||
}
|
||||
LocalStorageManager.profileSettingsStorage.setCompoundTag("capes", capes);
|
||||
|
||||
LocalStorageManager.saveStorageP();
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(!dropDownOpen) {
|
||||
if(par1GuiButton.id == 200) {
|
||||
save();
|
||||
this.mc.displayGuiScreen((GuiScreen) parent);
|
||||
}else if(par1GuiButton.id == 2) {
|
||||
EaglerAdapter.openFileChooser("png", "image/png");
|
||||
}else if(par1GuiButton.id == 3) {
|
||||
for(EaglerProfileSkin i : EaglerProfile.skins) {
|
||||
this.mc.renderEngine.deleteTexture(i.glTex);
|
||||
}
|
||||
EaglerProfile.skins.clear();
|
||||
this.dropDownOptions = defaultOptions;
|
||||
this.selectedSlot = 0;
|
||||
save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
this.username.updateCursorCounter();
|
||||
|
||||
if(dropDownOpen) {
|
||||
if(EaglerAdapter.mouseIsButtonDown(0)) {
|
||||
int skinX = this.width / 2 - 20;
|
||||
int skinY = this.height / 6 + 103;
|
||||
int skinWidth = 140;
|
||||
if(mousex >= (skinX + skinWidth - 10) && mousex < (skinX + skinWidth) && mousey >= skinY && mousey < (skinY + skinsHeight)) {
|
||||
dragging = true;
|
||||
}
|
||||
if(dragging) {
|
||||
int scrollerSize = skinsHeight * slotsVisible / dropDownOptions.length;
|
||||
scrollPos = (mousey - skinY - (scrollerSize / 2)) * dropDownOptions.length / skinsHeight;
|
||||
}
|
||||
}else {
|
||||
dragging = false;
|
||||
}
|
||||
}else {
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
byte[] b;
|
||||
if((b = EaglerAdapter.getFileChooserResult()) != null && b.length > 0) {
|
||||
EaglerImage img = EaglerImage.loadImage(b);
|
||||
if(!((img.w == 64 && img.h == 32) || (img.w == 64 && img.h == 64))) return;
|
||||
byte[] rawSkin = new byte[img.data.length * 4];
|
||||
for(int i = 0; i < img.data.length; i++) {
|
||||
int i2 = i * 4; int i3 = img.data[i];
|
||||
rawSkin[i2] = (byte)(i3);
|
||||
rawSkin[i2 + 1] = (byte)(i3 >> 8);
|
||||
rawSkin[i2 + 2] = (byte)(i3 >> 16);
|
||||
rawSkin[i2 + 3] = (byte)(i3 >> 24);
|
||||
}
|
||||
String name = EaglerAdapter.getFileChooserResultName();
|
||||
if(name.length() > 32) {
|
||||
name = name.substring(0, 32);
|
||||
}
|
||||
if(img.w == 64 && img.h == 64) {
|
||||
newSkinWaitSteveOrAlex = true;
|
||||
}
|
||||
int k;
|
||||
if((k = EaglerProfile.addSkin(name, rawSkin, false)) != -1) {
|
||||
selectedSlot = k;
|
||||
reconcatDD();
|
||||
save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onGuiClosed() {
|
||||
EaglerAdapter.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
|
||||
protected void keyTyped(char par1, int par2) {
|
||||
this.username.textboxKeyTyped(par1, par2);
|
||||
|
||||
String text = username.getText();
|
||||
if(text.length() > 16) text = text.substring(0, 16);
|
||||
text = text.replaceAll("[^A-Za-z0-9\\-_]", "_");
|
||||
this.username.setText(text);
|
||||
|
||||
if(par2 == 200 && selectedSlot > 0) {
|
||||
--selectedSlot;
|
||||
scrollPos = selectedSlot - 2;
|
||||
}
|
||||
if(par2 == 208 && selectedSlot < (dropDownOptions.length - 1)) {
|
||||
++selectedSlot;
|
||||
scrollPos = selectedSlot - 2;
|
||||
}
|
||||
}
|
||||
|
||||
protected void mouseClicked(int par1, int par2, int par3) {
|
||||
if(newSkinWaitSteveOrAlex) {
|
||||
int skinX = this.width / 2 - 90;
|
||||
int skinY = this.height / 4;
|
||||
int skinWidth = 70;
|
||||
int skinHeight = 120;
|
||||
if(par1 >= skinX && par2 >= skinY && par1 < skinX + skinWidth && par2 < skinY + skinHeight) {
|
||||
if(selectedSlot < EaglerProfile.skins.size()) {
|
||||
newSkinWaitSteveOrAlex = false;
|
||||
EaglerProfile.skins.get(selectedSlot).slim = false;
|
||||
save();
|
||||
}
|
||||
return;
|
||||
}
|
||||
skinX = this.width / 2 + 20;
|
||||
skinY = this.height / 4;
|
||||
if(par1 >= skinX && par2 >= skinY && par1 < skinX + skinWidth && par2 < skinY + skinHeight) {
|
||||
if(selectedSlot < EaglerProfile.skins.size()) {
|
||||
EaglerProfile.skins.get(selectedSlot).slim = true;
|
||||
newSkinWaitSteveOrAlex = false;
|
||||
save();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}else if(selectedSlot < EaglerProfile.skins.size()) {
|
||||
int skinX = this.width / 2 - 120;
|
||||
int skinY = this.height / 6 + 18;
|
||||
int skinWidth = 80;
|
||||
int skinHeight = 120;
|
||||
if(par1 >= skinX && par2 >= skinY && par1 < skinX + skinWidth && par2 < skinY + skinHeight) {
|
||||
if(selectedSlot < EaglerProfile.skins.size()) {
|
||||
int type = EaglerProfile.getSkinSize(EaglerProfile.skins.get(selectedSlot).data.length);
|
||||
if(type == 1 || type == 3) {
|
||||
newSkinWaitSteveOrAlex = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.mouseClicked(par1, par2, par3);
|
||||
this.username.mouseClicked(par1, par2, par3);
|
||||
if (par3 == 0) {
|
||||
int skinX = this.width / 2 + 140 - 40;
|
||||
int skinY = this.height / 6 + 82;
|
||||
|
||||
if(par1 >= skinX && par1 < (skinX + 20) && par2 >= skinY && par2 < (skinY + 22)) {
|
||||
dropDownOpen = !dropDownOpen;
|
||||
if(!dropDownOpen) {
|
||||
//newSkinNotificationIndexCurrent = EaglerProfile.newSkinNotificationIndex;
|
||||
}
|
||||
}
|
||||
|
||||
skinX = this.width / 2 - 20;
|
||||
skinY = this.height / 6 + 82;
|
||||
int skinWidth = 140;
|
||||
int skinHeight = skinsHeight;
|
||||
|
||||
if(!(par1 >= skinX && par1 < (skinX + skinWidth) && par2 >= skinY && par2 < (skinY + skinHeight + 22))) {
|
||||
dropDownOpen = false;
|
||||
dragging = false;
|
||||
if(!dropDownOpen) {
|
||||
//newSkinNotificationIndexCurrent = EaglerProfile.newSkinNotificationIndex;
|
||||
}
|
||||
}
|
||||
|
||||
skinY += 21;
|
||||
|
||||
if(dropDownOpen && !dragging) {
|
||||
for(int i = 0; i < slotsVisible; i++) {
|
||||
if(i + scrollPos < dropDownOptions.length) {
|
||||
if(selectedSlot != i + scrollPos) {
|
||||
if(par1 >= skinX && par1 < (skinX + skinWidth - 10) && par2 >= (skinY + i*10 + 5) && par2 < (skinY + i*10 + 15) && selectedSlot != i + scrollPos) {
|
||||
selectedSlot = i + scrollPos;
|
||||
dropDownOpen = false;
|
||||
dragging = false;
|
||||
if(!dropDownOpen) {
|
||||
//newSkinNotificationIndexCurrent = EaglerProfile.newSkinNotificationIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int skid = selectedSlot - EaglerProfile.skins.size();
|
||||
if(skid < 0) {
|
||||
skid = 0;
|
||||
}
|
||||
if(DefaultSkinRenderer.isStandardModel(skid) || DefaultSkinRenderer.isZombieModel(skid)) {
|
||||
skinX = this.width / 2 - 120;
|
||||
skinY = this.height / 6 + 8;
|
||||
String capesText = StringTranslate.getInstance().translateKey("profile.capes");
|
||||
if(par1 > skinX - 10 && par2 > skinY - 16 && par1 < skinX + (fontRenderer.getStringWidth(capesText) / 0.75f) + 10 && par2 < skinY + 7) {
|
||||
save();
|
||||
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
|
||||
this.mc.displayGuiScreen(new GuiScreenEditCape(this, selectedSlot));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiTextField;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenLANConnect extends GuiScreen {
|
||||
|
||||
private final GuiScreen parent;
|
||||
private GuiTextField codeTextField;
|
||||
private final GuiNetworkSettingsButton relaysButton;
|
||||
|
||||
private static String lastCode = "";
|
||||
|
||||
public GuiScreenLANConnect(GuiScreen parent) {
|
||||
this.parent = parent;
|
||||
this.relaysButton = new GuiNetworkSettingsButton(this);
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
EaglerAdapter.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12, var1.translateKey("directConnect.lanWorldJoin")));
|
||||
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, var1.translateKey("gui.cancel")));
|
||||
this.codeTextField = new GuiTextField(this.fontRenderer, this.width / 2 - 100, this.height / 4 + 27, 200, 20);
|
||||
this.codeTextField.setMaxStringLength(48);
|
||||
this.codeTextField.setFocused(true);
|
||||
this.codeTextField.setText(lastCode);
|
||||
((GuiButton) this.buttonList.get(0)).enabled = this.codeTextField.getText().trim().length() > 0;
|
||||
}
|
||||
|
||||
public void onGuiClosed() {
|
||||
EaglerAdapter.enableRepeatEvents(false);
|
||||
lastCode = this.codeTextField.getText().trim();
|
||||
}
|
||||
|
||||
protected void keyTyped(char par1, int par2) {
|
||||
if (this.codeTextField.textboxKeyTyped(par1, par2)) {
|
||||
((GuiButton) this.buttonList.get(0)).enabled = this.codeTextField.getText().trim().length() > 0;
|
||||
} else if (par2 == 28) {
|
||||
this.actionPerformed((GuiButton) this.buttonList.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
this.codeTextField.updateCursorCounter();
|
||||
}
|
||||
|
||||
protected void mouseClicked(int par1, int par2, int par3) {
|
||||
super.mouseClicked(par1, par2, par3);
|
||||
this.codeTextField.mouseClicked(par1, par2, par3);
|
||||
this.relaysButton.mouseClicked(par1, par2, par3);
|
||||
}
|
||||
|
||||
public void drawScreen(int xx, int yy, float pt) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectServer.direct"), this.width / 2, this.height / 4 - 60 + 20, 16777215);
|
||||
this.drawString(this.fontRenderer, var4.translateKey("directConnect.lanWorldCode"), this.width / 2 - 100, this.height / 4 + 12, 10526880);
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("directConnect.networkSettingsNote"), this.width / 2, this.height / 4 + 63, 10526880);
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("directConnect.ipGrabNote"), this.width / 2, this.height / 4 + 77, 10526880);
|
||||
this.codeTextField.drawTextBox();
|
||||
super.drawScreen(xx, yy, pt);
|
||||
this.relaysButton.drawScreen(xx, yy);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 1) {
|
||||
mc.displayGuiScreen(parent);
|
||||
}else if(par1GuiButton.id == 0) {
|
||||
mc.displayGuiScreen(new GuiScreenLANConnecting(parent, this.codeTextField.getText().trim()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.src.GuiDisconnected;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.LoadingScreenRenderer;
|
||||
import net.minecraft.src.NetClientHandler;
|
||||
import net.minecraft.src.Packet250CustomPayload;
|
||||
import net.minecraft.src.Packet2ClientProtocol;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenLANConnecting extends GuiScreen {
|
||||
|
||||
private final GuiScreen parent;
|
||||
private final String code;
|
||||
private final RelayServer relay;
|
||||
|
||||
private boolean completed = false;
|
||||
|
||||
private NetClientHandler netHandler = null;
|
||||
|
||||
private int renderCount = 0;
|
||||
|
||||
public GuiScreenLANConnecting(GuiScreen parent, String code) {
|
||||
this.parent = parent;
|
||||
this.code = code;
|
||||
this.relay = null;
|
||||
}
|
||||
|
||||
public GuiScreenLANConnecting(GuiScreen parent, String code, RelayServer relay) {
|
||||
this.parent = parent;
|
||||
this.code = code;
|
||||
this.relay = relay;
|
||||
}
|
||||
|
||||
public boolean doesGuiPauseGame() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
if(netHandler != null) {
|
||||
netHandler.processReadPackets();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
StringTranslate st = StringTranslate.getInstance();
|
||||
if(completed) {
|
||||
String message = st.translateKey("connect.authorizing");
|
||||
this.drawString(fontRenderer, message, (this.width - this.fontRenderer.getStringWidth(message)) / 2, this.height / 3 + 10, 0xFFFFFF);
|
||||
}else {
|
||||
LoadingScreenRenderer ls = mc.loadingScreen;
|
||||
|
||||
String message = st.translateKey("lanServer.pleaseWait");
|
||||
this.drawString(fontRenderer, message, (this.width - this.fontRenderer.getStringWidth(message)) / 2, this.height / 3 + 10, 0xFFFFFF);
|
||||
|
||||
if(++renderCount > 1) {
|
||||
RelayServerSocket sock;
|
||||
if(relay == null) {
|
||||
sock = IntegratedServer.relayManager.getWorkingRelay((str) -> ls.resetProgresAndWorkingMessage("Connecting: " + str), 0x02, code);
|
||||
}else {
|
||||
sock = IntegratedServer.relayManager.connectHandshake(relay, 0x02, code);
|
||||
}
|
||||
if(sock == null) {
|
||||
this.mc.displayGuiScreen(new GuiScreenNoRelays(parent, st.translateKey("noRelay.worldNotFound1").replace("$code$", code),
|
||||
st.translateKey("noRelay.worldNotFound2").replace("$code$", code), st.translateKey("noRelay.worldNotFound3")));
|
||||
return;
|
||||
}
|
||||
|
||||
LANClientNetworkManager netMgr = LANClientNetworkManager.connectToWorld(sock, code, sock.getURI());
|
||||
if(netMgr == null) {
|
||||
this.mc.displayGuiScreen(new GuiDisconnected(parent, "connect.failed", "disconnect.genericReason", st.translateKey("noRelay.worldFail").replace("$code$", code), ""));
|
||||
return;
|
||||
}
|
||||
|
||||
completed = true;
|
||||
|
||||
try {
|
||||
netHandler = new NetClientHandler(mc, netMgr);
|
||||
this.mc.setNetManager(netMgr);
|
||||
netMgr.setNetHandler(netHandler);
|
||||
netHandler.addToSendQueue(new Packet2ClientProtocol(61, EaglerProfile.username, "127.0.0.1", mc.gameSettings.renderDistance));
|
||||
netHandler.addToSendQueue(new Packet250CustomPayload("EAG|MySkin", EaglerProfile.getSkinPacket()));
|
||||
netHandler.addToSendQueue(new Packet250CustomPayload("EAG|MyCape", EaglerProfile.getCapePacket()));
|
||||
} catch (IOException e) {
|
||||
this.mc.displayGuiScreen(new GuiDisconnected(parent, "connect.failed", "disconnect.genericReason", "could not create nethandler", ""));
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiCreateWorld;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiTextField;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenNameWorldImport extends GuiScreen {
|
||||
private GuiScreen parentGuiScreen;
|
||||
private GuiTextField theGuiTextField;
|
||||
private int importFormat;
|
||||
private String name;
|
||||
private String oldName;
|
||||
private boolean timeToImport = false;
|
||||
private boolean definetlyTimeToImport = false;
|
||||
private boolean isImporting = false;
|
||||
|
||||
public GuiScreenNameWorldImport(GuiScreen menu, String name, int format) {
|
||||
this.parentGuiScreen = menu;
|
||||
this.importFormat = format;
|
||||
this.oldName = name;
|
||||
if(name.length() > 4 && (name.endsWith(".epk") || name.endsWith(".zip"))) {
|
||||
name = name.substring(0, name.length() - 4);
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the main game loop to update the screen.
|
||||
*/
|
||||
public void updateScreen() {
|
||||
if(!timeToImport) {
|
||||
this.theGuiTextField.updateCursorCounter();
|
||||
}
|
||||
if(definetlyTimeToImport && !isImporting) {
|
||||
isImporting = true;
|
||||
IntegratedServer.importWorld(GuiCreateWorld.makeUsableName(this.theGuiTextField.getText().trim()), EaglerAdapter.getFileChooserResult(), importFormat);
|
||||
mc.displayGuiScreen(new GuiScreenSingleplayerLoading(parentGuiScreen, "selectWorld.progress.importing." + importFormat, () -> IntegratedServer.isReady()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the buttons (and other controls) to the screen in question.
|
||||
*/
|
||||
public void initGui() {
|
||||
if(!timeToImport) {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
EaglerAdapter.enableRepeatEvents(true);
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12, var1.translateKey("selectWorld.progress.continue")));
|
||||
this.buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, var1.translateKey("gui.cancel")));
|
||||
this.theGuiTextField = new GuiTextField(this.fontRenderer, this.width / 2 - 100, this.height / 4 + 3, 200, 20);
|
||||
this.theGuiTextField.setFocused(true);
|
||||
this.theGuiTextField.setText(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the screen is unloaded. Used to disable keyboard repeat events
|
||||
*/
|
||||
public void onGuiClosed() {
|
||||
EaglerAdapter.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a control is clicked. This is the equivalent of
|
||||
* ActionListener.actionPerformed(ActionEvent e).
|
||||
*/
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if (par1GuiButton.enabled) {
|
||||
if (par1GuiButton.id == 1) {
|
||||
EaglerAdapter.clearFileChooserResult();
|
||||
this.mc.displayGuiScreen(this.parentGuiScreen);
|
||||
} else if (par1GuiButton.id == 0) {
|
||||
this.buttonList.clear();
|
||||
timeToImport = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when a key is typed. This is the equivalent of
|
||||
* KeyListener.keyTyped(KeyEvent e).
|
||||
*/
|
||||
protected void keyTyped(char par1, int par2) {
|
||||
this.theGuiTextField.textboxKeyTyped(par1, par2);
|
||||
((GuiButton) this.buttonList.get(0)).enabled = this.theGuiTextField.getText().trim().length() > 0;
|
||||
|
||||
if (par1 == 13) {
|
||||
this.actionPerformed((GuiButton) this.buttonList.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the mouse is clicked.
|
||||
*/
|
||||
protected void mouseClicked(int par1, int par2, int par3) {
|
||||
super.mouseClicked(par1, par2, par3);
|
||||
if(!timeToImport) {
|
||||
this.theGuiTextField.mouseClicked(par1, par2, par3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the screen and all the components in it.
|
||||
*/
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
if(!timeToImport) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey("selectWorld.importName"), this.width / 2, this.height / 4 - 60 + 20, 16777215);
|
||||
this.drawString(this.fontRenderer, var4.translateKey("selectWorld.enterName"), this.width / 2 - 100, this.height / 4 - 60 + 50, 10526880);
|
||||
this.theGuiTextField.drawTextBox();
|
||||
}else {
|
||||
definetlyTimeToImport = true;
|
||||
long dots = (EaglerAdapter.steadyTimeMillis() / 500l) % 4l;
|
||||
String str = "Reading: '" + oldName + "'";
|
||||
this.drawString(fontRenderer, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(str)) / 2, this.height / 3 + 10, 0xFFFFFF);
|
||||
}
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenNoRelays extends GuiScreen {
|
||||
|
||||
private GuiScreen parent;
|
||||
private String title1;
|
||||
private String title2;
|
||||
private String title3;
|
||||
|
||||
public GuiScreenNoRelays(GuiScreen parent, String title) {
|
||||
this.parent = parent;
|
||||
this.title1 = title;
|
||||
this.title2 = null;
|
||||
this.title3 = null;
|
||||
}
|
||||
|
||||
public GuiScreenNoRelays(GuiScreen parent, String title1, String title2, String title3) {
|
||||
this.parent = parent;
|
||||
this.title1 = title1;
|
||||
this.title2 = title2;
|
||||
this.title3 = title3;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
buttonList.clear();
|
||||
buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 - 60 + 145, var1.translateKey("gui.cancel")));
|
||||
buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 - 60 + 115, var1.translateKey("directConnect.lanWorldRelay")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
this.drawDefaultBackground();
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey(title1), this.width / 2, this.height / 4 - 60 + 70, 16777215);
|
||||
if(title2 != null) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey(title2), this.width / 2, this.height / 4 - 60 + 80, 0xCCCCCC);
|
||||
}
|
||||
if(title3 != null) {
|
||||
this.drawCenteredString(this.fontRenderer, var4.translateKey(title3), this.width / 2, this.height / 4 - 60 + 90, 0xCCCCCC);
|
||||
}
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
mc.displayGuiScreen(parent);
|
||||
}else if(par1GuiButton.id == 1) {
|
||||
mc.displayGuiScreen(new GuiScreenRelay(parent));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
195
src/main/java/net/lax1dude/eaglercraft/GuiScreenRelay.java
Normal file
195
src/main/java/net/lax1dude/eaglercraft/GuiScreenRelay.java
Normal file
@@ -0,0 +1,195 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.EnumChatFormatting;
|
||||
import net.minecraft.src.Gui;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.GuiScreenConfirmation;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenRelay extends GuiScreen {
|
||||
|
||||
private final GuiScreen screen;
|
||||
private GuiSlotRelay slots;
|
||||
private boolean hasPinged;
|
||||
private boolean addingNew = false;
|
||||
private boolean deleting = false;
|
||||
int selected;
|
||||
|
||||
private GuiButton deleteRelay;
|
||||
private GuiButton setPrimary;
|
||||
|
||||
private String tooltipString = null;
|
||||
|
||||
private long lastRefresh = 0l;
|
||||
|
||||
public GuiScreenRelay(GuiScreen screen) {
|
||||
this.screen = screen;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
selected = -1;
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
buttonList.clear();
|
||||
buttonList.add(new GuiButton(0, this.width / 2 + 54, this.height - 28, 100, 20, var1.translateKey("gui.done")));
|
||||
buttonList.add(new GuiButton(1, this.width / 2 - 154, this.height - 52, 100, 20, var1.translateKey("networkSettings.add")));
|
||||
buttonList.add(deleteRelay = new GuiButton(2, this.width / 2 - 50, this.height - 52, 100, 20, var1.translateKey("networkSettings.delete")));
|
||||
buttonList.add(setPrimary = new GuiButton(3, this.width / 2 + 54, this.height - 52, 100, 20, var1.translateKey("networkSettings.default")));
|
||||
buttonList.add(new GuiButton(4, this.width / 2 - 50, this.height - 28, 100, 20, var1.translateKey("networkSettings.refresh")));
|
||||
buttonList.add(new GuiButton(5, this.width / 2 - 154, this.height - 28, 100, 20, var1.translateKey("networkSettings.loadDefaults")));
|
||||
buttonList.add(new GuiButton(6, this.width - 100, 0, 100, 20, var1.translateKey("networkSettings.downloadRelay")));
|
||||
updateButtons();
|
||||
this.slots = new GuiSlotRelay(this);
|
||||
if(!hasPinged) {
|
||||
hasPinged = true;
|
||||
slots.relayManager.ping();
|
||||
}
|
||||
}
|
||||
|
||||
void updateButtons() {
|
||||
if(selected < 0) {
|
||||
deleteRelay.enabled = false;
|
||||
setPrimary.enabled = false;
|
||||
}else {
|
||||
deleteRelay.enabled = true;
|
||||
setPrimary.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void actionPerformed(GuiButton btn) {
|
||||
if(btn.id == 0) {
|
||||
IntegratedServer.relayManager.save();
|
||||
mc.displayGuiScreen(screen);
|
||||
} else if(btn.id == 1) {
|
||||
addingNew = true;
|
||||
mc.displayGuiScreen(new GuiScreenAddRelay(this));
|
||||
} else if(btn.id == 2) {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
if(selected >= 0) {
|
||||
RelayServer srv = IntegratedServer.relayManager.get(selected);
|
||||
mc.displayGuiScreen(new GuiScreenConfirmation(this, var1.translateKey("networkSettings.delete"), var1.translateKey("addRelay.removeText1"),
|
||||
EnumChatFormatting.GRAY + "'" + srv.comment + "' (" + srv.address + ")", selected));
|
||||
deleting = true;
|
||||
}
|
||||
} else if(btn.id == 3) {
|
||||
if(selected >= 0) {
|
||||
slots.relayManager.setPrimary(selected);
|
||||
selected = 0;
|
||||
}
|
||||
} else if(btn.id == 4) {
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
if(millis - lastRefresh > 700l) {
|
||||
lastRefresh = millis;
|
||||
slots.relayManager.ping();
|
||||
}
|
||||
lastRefresh += 60l;
|
||||
} else if(btn.id == 5) {
|
||||
slots.relayManager.loadDefaults();
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
if(millis - lastRefresh > 700l) {
|
||||
lastRefresh = millis;
|
||||
slots.relayManager.ping();
|
||||
}
|
||||
lastRefresh += 60l;
|
||||
} else if(btn.id == 6) {
|
||||
EaglerAdapter.downloadBytes("EaglerSPRelay.zip", EaglerAdapter.loadResourceBytes("relay_download.zip"));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
slots.relayManager.update();
|
||||
}
|
||||
|
||||
private int mx = 0;
|
||||
private int my = 0;
|
||||
|
||||
int getFrameMouseX() {
|
||||
return mx;
|
||||
}
|
||||
|
||||
int getFrameMouseY() {
|
||||
return my;
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
drawDefaultBackground();
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
|
||||
mx = par1;
|
||||
my = par2;
|
||||
slots.drawScreen(par1, par2, par3);
|
||||
|
||||
if(tooltipString != null) {
|
||||
int ww = mc.fontRenderer.getStringWidth(tooltipString);
|
||||
Gui.drawRect(par1 + 1, par2 - 14, par1 + ww + 7, par2 - 2, 0xC0000000);
|
||||
screen.drawString(mc.fontRenderer, tooltipString, par1 + 4, par2 - 12, 0xFF999999);
|
||||
tooltipString = null;
|
||||
}
|
||||
|
||||
this.drawCenteredString(fontRenderer, var4.translateKey("networkSettings.title"), this.width / 2, 16, 16777215);
|
||||
|
||||
String str = var4.translateKey("networkSettings.relayTimeout") + " " + mc.gameSettings.relayTimeout;
|
||||
int w = fontRenderer.getStringWidth(str);
|
||||
this.drawString(fontRenderer, str, 3, 3, 0xDDDDDD);
|
||||
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glTranslatef(w + 7, 4, 0.0f);
|
||||
EaglerAdapter.glScalef(0.75f, 0.75f, 0.75f);
|
||||
str = EnumChatFormatting.UNDERLINE + var4.translateKey("networkSettings.relayTimeoutChange");
|
||||
int w2 = fontRenderer.getStringWidth(str);
|
||||
boolean b = par1 > w + 5 && par1 < w + 7 + w2 * 3 / 4 && par2 > 3 && par2 < 11;
|
||||
this.drawString(fontRenderer, EnumChatFormatting.UNDERLINE + var4.translateKey("networkSettings.relayTimeoutChange"), 0, 0, b ? 0xCCCCCC : 0x999999);
|
||||
EaglerAdapter.glPopMatrix();
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void mouseClicked(int par1, int par2, int par3) {
|
||||
super.mouseClicked(par1, par2, par3);
|
||||
if(par3 == 0) {
|
||||
StringTranslate var4 = StringTranslate.getInstance();
|
||||
String str = var4.translateKey("networkSettings.relayTimeout") + " " + mc.gameSettings.relayTimeout;
|
||||
int w = fontRenderer.getStringWidth(str);
|
||||
str = var4.translateKey("networkSettings.relayTimeoutChange");
|
||||
int w2 = fontRenderer.getStringWidth(str);
|
||||
if(par1 > w + 5 && par1 < w + 7 + w2 * 3 / 4 && par2 > 3 && par2 < 11) {
|
||||
this.mc.displayGuiScreen(new GuiScreenChangeRelayTimeout(this));
|
||||
this.mc.sndManager.playSoundFX("random.click", 1.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setToolTip(String str) {
|
||||
tooltipString = str;
|
||||
}
|
||||
|
||||
String addNewName;
|
||||
String addNewAddr;
|
||||
boolean addNewPrimary;
|
||||
|
||||
public void confirmClicked(boolean par1, int par2) {
|
||||
if(par1) {
|
||||
if(addingNew) {
|
||||
IntegratedServer.relayManager.addNew(addNewAddr, addNewName, addNewPrimary);
|
||||
addNewAddr = null;
|
||||
addNewName = null;
|
||||
addNewPrimary = false;
|
||||
selected = -1;
|
||||
updateButtons();
|
||||
}else if(deleting) {
|
||||
IntegratedServer.relayManager.remove(par2);
|
||||
selected = -1;
|
||||
updateButtons();
|
||||
}
|
||||
}
|
||||
addingNew = false;
|
||||
deleting = false;
|
||||
this.mc.displayGuiScreen(this);
|
||||
}
|
||||
|
||||
static Minecraft getMinecraft(GuiScreenRelay screen) {
|
||||
return screen.mc;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiDisconnected;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.NetClientHandler;
|
||||
import net.minecraft.src.Packet250CustomPayload;
|
||||
import net.minecraft.src.Packet2ClientProtocol;
|
||||
import net.minecraft.src.WorldClient;
|
||||
|
||||
public class GuiScreenSingleplayerConnecting extends GuiScreen {
|
||||
|
||||
private GuiScreen menu;
|
||||
private String message;
|
||||
private GuiButton killTask;
|
||||
private NetClientHandler netHandler = null;
|
||||
|
||||
private long startStartTime;
|
||||
|
||||
public GuiScreenSingleplayerConnecting(GuiScreen menu, String message) {
|
||||
this.menu = menu;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
if(startStartTime == 0) this.startStartTime = EaglerAdapter.steadyTimeMillis();
|
||||
this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, "Kill Task"));
|
||||
killTask.enabled = false;
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
float f = 2.0f;
|
||||
int top = this.height / 3;
|
||||
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
|
||||
long dots = (millis / 500l) % 4l;
|
||||
this.drawString(fontRenderer, message + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(message)) / 2, top + 10, 0xFFFFFF);
|
||||
|
||||
long elapsed = (millis - startStartTime) / 1000l;
|
||||
if(elapsed > 3) {
|
||||
this.drawCenteredString(fontRenderer, "(" + elapsed + "s)", this.width / 2, top + 25, 0xFFFFFF);
|
||||
}
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
public boolean doesGuiPauseGame() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
if(netHandler == null) {
|
||||
try {
|
||||
netHandler = new NetClientHandler(mc, EaglerProfile.username);
|
||||
this.mc.setNetManager(netHandler.getNetManager());
|
||||
netHandler.addToSendQueue(new Packet2ClientProtocol(61, EaglerProfile.username, "127.0.0.1", mc.gameSettings.renderDistance));
|
||||
netHandler.addToSendQueue(new Packet250CustomPayload("EAG|MySkin", EaglerProfile.getSkinPacket()));
|
||||
netHandler.addToSendQueue(new Packet250CustomPayload("EAG|MyCape", EaglerProfile.getCapePacket()));
|
||||
} catch (IOException e) {
|
||||
this.mc.displayGuiScreen(new GuiDisconnected(this.menu, "connect.failed", "disconnect.genericReason", "could not create nethandler", ""));
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
if(millis - startStartTime > 6000l) {
|
||||
killTask.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
IntegratedServer.killWorker();
|
||||
this.mc.loadWorld((WorldClient)null);
|
||||
this.mc.displayGuiScreen(menu);
|
||||
if(netHandler != null) {
|
||||
netHandler.getNetManager().closeConnections();
|
||||
Minecraft.getMinecraft().setNetManager(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.ipc.IPCPacket15ThrowException;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenSingleplayerException extends GuiScreen {
|
||||
|
||||
private GuiScreen mainmenu;
|
||||
private IPCPacket15ThrowException exception;
|
||||
private GuiButton returnToMenu;
|
||||
private String action;
|
||||
|
||||
public GuiScreenSingleplayerException(GuiScreen mainmenu, String action, IPCPacket15ThrowException exception) {
|
||||
this.mainmenu = mainmenu;
|
||||
this.action = action;
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.add(returnToMenu = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 36, StringTranslate.getInstance().translateKey("selectWorld.progress.continue")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
|
||||
int width_ = this.fontRenderer.getStringWidth(exception.errorMessage);
|
||||
|
||||
int numTrace = exception.stackTrace.size();
|
||||
if(numTrace > 7) {
|
||||
numTrace = 7;
|
||||
}
|
||||
int height_ = numTrace * 10 + 90 + (numTrace >= 7 ? 10 : 0);
|
||||
|
||||
for(String s : exception.stackTrace) {
|
||||
int w = this.fontRenderer.getStringWidth(" " + s);
|
||||
if(width_ < w) {
|
||||
width_ = w;
|
||||
}
|
||||
}
|
||||
|
||||
int top = (this.height - height_) / 2;
|
||||
if(top < 5) top = 5;
|
||||
int left = (this.width - width_) / 2;
|
||||
if(left < 5) left = 5;
|
||||
|
||||
this.drawCenteredString(fontRenderer, "An error occured while '" + StringTranslate.getInstance().translateKey(action) + "'", this.width / 2, top, 0xFFAAAA);
|
||||
|
||||
this.drawString(fontRenderer, exception.errorMessage, left, top + 20, 0xFFAAAA);
|
||||
for(int i = 0; i < numTrace; ++i) {
|
||||
this.drawString(fontRenderer, " " + exception.stackTrace.get(i), left, top + 30 + i * 10, 0xFFAAAA);
|
||||
}
|
||||
if(numTrace >= 7) {
|
||||
this.drawCenteredString(fontRenderer, "... " + (exception.size() - numTrace) + " remaining ...", this.width / 2, top + 30 + numTrace * 10, 0xFFAAAA);
|
||||
}
|
||||
|
||||
returnToMenu.yPosition = top + 46 + numTrace * 10 + (numTrace >= 7 ? 10 : 0);
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
this.mc.displayGuiScreen(mainmenu);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.ipc.IPCPacket15ThrowException;
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiMainMenu;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenSingleplayerLoading extends GuiScreen {
|
||||
|
||||
public final GuiScreen menu;
|
||||
private GuiButton killTask;
|
||||
public final String message;
|
||||
private BooleanSupplier checkTaskComplete;
|
||||
private Runnable taskKill;
|
||||
private String lastStatus;
|
||||
private String currentStatus;
|
||||
private BiConsumer<GuiScreen, IPCPacket15ThrowException[]> onException;
|
||||
private int areYouSure;
|
||||
|
||||
private long startStartTime;
|
||||
|
||||
private static final Runnable defaultTerminateAction = () -> {
|
||||
IntegratedServer.killWorker();
|
||||
Minecraft.getMinecraft().displayGuiScreen(new GuiMainMenu());
|
||||
};
|
||||
|
||||
public static GuiScreen createException(GuiScreen ok, String msg, IPCPacket15ThrowException[] exceptions) {
|
||||
for(int i = exceptions.length - 1; i >= 0; --i) {
|
||||
ok = new GuiScreenSingleplayerException(ok, msg, exceptions[i]);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
private static final BiConsumer<GuiScreen, IPCPacket15ThrowException[]> defaultExceptionAction = (t, u) -> {
|
||||
GuiScreenSingleplayerLoading tt = (GuiScreenSingleplayerLoading) t;
|
||||
Minecraft.getMinecraft().displayGuiScreen(createException(tt.menu, tt.message, u));
|
||||
};
|
||||
|
||||
public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete) {
|
||||
this(menu, message, checkTaskComplete, defaultExceptionAction, defaultTerminateAction);
|
||||
}
|
||||
|
||||
public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, BiConsumer<GuiScreen, IPCPacket15ThrowException[]> exceptionAction) {
|
||||
this(menu, message, checkTaskComplete, exceptionAction, defaultTerminateAction);
|
||||
}
|
||||
|
||||
public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, Runnable onTerminate) {
|
||||
this(menu, message, checkTaskComplete, defaultExceptionAction, onTerminate);
|
||||
}
|
||||
|
||||
public GuiScreenSingleplayerLoading(GuiScreen menu, String message, BooleanSupplier checkTaskComplete, BiConsumer<GuiScreen, IPCPacket15ThrowException[]> onException, Runnable onTerminate) {
|
||||
this.menu = menu;
|
||||
this.message = message;
|
||||
this.checkTaskComplete = checkTaskComplete;
|
||||
this.onException = onException;
|
||||
this.taskKill = onTerminate;
|
||||
this.lastStatus = IntegratedServer.worldStatusString();
|
||||
this.currentStatus = message;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
if(startStartTime == 0) this.startStartTime = EaglerAdapter.steadyTimeMillis();
|
||||
areYouSure = 0;
|
||||
this.buttonList.add(killTask = new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, StringTranslate.getInstance().translateKey("gui.killTask")));
|
||||
killTask.enabled = false;
|
||||
}
|
||||
|
||||
public boolean doesGuiPauseGame() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
float f = 2.0f;
|
||||
int top = this.height / 3;
|
||||
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
|
||||
String str = StringTranslate.getInstance().translateKey(currentStatus);
|
||||
|
||||
long dots = (millis / 500l) % 4l;
|
||||
this.drawString(fontRenderer, str + (dots > 0 ? "." : "") + (dots > 1 ? "." : "") + (dots > 2 ? "." : ""), (this.width - this.fontRenderer.getStringWidth(str)) / 2, top + 10, 0xFFFFFF);
|
||||
|
||||
if(areYouSure > 0) {
|
||||
this.drawCenteredString(fontRenderer, StringTranslate.getInstance().translateKey("selectWorld.progress.cancelWarning"), this.width / 2, top + 25, 0xFF8888);
|
||||
}else {
|
||||
float prog = IntegratedServer.worldStatusProgress();
|
||||
if(this.currentStatus.equals(this.lastStatus) && prog > 0.01f) {
|
||||
this.drawCenteredString(fontRenderer, (prog > 1.0f ? ("(" + (prog > 1000000.0f ? "" + (int)(prog / 1000000.0f) + "MB" :
|
||||
(prog > 1000.0f ? "" + (int)(prog / 1000.0f) + "kB" : "" + (int)prog + "B")) + ")") : "" + (int)(prog * 100.0f) + "%"), this.width / 2, top + 25, 0xFFFFFF);
|
||||
}else {
|
||||
long elapsed = (millis - startStartTime) / 1000l;
|
||||
if(elapsed > 3) {
|
||||
this.drawCenteredString(fontRenderer, "(" + elapsed + "s)", this.width / 2, top + 25, 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
public void updateScreen() {
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
if(millis - startStartTime > 6000l) {
|
||||
killTask.enabled = true;
|
||||
}
|
||||
if(IntegratedServer.didLastCallFail()) {
|
||||
IPCPacket15ThrowException[] pk = IntegratedServer.worldStatusErrors();
|
||||
if(pk != null) {
|
||||
onException.accept(this, pk);
|
||||
}else {
|
||||
onException.accept(this, new IPCPacket15ThrowException[] { new IPCPacket15ThrowException("Server Crash: State '" +
|
||||
IntegratedState.getStateName(IntegratedServer.statusState()) + "'", new String[0]) });
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(checkTaskComplete.getAsBoolean()) {
|
||||
this.mc.displayGuiScreen(menu);
|
||||
}
|
||||
String str = IntegratedServer.worldStatusString();
|
||||
if(!lastStatus.equals(str)) {
|
||||
lastStatus = str;
|
||||
currentStatus = str;
|
||||
}
|
||||
killTask.displayString = StringTranslate.getInstance().translateKey(areYouSure > 0 ? "selectWorld.progress.confirmCancel" : "gui.killTask");
|
||||
if(areYouSure > 0) {
|
||||
--areYouSure;
|
||||
}
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
if(areYouSure <= 0) {
|
||||
areYouSure = 80;
|
||||
}else if(areYouSure <= 65) {
|
||||
taskKill.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
|
||||
public class GuiScreenSingleplayerNotImplemented extends GuiScreen {
|
||||
|
||||
private GuiScreen mainmenu;
|
||||
private String featureName;
|
||||
|
||||
public GuiScreenSingleplayerNotImplemented(GuiScreen mainmenu, String featureName) {
|
||||
this.mainmenu = mainmenu;
|
||||
this.featureName = featureName;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 3 + 50, "I Understand"));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
|
||||
this.drawCenteredString(fontRenderer, "the feature '" + featureName + "' is incomplete", this.width / 2, this.height / 3, 0xFFFFFF);
|
||||
this.drawCenteredString(fontRenderer, "it will be added to Eaglercraft in the next update", this.width / 2, this.height / 3 + 20, 0xFFFFFF);
|
||||
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
this.mc.displayGuiScreen(mainmenu);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.MathHelper;
|
||||
import net.minecraft.src.StringTranslate;
|
||||
|
||||
public class GuiScreenSkinCapeSettings extends GuiScreen {
|
||||
|
||||
private final GuiScreen parent;
|
||||
|
||||
private String skinCustomizationTitle = "yee";
|
||||
private String skinCustomizationOtherPlayers = "yee";
|
||||
|
||||
private GuiButton toggleCape;
|
||||
private GuiButton toggleJacket;
|
||||
private GuiButton toggleHat;
|
||||
private GuiButton toggleLeftArm;
|
||||
private GuiButton toggleRightArm;
|
||||
private GuiButton toggleLeftLeg;
|
||||
private GuiButton toggleRightLeg;
|
||||
private GuiButton toggleShowErasers;
|
||||
private GuiButton toggleShowOtherCapes;
|
||||
|
||||
public GuiScreenSkinCapeSettings(GuiScreen parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
skinCustomizationTitle = var1.translateKey("menu.skinCapeSettings.skinCustomization");
|
||||
skinCustomizationOtherPlayers = var1.translateKey("menu.skinCapeSettings.skinCustomization.otherPlayers");
|
||||
|
||||
int offset = MathHelper.clamp_int((height - 300) / 3, -100, 0);
|
||||
|
||||
buttonList.add(new GuiButton(0, ((width - 230) / 2), 225 + offset, 230, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.apply")));
|
||||
|
||||
buttonList.add(toggleJacket = new GuiButton(1, width / 2 - 152, 60 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.jacket") + ": " +
|
||||
(mc.gameSettings.showSkinJacket ? var1.translateKey("options.on") : var1.translateKey("options.off"))));
|
||||
buttonList.add(toggleHat = new GuiButton(2, width / 2 + 2, 60 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.hat") + ": " +
|
||||
(mc.gameSettings.showSkinHat ? var1.translateKey("options.on") : var1.translateKey("options.off"))));
|
||||
buttonList.add(toggleLeftArm = new GuiButton(3, width / 2 - 152, 82 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.leftArm") + ": " +
|
||||
(mc.gameSettings.showSkinLeftArm ? var1.translateKey("options.on") : var1.translateKey("options.off"))));
|
||||
buttonList.add(toggleRightArm = new GuiButton(4, width / 2 + 2, 82 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.rightArm") + ": " +
|
||||
(mc.gameSettings.showSkinRightArm ? var1.translateKey("options.on") : var1.translateKey("options.off"))));
|
||||
buttonList.add(toggleLeftLeg = new GuiButton(5, width / 2 - 152, 104 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.leftPants") + ": " +
|
||||
(mc.gameSettings.showSkinLeftLeg ? var1.translateKey("options.on") : var1.translateKey("options.off"))));
|
||||
buttonList.add(toggleRightLeg = new GuiButton(6, width / 2 + 2, 104 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.rightPants") + ": " +
|
||||
(mc.gameSettings.showSkinRightLeg ? var1.translateKey("options.on") : var1.translateKey("options.off"))));
|
||||
buttonList.add(toggleCape = new GuiButton(7, width / 2 - 85, 130 + offset, 165, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.cape") + ": " +
|
||||
(mc.gameSettings.showCape ? var1.translateKey("options.on") : var1.translateKey("options.off"))));
|
||||
buttonList.add(toggleShowErasers = new GuiButton(8, width / 2 - 152, 190 + offset, 150, 20, (mc.gameSettings.allowFNAWSkins ?
|
||||
var1.translateKey("menu.skinCapeSettings.skinCustomization.showErasersOn") : var1.translateKey("menu.skinCapeSettings.skinCustomization.showErasersOff"))));
|
||||
buttonList.add(toggleShowOtherCapes = new GuiButton(9, width / 2 + 2, 190 + offset, 150, 20, var1.translateKey("menu.skinCapeSettings.skinCustomization.showOtherCapes") + ": " +
|
||||
(mc.gameSettings.showOtherCapes ? var1.translateKey("options.on") : var1.translateKey("options.off"))));
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
StringTranslate var1 = StringTranslate.getInstance();
|
||||
switch(par1GuiButton.id) {
|
||||
case 0:
|
||||
mc.displayGuiScreen(parent);
|
||||
mc.gameSettings.saveOptions();
|
||||
break;
|
||||
case 1:
|
||||
mc.gameSettings.showSkinJacket = !mc.gameSettings.showSkinJacket;
|
||||
toggleJacket.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.jacket") + ": " +
|
||||
(mc.gameSettings.showSkinJacket ? var1.translateKey("options.on") : var1.translateKey("options.off"));
|
||||
break;
|
||||
case 2:
|
||||
mc.gameSettings.showSkinHat = !mc.gameSettings.showSkinHat;
|
||||
toggleHat.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.hat") + ": " +
|
||||
(mc.gameSettings.showSkinHat ? var1.translateKey("options.on") : var1.translateKey("options.off"));
|
||||
break;
|
||||
case 3:
|
||||
mc.gameSettings.showSkinLeftArm = !mc.gameSettings.showSkinLeftArm;
|
||||
toggleLeftArm.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.leftArm") + ": " +
|
||||
(mc.gameSettings.showSkinLeftArm ? var1.translateKey("options.on") : var1.translateKey("options.off"));
|
||||
break;
|
||||
case 4:
|
||||
mc.gameSettings.showSkinRightArm = !mc.gameSettings.showSkinRightArm;
|
||||
toggleRightArm.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.rightArm") + ": " +
|
||||
(mc.gameSettings.showSkinRightArm ? var1.translateKey("options.on") : var1.translateKey("options.off"));
|
||||
break;
|
||||
case 5:
|
||||
mc.gameSettings.showSkinLeftLeg = !mc.gameSettings.showSkinLeftLeg;
|
||||
toggleLeftLeg.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.leftPants") + ": " +
|
||||
(mc.gameSettings.showSkinLeftLeg ? var1.translateKey("options.on") : var1.translateKey("options.off"));
|
||||
break;
|
||||
case 6:
|
||||
mc.gameSettings.showSkinRightLeg = !mc.gameSettings.showSkinRightLeg;
|
||||
toggleRightLeg.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.rightPants") + ": " +
|
||||
(mc.gameSettings.showSkinRightLeg ? var1.translateKey("options.on") : var1.translateKey("options.off"));
|
||||
break;
|
||||
case 7:
|
||||
mc.gameSettings.showCape = !mc.gameSettings.showCape;
|
||||
toggleCape.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.cape") + ": " +
|
||||
(mc.gameSettings.showCape ? var1.translateKey("options.on") : var1.translateKey("options.off"));
|
||||
break;
|
||||
case 8:
|
||||
mc.gameSettings.allowFNAWSkins = !mc.gameSettings.allowFNAWSkins;
|
||||
toggleShowErasers.displayString = mc.gameSettings.allowFNAWSkins ? var1.translateKey("menu.skinCapeSettings.skinCustomization.showErasersOn") :
|
||||
var1.translateKey("menu.skinCapeSettings.skinCustomization.showErasersOff");
|
||||
break;
|
||||
case 9:
|
||||
mc.gameSettings.showOtherCapes = !mc.gameSettings.showOtherCapes;
|
||||
toggleShowOtherCapes.displayString = var1.translateKey("menu.skinCapeSettings.skinCustomization.showOtherCapes") + ": " +
|
||||
(mc.gameSettings.showOtherCapes ? var1.translateKey("options.on") : var1.translateKey("options.off"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void drawScreen(int mx, int my, float partialTicks) {
|
||||
drawDefaultBackground();
|
||||
|
||||
int offset = MathHelper.clamp_int((height - 300) / 3, -100, 0);
|
||||
|
||||
this.drawCenteredString(this.fontRenderer, skinCustomizationTitle, this.width / 2, 40 + offset, 16777215);
|
||||
this.drawCenteredString(this.fontRenderer, skinCustomizationOtherPlayers, this.width / 2, 170 + offset, 16777215);
|
||||
|
||||
super.drawScreen(mx, my, partialTicks);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.src.EnumChatFormatting;
|
||||
import net.minecraft.src.GuiButton;
|
||||
import net.minecraft.src.GuiScreen;
|
||||
import net.minecraft.src.StatCollector;
|
||||
|
||||
public class GuiScreenVSyncWarning extends GuiScreen {
|
||||
|
||||
private final GuiScreen cont;
|
||||
private final List<String> messages = new ArrayList<>();
|
||||
private int top = 0;
|
||||
|
||||
public GuiScreenVSyncWarning(GuiScreen cont) {
|
||||
this.cont = cont;
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
messages.clear();
|
||||
messages.add(EnumChatFormatting.RED + StatCollector.translateToLocal("options.vsyncWarning.title"));
|
||||
messages.add(null);
|
||||
messages.add(EnumChatFormatting.GRAY + StatCollector.translateToLocal("options.vsyncWarning.0"));
|
||||
messages.add(EnumChatFormatting.GRAY + StatCollector.translateToLocal("options.vsyncWarning.1"));
|
||||
messages.add(null);
|
||||
messages.add(StatCollector.translateToLocal("options.vsyncWarning.2"));
|
||||
messages.add(StatCollector.translateToLocal("options.vsyncWarning.3"));
|
||||
messages.add(StatCollector.translateToLocal("options.vsyncWarning.4"));
|
||||
messages.add(StatCollector.translateToLocal("options.vsyncWarning.5"));
|
||||
messages.add(StatCollector.translateToLocal("options.vsyncWarning.6"));
|
||||
int j = 0;
|
||||
for(int i = 0, l = messages.size(); i < l; ++i) {
|
||||
if(messages.get(i) != null) {
|
||||
j += 9;
|
||||
}else {
|
||||
j += 5;
|
||||
}
|
||||
}
|
||||
top = this.height / 6 + j / -12;
|
||||
j += top;
|
||||
buttonList.clear();
|
||||
buttonList.add(new GuiButton(0, this.width / 2 - 100, j + 16, StatCollector.translateToLocal("options.vsyncWarning.fixSettings")));
|
||||
buttonList.add(new GuiButton(1, this.width / 2 - 100, j + 40, StatCollector.translateToLocal("options.vsyncWarning.continueAnyway")));
|
||||
buttonList.add(new GuiButton(2, this.width / 2 - 100, j + 64, StatCollector.translateToLocal("options.vsyncWarning.doNotShowAgain")));
|
||||
}
|
||||
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
this.drawDefaultBackground();
|
||||
int j = 0;
|
||||
for(int i = 0, l = messages.size(); i < l; ++i) {
|
||||
String str = messages.get(i);
|
||||
if(str != null) {
|
||||
this.drawCenteredString(fontRenderer, str, this.width / 2, top + j, 16777215);
|
||||
j += 9;
|
||||
}else {
|
||||
j += 5;
|
||||
}
|
||||
}
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if(par1GuiButton.id == 0) {
|
||||
mc.gameSettings.enableVsync = true;
|
||||
mc.gameSettings.saveOptions();
|
||||
mc.displayGuiScreen(cont);
|
||||
}else if(par1GuiButton.id == 1) {
|
||||
mc.displayGuiScreen(cont);
|
||||
}else if(par1GuiButton.id == 2) {
|
||||
mc.gameSettings.hideVsyncWarning = true;
|
||||
mc.gameSettings.saveOptions();
|
||||
mc.displayGuiScreen(cont);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
130
src/main/java/net/lax1dude/eaglercraft/GuiSlotRelay.java
Normal file
130
src/main/java/net/lax1dude/eaglercraft/GuiSlotRelay.java
Normal file
@@ -0,0 +1,130 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch;
|
||||
import net.lax1dude.eaglercraft.adapter.Tessellator;
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.GuiSlot;
|
||||
|
||||
class GuiSlotRelay extends GuiSlot {
|
||||
|
||||
final GuiScreenRelay screen;
|
||||
final RelayManager relayManager;
|
||||
|
||||
public GuiSlotRelay(GuiScreenRelay screen) {
|
||||
super(GuiScreenRelay.getMinecraft(screen), screen.width, screen.height, 32, screen.height - 64, 26);
|
||||
this.screen = screen;
|
||||
this.relayManager = IntegratedServer.relayManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSize() {
|
||||
return relayManager.count();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void elementClicked(int var1, boolean var2) {
|
||||
screen.selected = var1;
|
||||
screen.updateButtons();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSelected(int var1) {
|
||||
return screen.selected == var1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawBackground() {
|
||||
screen.drawDefaultBackground();
|
||||
}
|
||||
|
||||
private static final TextureLocation icons = new TextureLocation("/gui/icons.png");
|
||||
|
||||
@Override
|
||||
protected void drawSlot(int id, int xx, int yy, int height, Tessellator var5) {
|
||||
if(id < relayManager.count()) {
|
||||
icons.bindTexture();
|
||||
RelayServer srv = relayManager.get(id);
|
||||
String comment = srv.comment;
|
||||
int var15 = 0;
|
||||
int var16 = 0;
|
||||
String str = null;
|
||||
int h = 12;
|
||||
long ping = srv.getPing();
|
||||
if(ping == 0l) {
|
||||
var16 = 5;
|
||||
str = "No Connection";
|
||||
}else if(ping < 0l) {
|
||||
var15 = 1;
|
||||
var16 = (int) (Minecraft.getSystemTime() / 100L + (long) (id * 2) & 7L);
|
||||
if (var16 > 4) {
|
||||
var16 = 8 - var16;
|
||||
}
|
||||
str = "Polling...";
|
||||
}else {
|
||||
VersionMismatch vm = srv.getPingCompatible();
|
||||
if(!vm.isCompatible()) {
|
||||
var16 = 5;
|
||||
switch(vm) {
|
||||
case CLIENT_OUTDATED:
|
||||
str = "Outdated Client!";
|
||||
break;
|
||||
case RELAY_OUTDATED:
|
||||
str = "Outdated Relay!";
|
||||
break;
|
||||
default:
|
||||
case UNKNOWN:
|
||||
str = "Incompatible Relay!";
|
||||
break;
|
||||
}
|
||||
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glTranslatef(xx + 205, yy + 11, 0.0f);
|
||||
EaglerAdapter.glScalef(0.6f, 0.6f, 0.6f);
|
||||
screen.drawTexturedModalRect(0, 0, 0, 144, 16, 16);
|
||||
EaglerAdapter.glPopMatrix();
|
||||
h += 10;
|
||||
}else {
|
||||
String pingComment = srv.getPingComment().trim();
|
||||
if(pingComment.length() > 0) {
|
||||
comment = pingComment;
|
||||
}
|
||||
str = "" + ping + "ms";
|
||||
if (ping < 150L) {
|
||||
var16 = 0;
|
||||
} else if (ping < 300L) {
|
||||
var16 = 1;
|
||||
} else if (ping < 600L) {
|
||||
var16 = 2;
|
||||
} else if (ping < 1000L) {
|
||||
var16 = 3;
|
||||
} else {
|
||||
var16 = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EaglerAdapter.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
screen.drawTexturedModalRect(xx + 205, yy, 0 + var15 * 10, 176 + var16 * 8, 10, 8);
|
||||
if(srv.isPrimary()) {
|
||||
EaglerAdapter.glPushMatrix();
|
||||
EaglerAdapter.glTranslatef(xx + 4, yy + 5, 0.0f);
|
||||
EaglerAdapter.glScalef(0.8f, 0.8f, 0.8f);
|
||||
screen.drawTexturedModalRect(0, 0, 0, 160, 16, 16);
|
||||
EaglerAdapter.glPopMatrix();
|
||||
}
|
||||
|
||||
screen.drawString(mc.fontRenderer, comment, xx + 22, yy + 2, 0xFFFFFFFF);
|
||||
screen.drawString(mc.fontRenderer, srv.address, xx + 22, yy + 12, 0xFF999999);
|
||||
|
||||
if(str != null) {
|
||||
int mx = screen.getFrameMouseX();
|
||||
int my = screen.getFrameMouseY();
|
||||
int rx = xx + 202;
|
||||
if(mx > rx && mx < rx + 13 && my > yy - 1 && my < yy + h) {
|
||||
screen.setToolTip(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
96
src/main/java/net/lax1dude/eaglercraft/HighPolySkin.java
Normal file
96
src/main/java/net/lax1dude/eaglercraft/HighPolySkin.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public enum HighPolySkin {
|
||||
|
||||
LONG_ARMS(
|
||||
new TextureLocation("/mesh/longarms.png"),
|
||||
new ModelLocation("/mesh/longarms0.mdl"),
|
||||
null,
|
||||
new ModelLocation("/mesh/longarms2.mdl"),
|
||||
new ModelLocation[] {
|
||||
new ModelLocation("/mesh/longarms1.mdl")
|
||||
},
|
||||
new float[] {
|
||||
1.325f
|
||||
},
|
||||
0.0f,
|
||||
new TextureLocation("/mesh/longarms.fallback.png")
|
||||
),
|
||||
|
||||
WEIRD_CLIMBER_DUDE(
|
||||
new TextureLocation("/mesh/weirdclimber.png"),
|
||||
new ModelLocation("/mesh/weirdclimber0.mdl"),
|
||||
null,
|
||||
new ModelLocation("/mesh/weirdclimber2.mdl"),
|
||||
new ModelLocation[] {
|
||||
new ModelLocation("/mesh/weirdclimber1.mdl")
|
||||
},
|
||||
new float[] {
|
||||
2.62f
|
||||
},
|
||||
-90.0f,
|
||||
new TextureLocation("/mesh/weirdclimber.fallback.png")
|
||||
),
|
||||
|
||||
LAXATIVE_DUDE(
|
||||
new TextureLocation("/mesh/laxativedude.png"),
|
||||
new ModelLocation("/mesh/laxativedude0.mdl"),
|
||||
null,
|
||||
new ModelLocation("/mesh/laxativedude3.mdl"),
|
||||
new ModelLocation[] {
|
||||
new ModelLocation("/mesh/laxativedude1.mdl"),
|
||||
new ModelLocation("/mesh/laxativedude2.mdl")
|
||||
},
|
||||
new float[] {
|
||||
2.04f
|
||||
},
|
||||
0.0f,
|
||||
new TextureLocation("/mesh/laxativedude.fallback.png")
|
||||
),
|
||||
|
||||
BABY_CHARLES(
|
||||
new TextureLocation("/mesh/charles.png"),
|
||||
new ModelLocation("/mesh/charles0.mdl"),
|
||||
new ModelLocation("/mesh/charles1.mdl"),
|
||||
new ModelLocation("/mesh/charles2.mdl"),
|
||||
new ModelLocation[] {},
|
||||
new float[] {},
|
||||
0.0f,
|
||||
new TextureLocation("/mesh/charles.fallback.png")
|
||||
),
|
||||
|
||||
BABY_WINSTON(
|
||||
new TextureLocation("/mesh/winston.png"),
|
||||
new ModelLocation("/mesh/winston0.mdl"),
|
||||
null,
|
||||
new ModelLocation("/mesh/winston1.mdl"),
|
||||
new ModelLocation[] {},
|
||||
new float[] {},
|
||||
0.0f,
|
||||
new TextureLocation("/mesh/winston.fallback.png")
|
||||
);
|
||||
|
||||
public static float highPolyScale = 0.5f;
|
||||
|
||||
public final TextureLocation texture;
|
||||
public final ModelLocation bodyModel;
|
||||
public final ModelLocation headModel;
|
||||
public final ModelLocation eyesModel;
|
||||
public final ModelLocation[] limbsModel;
|
||||
public final float[] limbsOffset;
|
||||
public final float limbsInitialRotation;
|
||||
public final TextureLocation fallbackTexture;
|
||||
|
||||
HighPolySkin(TextureLocation texture, ModelLocation bodyModel, ModelLocation headModel, ModelLocation eyesModel,
|
||||
ModelLocation[] limbsModel, float[] limbsOffset, float limbsInitialRotation, TextureLocation fallbackTexture) {
|
||||
this.texture = texture;
|
||||
this.bodyModel = bodyModel;
|
||||
this.headModel = headModel;
|
||||
this.eyesModel = eyesModel;
|
||||
this.limbsModel = limbsModel;
|
||||
this.limbsOffset = limbsOffset;
|
||||
this.limbsInitialRotation = limbsInitialRotation;
|
||||
this.fallbackTexture = fallbackTexture;
|
||||
}
|
||||
|
||||
}
|
||||
452
src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java
Normal file
452
src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java
Normal file
@@ -0,0 +1,452 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.ipc.*;
|
||||
import net.minecraft.src.EnumGameType;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
import net.minecraft.src.NetHandler;
|
||||
import net.minecraft.src.WorldSettings;
|
||||
|
||||
public class IntegratedServer {
|
||||
|
||||
public static boolean isWorkerAlive() {
|
||||
return !(statusState < 0 || !EaglerAdapter.isIntegratedServerAlive());
|
||||
}
|
||||
|
||||
public static void killWorker() {
|
||||
openConnections.clear();
|
||||
exceptions.clear();
|
||||
statusState = IntegratedState.WORLD_WORKER_NOT_RUNNING;
|
||||
EaglerAdapter.terminateIntegratedServer();
|
||||
}
|
||||
|
||||
private static String[] loadLocale = null;
|
||||
private static String[] loadStats = null;
|
||||
private static boolean isPaused = false;
|
||||
private static List<String> integratedServerTPS = new LinkedList<>();
|
||||
|
||||
public static final int preferredRelayVersion = 1;
|
||||
|
||||
public static final RelayManager relayManager = new RelayManager();
|
||||
|
||||
public static List<String> getTPS() {
|
||||
return integratedServerTPS;
|
||||
}
|
||||
|
||||
public static void clearTPS() {
|
||||
integratedServerTPS.clear();
|
||||
}
|
||||
|
||||
public static void begin() {
|
||||
if(!isWorkerAlive()) {
|
||||
begin(EaglerAdapter.fileContentsLines("lang/en_US.lang"), EaglerAdapter.fileContentsLines("achievement/map.txt"));
|
||||
}
|
||||
}
|
||||
|
||||
public static void begin(String[] locale, String[] stats) {
|
||||
logException = true;
|
||||
if(!isWorkerAlive()) {
|
||||
openConnections.clear();
|
||||
exceptions.clear();
|
||||
statusState = IntegratedState.WORLD_WORKER_BOOTING;
|
||||
isPaused = false;
|
||||
loadLocale = locale;
|
||||
loadStats = stats;
|
||||
clearTPS();
|
||||
EaglerAdapter.beginLoadingIntegratedServer();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isReady() {
|
||||
return statusState == IntegratedState.WORLD_NONE;
|
||||
}
|
||||
|
||||
public static boolean isWorldNotLoaded() {
|
||||
return statusState == IntegratedState.WORLD_NONE || statusState == IntegratedState.WORLD_WORKER_NOT_RUNNING ||
|
||||
statusState == IntegratedState.WORLD_WORKER_BOOTING;
|
||||
}
|
||||
|
||||
public static boolean isWorldRunning() {
|
||||
return statusState == IntegratedState.WORLD_LOADED || statusState == IntegratedState.WORLD_PAUSED ||
|
||||
statusState == IntegratedState.WORLD_LOADING || statusState == IntegratedState.WORLD_SAVING;
|
||||
}
|
||||
|
||||
public static boolean isWorldReady() {
|
||||
return statusState == IntegratedState.WORLD_LOADED || statusState == IntegratedState.WORLD_LOADING;
|
||||
}
|
||||
|
||||
private static void ensureReady() {
|
||||
if(!isReady()) {
|
||||
String msg = "Server is in state " + statusState + " '" + IntegratedState.getStateName(statusState) + "' which is not the 'WORLD_NONE' state for the requested IPC operation";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureWorldReady() {
|
||||
if(!isWorldReady()) {
|
||||
String msg = "Server is in state " + statusState + " '" + IntegratedState.getStateName(statusState) + "' which is not the 'WORLD_LOADED' state for the requested IPC operation";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isAlive() {
|
||||
return isWorkerAlive();
|
||||
}
|
||||
|
||||
public static void loadWorld(String name, int difficulty) {
|
||||
loadWorld(name, difficulty, null);
|
||||
}
|
||||
|
||||
public static void loadWorld(String name, int difficulty, WorldSettings gen) {
|
||||
ensureReady();
|
||||
clearTPS();
|
||||
statusState = IntegratedState.WORLD_LOADING;
|
||||
isPaused = false;
|
||||
|
||||
if(gen != null) {
|
||||
sendIPCPacket(new IPCPacket02InitWorld(name, gen.getIPCGamemode(), gen.getTerrainType().getWorldTypeID(),
|
||||
gen.func_82749_j(), gen.getSeed(), gen.areCommandsAllowed(), gen.isMapFeaturesEnabled(), gen.isBonusChestEnabled()));
|
||||
}
|
||||
|
||||
sendIPCPacket(new IPCPacket00StartServer(name, EaglerProfile.username, difficulty));
|
||||
}
|
||||
|
||||
public static void unloadWorld() {
|
||||
if(isWorldRunning()) {
|
||||
statusState = IntegratedState.WORLD_UNLOADING;
|
||||
sendIPCPacket(new IPCPacket01StopServer());
|
||||
}
|
||||
IntegratedServerLAN.closeLAN();
|
||||
}
|
||||
|
||||
public static void autoSave() {
|
||||
if(!isPaused) {
|
||||
statusState = IntegratedState.WORLD_SAVING;
|
||||
sendIPCPacket(new IPCPacket0BPause(false));
|
||||
}
|
||||
}
|
||||
|
||||
public static void setPaused(boolean pause) {
|
||||
if(statusState != IntegratedState.WORLD_LOADED && statusState != IntegratedState.WORLD_PAUSED) {
|
||||
return;
|
||||
}
|
||||
if(isPaused != pause) {
|
||||
if(pause) {
|
||||
statusState = IntegratedState.WORLD_PAUSED;
|
||||
}else {
|
||||
statusState = IntegratedState.WORLD_LOADED;
|
||||
}
|
||||
sendIPCPacket(new IPCPacket0BPause(pause));
|
||||
isPaused = pause;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void requestWorldList() {
|
||||
ensureReady();
|
||||
statusState = IntegratedState.WORLD_LISTING;
|
||||
worlds.clear();
|
||||
sendIPCPacket(new IPCPacket0EListWorlds());
|
||||
}
|
||||
|
||||
public static List<NBTTagCompound> getWorldList() {
|
||||
return statusState == IntegratedState.WORLD_LISTING ? null : worlds;
|
||||
}
|
||||
|
||||
public static NBTTagCompound getWorld(String folderName) {
|
||||
for(NBTTagCompound nbt : worlds) {
|
||||
if(folderName.equals(nbt.getString("folderName"))) {
|
||||
return nbt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void deleteWorld(String name) {
|
||||
ensureReady();
|
||||
statusState = IntegratedState.WORLD_DELETING;
|
||||
sendIPCPacket(new IPCPacket03DeleteWorld(name));
|
||||
}
|
||||
|
||||
public static void setWorldName(String name, String displayName) {
|
||||
ensureReady();
|
||||
sendIPCPacket(new IPCPacket06RenameWorldNBT(name, displayName));
|
||||
}
|
||||
|
||||
public static void copyMoveWorld(String oldName, String newName, String newDisplayName, boolean copyFilesNotRename) {
|
||||
ensureReady();
|
||||
statusState = copyFilesNotRename ? IntegratedState.WORLD_DUPLICATING : IntegratedState.WORLD_RENAMING;
|
||||
sendIPCPacket(new IPCPacket04RenameWorld(oldName, newName, newDisplayName, copyFilesNotRename));
|
||||
}
|
||||
|
||||
private static int statusState = IntegratedState.WORLD_WORKER_NOT_RUNNING;
|
||||
private static String worldStatusString = "";
|
||||
private static float worldStatusProgress = 0.0f;
|
||||
|
||||
private static final LinkedList<IPCPacket15ThrowException> exceptions = new LinkedList<>();
|
||||
|
||||
public static final LinkedList<NBTTagCompound> worlds = new LinkedList<>();
|
||||
|
||||
public static int statusState() {
|
||||
return statusState;
|
||||
}
|
||||
|
||||
public static String worldStatusString() {
|
||||
return worldStatusString;
|
||||
}
|
||||
|
||||
public static float worldStatusProgress() {
|
||||
return worldStatusProgress;
|
||||
}
|
||||
|
||||
public static IPCPacket15ThrowException worldStatusError() {
|
||||
return exceptions.size() > 0 ? exceptions.remove(0) : null;
|
||||
}
|
||||
|
||||
public static IPCPacket15ThrowException[] worldStatusErrors() {
|
||||
if(exceptions.size() <= 0) {
|
||||
return null;
|
||||
}
|
||||
IPCPacket15ThrowException[] t = new IPCPacket15ThrowException[exceptions.size()];
|
||||
for(int i = 0; i < t.length; ++i) {
|
||||
t[i] = exceptions.get(i);
|
||||
}
|
||||
exceptions.clear();
|
||||
return t;
|
||||
}
|
||||
|
||||
private static boolean logException = false;
|
||||
|
||||
public static void enableExceptionLog(boolean f) {
|
||||
logException = f;
|
||||
}
|
||||
|
||||
private static boolean callFailed = false;
|
||||
|
||||
public static boolean didLastCallFail() {
|
||||
boolean c = callFailed;
|
||||
callFailed = false;
|
||||
return c;
|
||||
}
|
||||
|
||||
public static void importWorld(String name, byte[] data, int format) {
|
||||
ensureReady();
|
||||
statusState = IntegratedState.WORLD_IMPORTING;
|
||||
sendIPCPacket(new IPCPacket07ImportWorld(name, data, (byte)format));
|
||||
}
|
||||
|
||||
public static void exportWorld(String name, int format) {
|
||||
ensureReady();
|
||||
statusState = IntegratedState.WORLD_EXPORTING;
|
||||
if(format == IPCPacket05RequestData.REQUEST_LEVEL_EAG) {
|
||||
name = name + (new String(new char[] { (char)253, (char)233, (char)233 })) + EaglerProfile.username;
|
||||
}
|
||||
sendIPCPacket(new IPCPacket05RequestData(name, (byte)format));
|
||||
}
|
||||
|
||||
private static byte[] exportResponse = null;
|
||||
|
||||
public static byte[] getExportResponse() {
|
||||
byte[] dat = exportResponse;
|
||||
exportResponse = null;
|
||||
return dat;
|
||||
}
|
||||
|
||||
public static void processICP() {
|
||||
|
||||
if(!EaglerAdapter.isIntegratedServerAlive()) {
|
||||
if(IntegratedServerLAN.isLANOpen()) {
|
||||
IntegratedServerLAN.closeLAN();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
PKT pktBytes;
|
||||
while((pktBytes = EaglerAdapter.recieveFromIntegratedServer("IPC")) != null) {
|
||||
|
||||
IPCPacketBase packet;
|
||||
try {
|
||||
packet = IPCPacketManager.IPCDeserialize(pktBytes.data);
|
||||
}catch(IOException e) {
|
||||
System.err.print("Failed to deserialize IPC packet: ");
|
||||
e.printStackTrace();
|
||||
continue;
|
||||
}
|
||||
|
||||
int id = packet.id();
|
||||
|
||||
try {
|
||||
switch(id) {
|
||||
case IPCPacketFFProcessKeepAlive.ID: {
|
||||
IPCPacketFFProcessKeepAlive pkt = (IPCPacketFFProcessKeepAlive)packet;
|
||||
IntegratedState.isACKValidInState(pkt.ack, statusState);
|
||||
switch(pkt.ack) {
|
||||
case 0xFF:
|
||||
System.out.println("Integrated server signaled a successful boot");
|
||||
sendIPCPacket(new IPCPacket14StringList(IPCPacket14StringList.LOCALE, loadLocale));
|
||||
sendIPCPacket(new IPCPacket14StringList(IPCPacket14StringList.STAT_GUID, loadStats));
|
||||
loadLocale = loadStats = null;
|
||||
statusState = IntegratedState.WORLD_NONE;
|
||||
break;
|
||||
case IPCPacket00StartServer.ID:
|
||||
statusState = IntegratedState.WORLD_LOADED;
|
||||
isPaused = false;
|
||||
break;
|
||||
case IPCPacket0BPause.ID:
|
||||
statusState = isPaused ? IntegratedState.WORLD_PAUSED : IntegratedState.WORLD_LOADED;
|
||||
break;
|
||||
case IPCPacketFFProcessKeepAlive.FAILURE:
|
||||
System.err.println("Server signaled 'FAILURE' response in state '" + IntegratedState.getStateName(statusState) + "'");
|
||||
statusState = IntegratedState.WORLD_NONE;
|
||||
callFailed = true;
|
||||
break;
|
||||
case IPCPacket01StopServer.ID:
|
||||
statusState = IntegratedState.WORLD_NONE;
|
||||
break;
|
||||
case IPCPacket03DeleteWorld.ID:
|
||||
case IPCPacket04RenameWorld.ID:
|
||||
case IPCPacket07ImportWorld.ID:
|
||||
case IPCPacket12FileWrite.ID:
|
||||
case IPCPacket13FileCopyMove.ID:
|
||||
case IPCPacket18ClearPlayers.ID:
|
||||
statusState = IntegratedState.WORLD_NONE;
|
||||
break;
|
||||
default:
|
||||
System.err.println("IPC acknowledge packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' was not handled");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPCPacket09RequestResponse.ID: {
|
||||
IPCPacket09RequestResponse pkt = (IPCPacket09RequestResponse)packet;
|
||||
if(statusState == IntegratedState.WORLD_EXPORTING) {
|
||||
statusState = IntegratedState.WORLD_NONE;
|
||||
exportResponse = pkt.response;
|
||||
}else {
|
||||
System.err.println("IPCPacket09RequestResponse was recieved but statusState was '" + IntegratedState.getStateName(statusState) + "' instead of 'WORLD_EXPORTING'");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPCPacket0DProgressUpdate.ID: {
|
||||
IPCPacket0DProgressUpdate pkt = (IPCPacket0DProgressUpdate)packet;
|
||||
worldStatusString = pkt.updateMessage;
|
||||
worldStatusProgress = pkt.updateProgress;
|
||||
if(logException) {
|
||||
System.out.println("IntegratedServer: task \"" + pkt.updateMessage + "\"" + (pkt.updateProgress > 0.0f ? " is " + ((int)(pkt.updateProgress * 100.0f)) + "% complete" : ""));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPCPacket14StringList.ID: {
|
||||
IPCPacket14StringList pkt = (IPCPacket14StringList)packet;
|
||||
|
||||
if(pkt.opCode == IPCPacket14StringList.SERVER_TPS) {
|
||||
integratedServerTPS.clear();
|
||||
integratedServerTPS.addAll(pkt.stringList);
|
||||
}
|
||||
|
||||
// file path list for file browser
|
||||
|
||||
break;
|
||||
}
|
||||
case IPCPacket15ThrowException.ID: {
|
||||
exceptions.add((IPCPacket15ThrowException)packet);
|
||||
if(logException) {
|
||||
((IPCPacket15ThrowException)packet).log();
|
||||
}
|
||||
if(exceptions.size() > 64) {
|
||||
exceptions.remove(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPCPacket16NBTList.ID: {
|
||||
IPCPacket16NBTList pkt = (IPCPacket16NBTList)packet;
|
||||
if(pkt.opCode == IPCPacket16NBTList.WORLD_LIST && statusState == IntegratedState.WORLD_LISTING) {
|
||||
statusState = IntegratedState.WORLD_NONE;
|
||||
worlds.clear();
|
||||
worlds.addAll(pkt.nbtTagList);
|
||||
}else {
|
||||
System.err.println("IPC packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' contained invalid opCode " + pkt.opCode + " in state " + statusState + " '" + IntegratedState.getStateName(statusState) + "'");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPCPacket0CPlayerChannel.ID: {
|
||||
IPCPacket0CPlayerChannel pkt = (IPCPacket0CPlayerChannel)packet;
|
||||
WorkerNetworkManager newConnection = openConnections.get(pkt.channel);
|
||||
if(newConnection == null) {
|
||||
return;
|
||||
}
|
||||
System.out.println("[Client][INIT][CLOSE][" + pkt.channel + "]");
|
||||
newConnection.closeConnections();
|
||||
openConnections.remove(pkt.channel);
|
||||
EaglerAdapter.disableChannel("NET|" + pkt.channel);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
System.err.println("IPC packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "' was not handled");
|
||||
break;
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
System.err.println("Failed to process IPC packet type 0x" + Integer.toHexString(id) + " class '" + packet.getClass().getSimpleName() + "'");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
IntegratedServerLAN.updateLANServer();
|
||||
}
|
||||
|
||||
public static void sendIPCPacket(IPCPacketBase pkt) {
|
||||
try {
|
||||
byte[] serialized = IPCPacketManager.IPCSerialize(pkt);
|
||||
EaglerAdapter.sendToIntegratedServer("IPC", serialized);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not serialize IPC packet 0x" + Integer.toHexString(pkt.id()) + " class '" + pkt.getClass().getSimpleName() + "'");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static final HashMap<String, WorkerNetworkManager> openConnections = new HashMap<>();
|
||||
|
||||
public static final boolean doesChannelExist(String channel) {
|
||||
return openConnections.containsKey(channel);
|
||||
}
|
||||
|
||||
public static final WorkerNetworkManager openConnection(String channel, NetHandler netHandler) {
|
||||
WorkerNetworkManager newConnection = openConnections.get(channel);
|
||||
if(newConnection != null) {
|
||||
return newConnection;
|
||||
}
|
||||
System.out.println("[Client][INIT][OPEN][" + channel + "]");
|
||||
EaglerAdapter.enableChannel("NET|" + channel);
|
||||
sendIPCPacket(new IPCPacket0CPlayerChannel(channel, true));
|
||||
newConnection = new WorkerNetworkManager(channel, netHandler);
|
||||
openConnections.put(channel, newConnection);
|
||||
return newConnection;
|
||||
}
|
||||
|
||||
public static final void closeChannel(String channel) {
|
||||
WorkerNetworkManager newConnection = openConnections.get(channel);
|
||||
if(newConnection == null) {
|
||||
return;
|
||||
}
|
||||
System.out.println("[Client][INIT][CLOSE][" + channel + "]");
|
||||
newConnection.closeConnections();
|
||||
openConnections.remove(channel);
|
||||
EaglerAdapter.disableChannel("NET|" + channel);
|
||||
sendIPCPacket(new IPCPacket0CPlayerChannel(channel, false));
|
||||
}
|
||||
|
||||
public static void configureLAN(EnumGameType enumGameType, boolean allowCommands) {
|
||||
sendIPCPacket(new IPCPacket17ConfigureLAN(enumGameType.getID(), allowCommands, IntegratedServerLAN.currentICEServers));
|
||||
}
|
||||
|
||||
public static void clearPlayerData(String worldName) {
|
||||
ensureReady();
|
||||
statusState = IntegratedState.WORLD_CLEAR_PLAYERS;
|
||||
sendIPCPacket(new IPCPacket18ClearPlayers(worldName));
|
||||
}
|
||||
|
||||
}
|
||||
369
src/main/java/net/lax1dude/eaglercraft/IntegratedServerLAN.java
Normal file
369
src/main/java/net/lax1dude/eaglercraft/IntegratedServerLAN.java
Normal file
@@ -0,0 +1,369 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.ipc.IPCPacket0CPlayerChannel;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.*;
|
||||
|
||||
public class IntegratedServerLAN {
|
||||
|
||||
public static final List<String> currentICEServers = new ArrayList<>();
|
||||
|
||||
private static RelayServerSocket lanRelaySocket = null;
|
||||
|
||||
private static String currentCode = null;
|
||||
|
||||
public static String shareToLAN(Consumer<String> progressCallback, String worldName, boolean worldHidden) {
|
||||
currentCode = null;
|
||||
RelayServerSocket sock = IntegratedServer.relayManager.getWorkingRelay((str) -> progressCallback.accept("Connecting: " + str),
|
||||
IntegratedServer.preferredRelayVersion, worldName + (worldHidden ? ";1" : ";0"));
|
||||
if(sock == null) {
|
||||
lanRelaySocket = null;
|
||||
return null;
|
||||
}else {
|
||||
progressCallback.accept("Opening: " + sock.getURI());
|
||||
IPacket00Handshake hs = (IPacket00Handshake)sock.readPacket();
|
||||
lanRelaySocket = sock;
|
||||
String code = hs.connectionCode;
|
||||
System.out.println("Relay [" + sock.getURI() + "] connected as 'server', code: " + code);
|
||||
progressCallback.accept("Opened '" + code + "' on " + sock.getURI());
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
do {
|
||||
if(sock.isClosed()) {
|
||||
System.out.println("Relay [" + sock.getURI() + "] connection lost");
|
||||
lanRelaySocket = null;
|
||||
return null;
|
||||
}
|
||||
IPacket pkt = sock.readPacket();
|
||||
if(pkt != null) {
|
||||
if(pkt instanceof IPacket01ICEServers) {
|
||||
IPacket01ICEServers ipkt = (IPacket01ICEServers)pkt;
|
||||
System.out.println("Relay [" + sock.getURI() + "] provided ICE servers:");
|
||||
currentICEServers.clear();
|
||||
for(net.lax1dude.eaglercraft.sp.relay.pkt.ICEServerSet.RelayServer srv : ipkt.servers) {
|
||||
System.out.println("Relay [" + sock.getURI() + "] " + srv.type.name()
|
||||
+ ": " + srv.address);
|
||||
currentICEServers.add(srv.getICEString());
|
||||
}
|
||||
EaglerAdapter.serverLANInitializeServer(currentICEServers.toArray(new String[currentICEServers.size()]));
|
||||
return currentCode = code;
|
||||
}else {
|
||||
System.err.println("Relay [" + sock.getURI() + "] unexpected packet: " + pkt.getClass().getSimpleName());
|
||||
closeLAN();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
EaglerAdapter.sleep(50);
|
||||
}while(EaglerAdapter.steadyTimeMillis() - millis < 2500l);
|
||||
System.out.println("Relay [" + sock.getURI() + "] relay provide ICE servers timeout");
|
||||
closeLAN();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCurrentURI() {
|
||||
return lanRelaySocket == null ? "<disconnected>" : lanRelaySocket.getURI();
|
||||
}
|
||||
|
||||
public static String getCurrentCode() {
|
||||
return currentCode == null ? "<undefined>" : currentCode;
|
||||
}
|
||||
|
||||
public static void closeLAN() {
|
||||
closeLANNoKick();
|
||||
EaglerAdapter.serverLANCloseServer();
|
||||
cleanupLAN();
|
||||
}
|
||||
|
||||
public static void closeLANNoKick() {
|
||||
if(lanRelaySocket != null) {
|
||||
lanRelaySocket.close();
|
||||
lanRelaySocket = null;
|
||||
currentCode = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void cleanupLAN() {
|
||||
Iterator<LANClient> itr = clients.values().iterator();
|
||||
while(itr.hasNext()) {
|
||||
itr.next().disconnect();
|
||||
}
|
||||
clients.clear();
|
||||
}
|
||||
|
||||
public static boolean isHostingLAN() {
|
||||
return lanRelaySocket != null || EaglerAdapter.countPeers() > 0;
|
||||
}
|
||||
|
||||
public static boolean isLANOpen() {
|
||||
return lanRelaySocket != null;
|
||||
}
|
||||
|
||||
private static final Map<String, LANClient> clients = new HashMap<>();
|
||||
|
||||
public static void updateLANServer() {
|
||||
if(lanRelaySocket != null) {
|
||||
IPacket pkt;
|
||||
while((pkt = lanRelaySocket.readPacket()) != null) {
|
||||
if(pkt instanceof IPacket02NewClient) {
|
||||
IPacket02NewClient ipkt = (IPacket02NewClient) pkt;
|
||||
if(clients.containsKey(ipkt.clientId)) {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay provided duplicate client '" + ipkt.clientId + "'");
|
||||
}else {
|
||||
clients.put(ipkt.clientId, new LANClient(ipkt.clientId));
|
||||
}
|
||||
}else if(pkt instanceof IPacket03ICECandidate) {
|
||||
IPacket03ICECandidate ipkt = (IPacket03ICECandidate) pkt;
|
||||
LANClient c = clients.get(ipkt.peerId);
|
||||
if(c != null) {
|
||||
c.handleICECandidates(ipkt.candidate);
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay sent IPacket03ICECandidate for unknown client '" + ipkt.peerId + "'");
|
||||
}
|
||||
}else if(pkt instanceof IPacket04Description) {
|
||||
IPacket04Description ipkt = (IPacket04Description) pkt;
|
||||
LANClient c = clients.get(ipkt.peerId);
|
||||
if(c != null) {
|
||||
c.handleDescription(ipkt.description);
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay sent IPacket04Description for unknown client '" + ipkt.peerId + "'");
|
||||
}
|
||||
}else if(pkt instanceof IPacket05ClientSuccess) {
|
||||
IPacket05ClientSuccess ipkt = (IPacket05ClientSuccess) pkt;
|
||||
LANClient c = clients.get(ipkt.clientId);
|
||||
if(c != null) {
|
||||
c.handleSuccess();
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay sent IPacket05ClientSuccess for unknown client '" + ipkt.clientId + "'");
|
||||
}
|
||||
}else if(pkt instanceof IPacket06ClientFailure) {
|
||||
IPacket06ClientFailure ipkt = (IPacket06ClientFailure) pkt;
|
||||
LANClient c = clients.get(ipkt.clientId);
|
||||
if(c != null) {
|
||||
c.handleFailure();
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] relay sent IPacket06ClientFailure for unknown client '" + ipkt.clientId + "'");
|
||||
}
|
||||
}else if(pkt instanceof IPacketFFErrorCode) {
|
||||
IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] error code thrown: " +
|
||||
IPacketFFErrorCode.code2string(ipkt.code) + "(" + ipkt.code + "): " + ipkt.desc);
|
||||
Throwable t;
|
||||
while((t = lanRelaySocket.getException()) != null) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected packet: " + pkt.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
if(lanRelaySocket.isClosed()) {
|
||||
lanRelaySocket = null;
|
||||
}
|
||||
}
|
||||
Iterator<LANClient> itr = clients.values().iterator();
|
||||
while(itr.hasNext()) {
|
||||
LANClient cl = itr.next();
|
||||
cl.update();
|
||||
if(cl.dead) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class LANClient {
|
||||
|
||||
private static final int PRE = 0, RECEIVED_ICE_CANDIDATE = 1, SENT_ICE_CANDIDATE = 2, RECEIVED_DESCRIPTION = 3,
|
||||
SENT_DESCRIPTION = 4, RECEIVED_SUCCESS = 5, CONNECTED = 6, CLOSED = 7;
|
||||
|
||||
protected final String clientId;
|
||||
protected final String channelId;
|
||||
|
||||
protected int state = PRE;
|
||||
protected boolean dead = false;
|
||||
protected String localICECandidate = null;
|
||||
protected boolean localChannel = false;
|
||||
protected List<byte[]> packetPreBuffer = null;
|
||||
protected final long startTime;
|
||||
|
||||
protected LANClient(String clientId) {
|
||||
this.clientId = clientId;
|
||||
this.channelId = "NET|" + clientId;
|
||||
this.startTime = EaglerAdapter.steadyTimeMillis();
|
||||
EaglerAdapter.serverLANCreatePeer(clientId);
|
||||
}
|
||||
|
||||
protected void handleICECandidates(String candidates) {
|
||||
if(state == SENT_DESCRIPTION) {
|
||||
EaglerAdapter.serverLANPeerICECandidates(clientId, candidates);
|
||||
if(localICECandidate != null) {
|
||||
lanRelaySocket.writePacket(new IPacket03ICECandidate(clientId, localICECandidate));
|
||||
localICECandidate = null;
|
||||
state = SENT_ICE_CANDIDATE;
|
||||
}else {
|
||||
state = RECEIVED_ICE_CANDIDATE;
|
||||
}
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected IPacket03ICECandidate for '" + clientId + "'");
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleDescription(String description) {
|
||||
if(state == PRE) {
|
||||
EaglerAdapter.serverLANPeerDescription(clientId, description);
|
||||
state = RECEIVED_DESCRIPTION;
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected IPacket04Description for '" + clientId + "'");
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleSuccess() {
|
||||
if(state == SENT_ICE_CANDIDATE) {
|
||||
if(localChannel) {
|
||||
EaglerAdapter.enableChannel(channelId);
|
||||
IntegratedServer.sendIPCPacket(new IPCPacket0CPlayerChannel(clientId, true));
|
||||
localChannel = false;
|
||||
if(packetPreBuffer != null) {
|
||||
for(byte[] b : packetPreBuffer) {
|
||||
EaglerAdapter.sendToIntegratedServer(channelId, b);
|
||||
}
|
||||
packetPreBuffer = null;
|
||||
}
|
||||
state = CONNECTED;
|
||||
}else {
|
||||
state = RECEIVED_SUCCESS;
|
||||
}
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected IPacket05ClientSuccess for '" + clientId + "'");
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleFailure() {
|
||||
if(state == SENT_ICE_CANDIDATE) {
|
||||
System.err.println("Client '" + clientId + "' failed to connect");
|
||||
disconnect();
|
||||
}else {
|
||||
System.err.println("Relay [" + lanRelaySocket.getURI() + "] unexpected IPacket06ClientFailure for '" + clientId + "'");
|
||||
}
|
||||
}
|
||||
|
||||
protected void update() {
|
||||
if(state != CLOSED) {
|
||||
if(state != CONNECTED && EaglerAdapter.steadyTimeMillis() - startTime > 13000l) {
|
||||
System.out.println("LAN client '" + clientId + "' handshake timed out");
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
PKT pk;
|
||||
while(state == CONNECTED && (pk = EaglerAdapter.recieveFromIntegratedServer("NET|" + clientId)) != null) {
|
||||
EaglerAdapter.serverLANWritePacket(clientId, pk.data);
|
||||
}
|
||||
List<LANPeerEvent> l = EaglerAdapter.serverLANGetAllEvent(clientId);
|
||||
if(l == null) {
|
||||
return;
|
||||
}
|
||||
read_loop: for(int i = 0, s = l.size(); i < s; ++i) {
|
||||
LANPeerEvent evt = l.get(i);
|
||||
if(evt instanceof LANPeerEvent.LANPeerDisconnectEvent) {
|
||||
System.out.println("LAN client '" + clientId + "' disconnected");
|
||||
disconnect();
|
||||
}else {
|
||||
switch(state) {
|
||||
case SENT_DESCRIPTION:{
|
||||
if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
|
||||
localICECandidate = ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates;
|
||||
continue read_loop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECEIVED_DESCRIPTION: {
|
||||
if(evt instanceof LANPeerEvent.LANPeerDescriptionEvent) {
|
||||
lanRelaySocket.writePacket(new IPacket04Description(clientId, ((LANPeerEvent.LANPeerDescriptionEvent)evt).description));
|
||||
state = SENT_DESCRIPTION;
|
||||
continue read_loop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECEIVED_ICE_CANDIDATE: {
|
||||
if(evt instanceof LANPeerEvent.LANPeerICECandidateEvent) {
|
||||
lanRelaySocket.writePacket(new IPacket03ICECandidate(clientId, ((LANPeerEvent.LANPeerICECandidateEvent)evt).candidates));
|
||||
state = SENT_ICE_CANDIDATE;
|
||||
continue read_loop;
|
||||
}else if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) {
|
||||
localChannel = true;
|
||||
continue read_loop;
|
||||
}else if(evt instanceof LANPeerEvent.LANPeerPacketEvent) {
|
||||
if(packetPreBuffer == null) packetPreBuffer = new LinkedList<>();
|
||||
packetPreBuffer.add(((LANPeerEvent.LANPeerPacketEvent)evt).payload);
|
||||
continue read_loop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SENT_ICE_CANDIDATE: {
|
||||
if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) {
|
||||
localChannel = true;
|
||||
continue read_loop;
|
||||
}else if(evt instanceof LANPeerEvent.LANPeerPacketEvent) {
|
||||
if(packetPreBuffer == null) packetPreBuffer = new LinkedList<>();
|
||||
packetPreBuffer.add(((LANPeerEvent.LANPeerPacketEvent)evt).payload);
|
||||
continue read_loop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RECEIVED_SUCCESS: {
|
||||
if(evt instanceof LANPeerEvent.LANPeerDataChannelEvent) {
|
||||
EaglerAdapter.enableChannel(channelId);
|
||||
IntegratedServer.sendIPCPacket(new IPCPacket0CPlayerChannel(clientId, true));
|
||||
if(packetPreBuffer != null) {
|
||||
for(byte[] b : packetPreBuffer) {
|
||||
EaglerAdapter.sendToIntegratedServer(channelId, b);
|
||||
}
|
||||
packetPreBuffer = null;
|
||||
}
|
||||
state = CONNECTED;
|
||||
continue read_loop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONNECTED: {
|
||||
if(evt instanceof LANPeerEvent.LANPeerPacketEvent) {
|
||||
EaglerAdapter.sendToIntegratedServer(channelId, ((LANPeerEvent.LANPeerPacketEvent)evt).payload);
|
||||
continue read_loop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(state != CLOSED) {
|
||||
System.err.println("LAN client '" + clientId + "' had an accident: " + evt.getClass().getSimpleName() + " (state " + state + ")");
|
||||
}
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
protected void disconnect() {
|
||||
if(!dead) {
|
||||
if(state == CONNECTED) {
|
||||
IntegratedServer.sendIPCPacket(new IPCPacket0CPlayerChannel(clientId, false));
|
||||
EaglerAdapter.disableChannel(channelId);
|
||||
}
|
||||
state = CLOSED;
|
||||
EaglerAdapter.serverLANDisconnectPeer(clientId);
|
||||
dead = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
80
src/main/java/net/lax1dude/eaglercraft/IntegratedState.java
Normal file
80
src/main/java/net/lax1dude/eaglercraft/IntegratedState.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.ipc.*;
|
||||
|
||||
public class IntegratedState {
|
||||
|
||||
public static final int WORLD_WORKER_NOT_RUNNING = -2;
|
||||
public static final int WORLD_WORKER_BOOTING = -1;
|
||||
public static final int WORLD_NONE = 0;
|
||||
public static final int WORLD_LOADING = 2;
|
||||
public static final int WORLD_LOADED = 3;
|
||||
public static final int WORLD_UNLOADING = 4;
|
||||
public static final int WORLD_DELETING = 5;
|
||||
public static final int WORLD_RENAMING = 6;
|
||||
public static final int WORLD_DUPLICATING = 7;
|
||||
public static final int WORLD_PAUSED = 9;
|
||||
public static final int WORLD_LISTING = 10;
|
||||
public static final int WORLD_SAVING = 11;
|
||||
public static final int WORLD_IMPORTING = 12;
|
||||
public static final int WORLD_EXPORTING = 13;
|
||||
public static final int WORLD_GET_NBT = 14;
|
||||
|
||||
public static final int WORLD_LIST_FILE = 15;
|
||||
public static final int WORLD_FILE_READ = 16;
|
||||
public static final int WORLD_FILE_WRITE = 17;
|
||||
public static final int WORLD_FILE_MOVE = 18;
|
||||
public static final int WORLD_FILE_COPY = 19;
|
||||
public static final int WORLD_CLEAR_PLAYERS = 20;
|
||||
|
||||
public static String getStateName(int i) {
|
||||
switch(i) {
|
||||
case WORLD_WORKER_NOT_RUNNING: return "WORLD_WORKER_NOT_RUNNING";
|
||||
case WORLD_WORKER_BOOTING: return "WORLD_WORKER_BOOTING";
|
||||
case WORLD_NONE: return "WORLD_NONE";
|
||||
case WORLD_LOADING: return "WORLD_LOADING";
|
||||
case WORLD_LOADED: return "WORLD_LOADED";
|
||||
case WORLD_UNLOADING: return "WORLD_UNLOADING";
|
||||
case WORLD_DELETING: return "WORLD_DELETING";
|
||||
case WORLD_RENAMING: return "WORLD_RENAMING";
|
||||
case WORLD_DUPLICATING: return "WORLD_DUPLICATING";
|
||||
case WORLD_PAUSED: return "WORLD_PAUSED";
|
||||
case WORLD_LISTING: return "WORLD_LISTING";
|
||||
case WORLD_SAVING: return "WORLD_SAVING";
|
||||
case WORLD_IMPORTING: return "WORLD_IMPORTING";
|
||||
case WORLD_EXPORTING: return "WORLD_EXPORTING";
|
||||
case WORLD_GET_NBT: return "WORLD_GET_NBT";
|
||||
case WORLD_LIST_FILE: return "WORLD_LIST_FILE";
|
||||
case WORLD_FILE_READ: return "WORLD_FILE_READ";
|
||||
case WORLD_FILE_WRITE: return "WORLD_FILE_WRITE";
|
||||
case WORLD_FILE_MOVE: return "WORLD_FILE_MOVE";
|
||||
case WORLD_FILE_COPY: return "WORLD_FILE_COPY";
|
||||
case WORLD_CLEAR_PLAYERS: return "WORLD_CLEAR_PLAYERS";
|
||||
default: return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isACKValidInState(int ack, int state) {
|
||||
switch(ack) {
|
||||
case 0xFF: return state == WORLD_WORKER_BOOTING;
|
||||
case IPCPacket00StartServer.ID: return state == WORLD_LOADING;
|
||||
case IPCPacket01StopServer.ID: return state == WORLD_UNLOADING;
|
||||
case IPCPacket03DeleteWorld.ID: return state == WORLD_DELETING;
|
||||
case IPCPacket04RenameWorld.ID: return (state == WORLD_DUPLICATING || state == WORLD_RENAMING);
|
||||
case IPCPacket07ImportWorld.ID: return state == WORLD_IMPORTING;
|
||||
case IPCPacket0BPause.ID: return (state == WORLD_SAVING || state == WORLD_PAUSED);
|
||||
case IPCPacket12FileWrite.ID: return state == WORLD_FILE_WRITE;
|
||||
case IPCPacket13FileCopyMove.ID: return (state == WORLD_FILE_MOVE || state == WORLD_FILE_COPY);
|
||||
case IPCPacket18ClearPlayers.ID: return state == WORLD_CLEAR_PLAYERS;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void assertState(int ack, int state) {
|
||||
if(!isACKValidInState(ack, state)) {
|
||||
String msg = "Recieved ACK " + ack + " '" + getStateName(ack) + "' while the client state was " + state + " '" + getStateName(state) + "'";
|
||||
System.err.println(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,329 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket00Handshake;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket01ICEServers;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket03ICECandidate;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket04Description;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket05ClientSuccess;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket06ClientFailure;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacketFFErrorCode;
|
||||
import net.minecraft.src.INetworkManager;
|
||||
import net.minecraft.src.NetHandler;
|
||||
import net.minecraft.src.Packet;
|
||||
|
||||
public class LANClientNetworkManager implements INetworkManager {
|
||||
|
||||
private static final int PRE = 0, INIT = 1, SENT_ICE_CANDIDATE = 2, SENT_DESCRIPTION = 3;
|
||||
|
||||
private static final String[] initStateNames = new String[] { "PRE", "INIT", "SENT_ICE_CANDIDATE", "SENT_DESCRIPTION" };
|
||||
|
||||
public final String displayCode;
|
||||
public final String displayRelay;
|
||||
|
||||
private NetHandler theNetHandler;
|
||||
|
||||
private LANClientNetworkManager(String displayCode, String displayRelay) {
|
||||
this.displayCode = displayCode;
|
||||
this.displayRelay = displayRelay;
|
||||
this.theNetHandler = null;
|
||||
}
|
||||
|
||||
public static LANClientNetworkManager connectToWorld(RelayServerSocket sock, String displayCode, String displayRelay) {
|
||||
EaglerAdapter.clearLANClientState();
|
||||
int connectState = PRE;
|
||||
IPacket pkt;
|
||||
mainLoop: while(!sock.isClosed()) {
|
||||
if((pkt = sock.readPacket()) != null) {
|
||||
if(pkt instanceof IPacket00Handshake) {
|
||||
if(connectState == PRE) {
|
||||
|
||||
// %%%%%% Process IPacket00Handshake %%%%%%
|
||||
|
||||
System.out.println("Relay [" + displayRelay + "|" + displayCode + "] recieved handshake, "
|
||||
+ "client id: " + ((IPacket00Handshake)pkt).connectionCode);
|
||||
connectState = INIT;
|
||||
|
||||
}else {
|
||||
sock.close();
|
||||
System.err.println("Relay [" + displayRelay + "|" + displayCode + "] unexpected packet: "
|
||||
+ "IPacket00Handshake in state " + initStateNames[connectState]);
|
||||
return null;
|
||||
}
|
||||
}else if(pkt instanceof IPacket01ICEServers) {
|
||||
if(connectState == INIT) {
|
||||
|
||||
// %%%%%% Process IPacket01ICEServers %%%%%%
|
||||
|
||||
IPacket01ICEServers ipkt = (IPacket01ICEServers) pkt;
|
||||
|
||||
// print servers
|
||||
System.out.println("Relay [" + displayRelay + "|" + displayCode + "] provided ICE servers:");
|
||||
List<String> servers = new ArrayList<>();
|
||||
for(net.lax1dude.eaglercraft.sp.relay.pkt.ICEServerSet.RelayServer srv : ipkt.servers) {
|
||||
System.out.println("Relay [" + displayRelay + "|" + displayCode + "] " + srv.type.name()
|
||||
+ ": " + srv.address);
|
||||
servers.add(srv.getICEString());
|
||||
}
|
||||
|
||||
// process
|
||||
EaglerAdapter.clientLANSetICEServersAndConnect(servers.toArray(new String[servers.size()]));
|
||||
|
||||
// await result
|
||||
long lm = EaglerAdapter.steadyTimeMillis();
|
||||
do {
|
||||
String c = EaglerAdapter.clientLANAwaitDescription();
|
||||
if(c != null) {
|
||||
System.out.println("Relay [" + displayRelay + "|" + displayCode + "] client sent description");
|
||||
|
||||
// 'this.descriptionHandler' was called, send result:
|
||||
sock.writePacket(new IPacket04Description("", c));
|
||||
|
||||
connectState = SENT_DESCRIPTION;
|
||||
continue mainLoop;
|
||||
}
|
||||
EaglerAdapter.sleep(20);
|
||||
}while(EaglerAdapter.steadyTimeMillis() - lm < 5000l);
|
||||
|
||||
// no description was sent
|
||||
sock.close();
|
||||
System.err.println("Relay [" + displayRelay + "|" + displayCode + "] client provide description timeout");
|
||||
return null;
|
||||
|
||||
}else {
|
||||
sock.close();
|
||||
System.err.println("Relay [" + displayRelay + "|" + displayCode + "] unexpected packet: "
|
||||
+ "IPacket01ICEServers in state " + initStateNames[connectState]);
|
||||
return null;
|
||||
}
|
||||
}else if(pkt instanceof IPacket03ICECandidate) {
|
||||
if(connectState == SENT_ICE_CANDIDATE) {
|
||||
|
||||
// %%%%%% Process IPacket03ICECandidate %%%%%%
|
||||
|
||||
IPacket03ICECandidate ipkt = (IPacket03ICECandidate) pkt;
|
||||
|
||||
// process
|
||||
System.out.println("Relay [" + displayRelay + "|" + displayCode + "] recieved server ICE candidate");
|
||||
EaglerAdapter.clientLANSetICECandidate(ipkt.candidate);
|
||||
|
||||
// await result
|
||||
long lm = EaglerAdapter.steadyTimeMillis();
|
||||
do {
|
||||
if(EaglerAdapter.clientLANAwaitChannel()) {
|
||||
System.out.println("Relay [" + displayRelay + "|" + displayCode + "] client opened data channel");
|
||||
|
||||
// 'this.remoteDataChannelHandler' was called, success
|
||||
sock.writePacket(new IPacket05ClientSuccess(ipkt.peerId));
|
||||
sock.close();
|
||||
return new LANClientNetworkManager(displayCode, displayRelay);
|
||||
|
||||
}
|
||||
EaglerAdapter.sleep(20);
|
||||
}while(EaglerAdapter.steadyTimeMillis() - lm < 10000l);
|
||||
|
||||
// no channel was opened
|
||||
sock.writePacket(new IPacket06ClientFailure(ipkt.peerId));
|
||||
sock.close();
|
||||
System.err.println("Relay [" + displayRelay + "|" + displayCode + "] client open data channel timeout");
|
||||
return null;
|
||||
|
||||
}else {
|
||||
sock.close();
|
||||
System.err.println("Relay [" + displayRelay + "|" + displayCode + "] unexpected packet: "
|
||||
+ "IPacket03ICECandidate in state " + initStateNames[connectState]);
|
||||
return null;
|
||||
}
|
||||
}else if(pkt instanceof IPacket04Description) {
|
||||
if(connectState == SENT_DESCRIPTION) {
|
||||
|
||||
// %%%%%% Process IPacket04Description %%%%%%
|
||||
|
||||
IPacket04Description ipkt = (IPacket04Description) pkt;
|
||||
|
||||
// process
|
||||
System.out.println("Relay [" + displayRelay + "|" + displayCode + "] recieved server description");
|
||||
EaglerAdapter.clientLANSetDescription(ipkt.description);
|
||||
|
||||
// await result
|
||||
long lm = EaglerAdapter.steadyTimeMillis();
|
||||
do {
|
||||
String c = EaglerAdapter.clientLANAwaitICECandidate();
|
||||
if(c != null) {
|
||||
System.out.println("Relay [" + displayRelay + "|" + displayCode + "] client sent ICE candidate");
|
||||
|
||||
// 'this.iceCandidateHandler' was called, send result:
|
||||
sock.writePacket(new IPacket03ICECandidate("", c));
|
||||
|
||||
connectState = SENT_ICE_CANDIDATE;
|
||||
continue mainLoop;
|
||||
}
|
||||
EaglerAdapter.sleep(20);
|
||||
}while(EaglerAdapter.steadyTimeMillis() - lm < 10000l);
|
||||
|
||||
// no ice candidates were sent
|
||||
sock.close();
|
||||
System.err.println("Relay [" + displayRelay + "|" + displayCode + "] client provide ICE candidate timeout");
|
||||
return null;
|
||||
|
||||
}else {
|
||||
sock.close();
|
||||
System.err.println("Relay [" + displayRelay + "|" + displayCode + "] unexpected packet: "
|
||||
+ "IPacket04Description in state " + initStateNames[connectState]);
|
||||
return null;
|
||||
}
|
||||
}else if(pkt instanceof IPacketFFErrorCode) {
|
||||
|
||||
// %%%%%% Process IPacketFFErrorCode %%%%%%
|
||||
|
||||
IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
|
||||
System.err.println("Relay [" + displayRelay + "|" + displayCode + "] connection failed: " +
|
||||
IPacketFFErrorCode.code2string(ipkt.code) + "(" + ipkt.code + "): " + ipkt.desc);
|
||||
Throwable t;
|
||||
while((t = sock.getException()) != null) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
sock.close();
|
||||
return null;
|
||||
|
||||
}else {
|
||||
|
||||
// %%%%%% Unexpected Packet %%%%%%
|
||||
|
||||
System.err.println("Relay [" + displayRelay + "] unexpected packet: " + pkt.getClass().getSimpleName());
|
||||
sock.close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
EaglerAdapter.sleep(20);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetHandler(NetHandler var1) {
|
||||
theNetHandler = var1;
|
||||
}
|
||||
|
||||
private ByteArrayOutputStream sendBuffer = new ByteArrayOutputStream();
|
||||
|
||||
@Override
|
||||
public void addToSendQueue(Packet var1) {
|
||||
try {
|
||||
sendBuffer.reset();
|
||||
Packet.writePacket(var1, new DataOutputStream(sendBuffer));
|
||||
EaglerAdapter.clientLANSendPacket(sendBuffer.toByteArray());
|
||||
}catch(IOException e) {
|
||||
System.err.println("Failed to serialize minecraft packet '" + var1.getClass().getSimpleName() + "' to remote LAN world");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wakeThreads() {
|
||||
// no
|
||||
}
|
||||
|
||||
private byte[] fragmentedPacket = new byte[0];
|
||||
|
||||
@Override
|
||||
public void processReadPackets() {
|
||||
|
||||
/*
|
||||
* Alright some really weird shit is up with TeaVM here, if you put the try/catch
|
||||
* around the full inner body of the while loop, the compiler fails with no error
|
||||
* message, just a vague stack trace. But making a multi-catch around just
|
||||
* readPacketData and processPacket has no issues
|
||||
*
|
||||
* You're welcome for the two hours of my time and single line changes I made
|
||||
* in a fuck ton of irrelevant files leading up to this bullshit revelation
|
||||
*/
|
||||
|
||||
if(this.theNetHandler != null) {
|
||||
byte[] data;
|
||||
while((data = EaglerAdapter.clientLANReadPacket()) != null) {
|
||||
byte[] fullData;
|
||||
|
||||
if (data[0] == 0) {
|
||||
fullData = new byte[fragmentedPacket.length + data.length - 1];
|
||||
System.arraycopy(fragmentedPacket, 0, fullData, 0, fragmentedPacket.length);
|
||||
System.arraycopy(data, 1, fullData, fragmentedPacket.length, data.length - 1);
|
||||
fragmentedPacket = new byte[0];
|
||||
} else if (data[0] == 1) {
|
||||
fullData = new byte[fragmentedPacket.length + data.length - 1];
|
||||
System.arraycopy(fragmentedPacket, 0, fullData, 0, fragmentedPacket.length);
|
||||
System.arraycopy(data, 1, fullData, fragmentedPacket.length, data.length - 1);
|
||||
fragmentedPacket = fullData;
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
EaglerInputStream bai = new EaglerInputStream(fullData);
|
||||
|
||||
int pktId = bai.read();
|
||||
|
||||
if(pktId == -1) {
|
||||
System.err.println("Recieved invalid '-1' packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
Packet pkt = Packet.getNewPacket(pktId);
|
||||
|
||||
if(pkt == null) {
|
||||
System.err.println("Recieved invalid '" + pktId + "' packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
pkt.readPacketData(new DataInputStream(bai));
|
||||
pkt.processPacket(theNetHandler);
|
||||
}catch(IOException ex) {
|
||||
System.err.println("Could not deserialize a " + data.length + " byte long minecraft packet of type '" + (data.length <= 0 ? -1 : (int)(data[0] & 0xFF)) + "' from remote LAN world");
|
||||
}catch(Throwable t) {
|
||||
System.err.println("Could not process minecraft packet 0x" + Integer.toHexString(pkt.getPacketId()) + " class '" + pkt.getClass().getSimpleName() + "' from remote LAN world");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverShutdown() {
|
||||
if(!EaglerAdapter.clientLANClosed()) {
|
||||
EaglerAdapter.clientLANCloseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int packetSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void networkShutdown(String var1, Object... var2) {
|
||||
if(!EaglerAdapter.clientLANClosed()) {
|
||||
EaglerAdapter.clientLANCloseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnections() {
|
||||
if(!EaglerAdapter.clientLANClosed()) {
|
||||
EaglerAdapter.clientLANCloseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerURI() {
|
||||
return "[lan:" + displayRelay + ":" + displayCode + "]";
|
||||
}
|
||||
|
||||
}
|
||||
88
src/main/java/net/lax1dude/eaglercraft/LANPeerEvent.java
Normal file
88
src/main/java/net/lax1dude/eaglercraft/LANPeerEvent.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public interface LANPeerEvent {
|
||||
|
||||
String getPeerId();
|
||||
|
||||
public static class LANPeerICECandidateEvent implements LANPeerEvent {
|
||||
|
||||
public final String clientId;
|
||||
public final String candidates;
|
||||
|
||||
public LANPeerICECandidateEvent(String clientId, String candidates) {
|
||||
this.clientId = clientId;
|
||||
this.candidates = candidates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPeerId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class LANPeerDescriptionEvent implements LANPeerEvent {
|
||||
|
||||
public final String clientId;
|
||||
public final String description;
|
||||
|
||||
public LANPeerDescriptionEvent(String clientId, String description) {
|
||||
this.clientId = clientId;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPeerId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class LANPeerDataChannelEvent implements LANPeerEvent {
|
||||
|
||||
public final String clientId;
|
||||
|
||||
public LANPeerDataChannelEvent(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPeerId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class LANPeerPacketEvent implements LANPeerEvent {
|
||||
|
||||
public final String clientId;
|
||||
public final byte[] payload;
|
||||
|
||||
public LANPeerPacketEvent(String clientId, byte[] payload) {
|
||||
this.clientId = clientId;
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPeerId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class LANPeerDisconnectEvent implements LANPeerEvent {
|
||||
|
||||
public final String clientId;
|
||||
|
||||
public LANPeerDisconnectEvent(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPeerId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
139
src/main/java/net/lax1dude/eaglercraft/LANServerList.java
Normal file
139
src/main/java/net/lax1dude/eaglercraft/LANServerList.java
Normal file
@@ -0,0 +1,139 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld;
|
||||
|
||||
public class LANServerList {
|
||||
|
||||
private final List<LanServer> lanServersList = new LinkedList<>();
|
||||
private final Map<String,RelayWorldsQuery> lanServersQueryList = new LinkedHashMap<>();
|
||||
private final Set<String> deadURIs = new HashSet<>();
|
||||
|
||||
private long lastRefresh = 0l;
|
||||
private int refreshCounter = 0;
|
||||
|
||||
public void update() {
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
if(millis - lastRefresh > 10000l) {
|
||||
if(++refreshCounter < 10) {
|
||||
refresh();
|
||||
}else {
|
||||
lastRefresh = millis;
|
||||
}
|
||||
}else {
|
||||
Iterator<Entry<String,RelayWorldsQuery>> itr = lanServersQueryList.entrySet().iterator();
|
||||
while(itr.hasNext()) {
|
||||
Entry<String,RelayWorldsQuery> etr = itr.next();
|
||||
String uri = etr.getKey();
|
||||
RelayWorldsQuery q = etr.getValue();
|
||||
if(!q.isQueryOpen()) {
|
||||
itr.remove();
|
||||
if(q.isQueryFailed()) {
|
||||
deadURIs.add(uri);
|
||||
Iterator<LanServer> itr2 = lanServersList.iterator();
|
||||
while(itr2.hasNext()) {
|
||||
if(itr2.next().lanServerRelay.address.equals(uri)) {
|
||||
itr2.remove();
|
||||
}
|
||||
}
|
||||
}else {
|
||||
RelayServer rl = IntegratedServer.relayManager.getByURI(uri);
|
||||
Iterator<LanServer> itr2 = lanServersList.iterator();
|
||||
while(itr2.hasNext()) {
|
||||
LanServer l = itr2.next();
|
||||
if(l.lanServerRelay.address.equals(uri)) {
|
||||
l.flagged = false;
|
||||
}
|
||||
}
|
||||
if(rl != null) {
|
||||
Iterator<LocalWorld> itr3 = q.getWorlds().iterator();
|
||||
yee: while(itr3.hasNext()) {
|
||||
LocalWorld l = itr3.next();
|
||||
itr2 = lanServersList.iterator();
|
||||
while(itr2.hasNext()) {
|
||||
LanServer l2 = itr2.next();
|
||||
if(l2.lanServerRelay.address.equals(uri) && l2.lanServerCode.equals(l.worldCode)) {
|
||||
l2.lanServerMotd = l.worldName;
|
||||
l2.flagged = true;
|
||||
continue yee;
|
||||
}
|
||||
}
|
||||
lanServersList.add(new LanServer(l.worldName, rl, l.worldCode));
|
||||
}
|
||||
}
|
||||
itr2 = lanServersList.iterator();
|
||||
while(itr2.hasNext()) {
|
||||
LanServer l = itr2.next();
|
||||
if(l.lanServerRelay.address.equals(uri)) {
|
||||
if(!l.flagged) {
|
||||
itr2.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void forceRefresh() {
|
||||
deadURIs.clear();
|
||||
refreshCounter = 0;
|
||||
refresh();
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
lastRefresh = EaglerAdapter.steadyTimeMillis();
|
||||
for(int i = 0, l = IntegratedServer.relayManager.count(); i < l; ++i) {
|
||||
RelayServer srv = IntegratedServer.relayManager.get(i);
|
||||
if(!lanServersQueryList.containsKey(srv.address) && !deadURIs.contains(srv.address)) {
|
||||
lanServersQueryList.put(srv.address, EaglerAdapter.openRelayWorldsQuery(srv.address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public LanServer getServer(int idx) {
|
||||
return lanServersList.get(idx);
|
||||
}
|
||||
|
||||
public int countServers() {
|
||||
return lanServersList.size();
|
||||
}
|
||||
|
||||
public class LanServer {
|
||||
|
||||
private String lanServerMotd;
|
||||
private RelayServer lanServerRelay;
|
||||
private String lanServerCode;
|
||||
|
||||
protected boolean flagged = true;
|
||||
|
||||
protected LanServer(String lanServerMotd, RelayServer lanServerRelay, String lanServerCode) {
|
||||
this.lanServerMotd = lanServerMotd;
|
||||
this.lanServerRelay = lanServerRelay;
|
||||
this.lanServerCode = lanServerCode;
|
||||
}
|
||||
|
||||
public String getLanServerMotd() {
|
||||
return lanServerMotd;
|
||||
}
|
||||
|
||||
public RelayServer getLanServerRelay() {
|
||||
return lanServerRelay;
|
||||
}
|
||||
|
||||
public String getLanServerCode() {
|
||||
return lanServerCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.src.Achievement;
|
||||
import net.minecraft.src.CompressedStreamTools;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
|
||||
public class LocalStorageManager {
|
||||
|
||||
public static NBTTagCompound achievementStorage = null;
|
||||
public static NBTTagCompound gameSettingsStorage = null;
|
||||
public static NBTTagCompound profileSettingsStorage = null;
|
||||
|
||||
public static void loadStorage() {
|
||||
byte[] a = EaglerAdapter.loadLocalStorage("a");
|
||||
byte[] g = EaglerAdapter.loadLocalStorage("g");
|
||||
byte[] p = EaglerAdapter.loadLocalStorage("p");
|
||||
|
||||
if(a != null) {
|
||||
try {
|
||||
achievementStorage = CompressedStreamTools.readUncompressed(a);
|
||||
}catch(IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if(g != null) {
|
||||
try {
|
||||
gameSettingsStorage = CompressedStreamTools.readUncompressed(g);
|
||||
}catch(IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if(p != null) {
|
||||
try {
|
||||
profileSettingsStorage = CompressedStreamTools.readUncompressed(p);
|
||||
}catch(IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if(achievementStorage == null) achievementStorage = new NBTTagCompound();
|
||||
if(gameSettingsStorage == null) gameSettingsStorage = new NBTTagCompound();
|
||||
if(profileSettingsStorage == null) profileSettingsStorage = new NBTTagCompound();
|
||||
|
||||
}
|
||||
|
||||
public static void saveStorageA() {
|
||||
try {
|
||||
EaglerAdapter.saveLocalStorage("a", CompressedStreamTools.writeUncompressed(achievementStorage));
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveStorageG() {
|
||||
try {
|
||||
EaglerAdapter.saveLocalStorage("g", CompressedStreamTools.writeUncompressed(gameSettingsStorage));
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveStorageP() {
|
||||
try {
|
||||
EaglerAdapter.saveLocalStorage("p", CompressedStreamTools.writeUncompressed(profileSettingsStorage));
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public static String dumpConfiguration() {
|
||||
try {
|
||||
return Base64.encodeBase64String(CompressedStreamTools.writeUncompressed(gameSettingsStorage));
|
||||
} catch(Throwable e) {
|
||||
return "<error>";
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasMadeAchievement(Achievement stat) {
|
||||
if(stat.parentAchievement != null && (!achievementStorage.getBoolean(stat.parentAchievement.statGuid))) {
|
||||
return false;
|
||||
}else {
|
||||
if(!achievementStorage.getBoolean(stat.statGuid)) {
|
||||
achievementStorage.setBoolean(stat.statGuid, true);
|
||||
saveStorageA();
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
160
src/main/java/net/lax1dude/eaglercraft/ModelBipedNewSkins.java
Normal file
160
src/main/java/net/lax1dude/eaglercraft/ModelBipedNewSkins.java
Normal file
@@ -0,0 +1,160 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.minecraft.src.Entity;
|
||||
import net.minecraft.src.ModelBiped;
|
||||
import net.minecraft.src.ModelRenderer;
|
||||
|
||||
public class ModelBipedNewSkins extends ModelBiped {
|
||||
/**
|
||||
* left arm
|
||||
*/
|
||||
public ModelRenderer field_178734_a;
|
||||
/**
|
||||
* right arm
|
||||
*/
|
||||
public ModelRenderer field_178732_b;
|
||||
/**
|
||||
* left leg
|
||||
*/
|
||||
public ModelRenderer field_178733_c;
|
||||
/**
|
||||
* right leg
|
||||
*/
|
||||
public ModelRenderer field_178731_d;
|
||||
/**
|
||||
* jacket
|
||||
*/
|
||||
public ModelRenderer field_178730_v;
|
||||
private ModelRenderer field_178729_w;
|
||||
private ModelRenderer field_178736_x;
|
||||
private boolean isAlex;
|
||||
|
||||
public ModelBipedNewSkins(float p_i46304_1_, boolean p_i46304_2_)
|
||||
{
|
||||
super(p_i46304_1_, 0.0F, 64, 64);
|
||||
this.isAlex = p_i46304_2_;
|
||||
this.field_178736_x = new ModelRenderer(this, 24, 0);
|
||||
this.field_178736_x.addBox(-3.0F, -6.0F, -1.0F, 6, 6, 1, p_i46304_1_);
|
||||
this.field_178729_w = new ModelRenderer(this, 0, 0);
|
||||
this.field_178729_w.setTextureSize(64, 32);
|
||||
this.field_178729_w.addBox(-5.0F, 0.0F, -1.0F, 10, 16, 1, p_i46304_1_);
|
||||
|
||||
if (p_i46304_2_)
|
||||
{
|
||||
this.bipedLeftArm = new ModelRenderer(this, 32, 48);
|
||||
this.bipedLeftArm.addBox(-1.0F, -2.0F, -2.0F, 3, 12, 4, p_i46304_1_);
|
||||
this.bipedLeftArm.setRotationPoint(5.0F, 2.5F, 0.0F);
|
||||
this.bipedRightArm = new ModelRenderer(this, 40, 16);
|
||||
this.bipedRightArm.addBox(-2.0F, -2.0F, -2.0F, 3, 12, 4, p_i46304_1_);
|
||||
this.bipedRightArm.setRotationPoint(-5.0F, 2.5F, 0.0F);
|
||||
this.field_178734_a = new ModelRenderer(this, 48, 48);
|
||||
this.field_178734_a.addBox(-1.0F, -2.0F, -2.0F, 3, 12, 4, p_i46304_1_ + 0.25F);
|
||||
this.field_178734_a.setRotationPoint(5.0F, 2.5F, 0.0F);
|
||||
this.field_178732_b = new ModelRenderer(this, 40, 32);
|
||||
this.field_178732_b.addBox(-2.0F, -2.0F, -2.0F, 3, 12, 4, p_i46304_1_ + 0.25F);
|
||||
this.field_178732_b.setRotationPoint(-5.0F, 2.5F, 10.0F);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bipedLeftArm = new ModelRenderer(this, 32, 48);
|
||||
this.bipedLeftArm.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, p_i46304_1_);
|
||||
this.bipedLeftArm.setRotationPoint(5.0F, 2.0F, 0.0F);
|
||||
this.field_178734_a = new ModelRenderer(this, 48, 48);
|
||||
this.field_178734_a.addBox(-1.0F, -2.0F, -2.0F, 4, 12, 4, p_i46304_1_ + 0.25F);
|
||||
this.field_178734_a.setRotationPoint(5.0F, 2.0F, 0.0F);
|
||||
this.field_178732_b = new ModelRenderer(this, 40, 32);
|
||||
this.field_178732_b.addBox(-3.0F, -2.0F, -2.0F, 4, 12, 4, p_i46304_1_ + 0.25F);
|
||||
this.field_178732_b.setRotationPoint(-5.0F, 2.0F, 10.0F);
|
||||
}
|
||||
|
||||
this.bipedLeftLeg = new ModelRenderer(this, 16, 48);
|
||||
this.bipedLeftLeg.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, p_i46304_1_);
|
||||
this.bipedLeftLeg.setRotationPoint(1.9F, 12.0F, 0.0F);
|
||||
this.field_178733_c = new ModelRenderer(this, 0, 48);
|
||||
this.field_178733_c.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, p_i46304_1_ + 0.25F);
|
||||
this.field_178733_c.setRotationPoint(1.9F, 12.0F, 0.0F);
|
||||
this.field_178731_d = new ModelRenderer(this, 0, 32);
|
||||
this.field_178731_d.addBox(-2.0F, 0.0F, -2.0F, 4, 12, 4, p_i46304_1_ + 0.25F);
|
||||
this.field_178731_d.setRotationPoint(-1.9F, 12.0F, 0.0F);
|
||||
this.field_178730_v = new ModelRenderer(this, 16, 32);
|
||||
this.field_178730_v.addBox(-4.0F, 0.0F, -2.0F, 8, 12, 4, p_i46304_1_ + 0.25F);
|
||||
this.field_178730_v.setRotationPoint(0.0F, 0.0F, 0.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the models various rotation angles then renders the model.
|
||||
*/
|
||||
public void render(Entity p_78088_1_, float p_78088_2_, float p_78088_3_, float p_78088_4_, float p_78088_5_, float p_78088_6_, float p_78088_7_) {
|
||||
super.render(p_78088_1_, p_78088_2_, p_78088_3_, p_78088_4_, p_78088_5_, p_78088_6_, p_78088_7_);
|
||||
//EaglerAdapter.glPushMatrix();
|
||||
|
||||
//if (p_78088_1_ != null && p_78088_1_.isSneaking()) {
|
||||
// EaglerAdapter.glTranslatef(0.0F, 0.2F, 0.0F);
|
||||
//}
|
||||
|
||||
this.field_178733_c.render(p_78088_7_);
|
||||
this.field_178731_d.render(p_78088_7_);
|
||||
this.field_178734_a.render(p_78088_7_);
|
||||
this.field_178732_b.render(p_78088_7_);
|
||||
this.field_178730_v.render(p_78088_7_);
|
||||
|
||||
//EaglerAdapter.glPopMatrix();
|
||||
}
|
||||
|
||||
public void func_178727_b(float p_178727_1_) {
|
||||
func_178685_a(this.bipedHead, this.field_178736_x);
|
||||
this.field_178736_x.rotationPointX = 0.0F;
|
||||
this.field_178736_x.rotationPointY = 0.0F;
|
||||
this.field_178736_x.render(p_178727_1_);
|
||||
}
|
||||
|
||||
public void func_178728_c(float p_178728_1_) {
|
||||
this.field_178729_w.render(p_178728_1_);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the model's various rotation angles. For bipeds, par1 and par2 are used
|
||||
* for animating the movement of arms and legs, where par1 represents the
|
||||
* time(so that arms and legs swing back and forth) and par2 represents how
|
||||
* "far" arms and legs can swing at most.
|
||||
*/
|
||||
public void setRotationAngles(float p_78087_1_, float p_78087_2_, float p_78087_3_, float p_78087_4_, float p_78087_5_, float p_78087_6_, Entity p_78087_7_) {
|
||||
super.setRotationAngles(p_78087_1_, p_78087_2_, p_78087_3_, p_78087_4_, p_78087_5_, p_78087_6_, p_78087_7_);
|
||||
func_178685_a(this.bipedLeftLeg, this.field_178733_c);
|
||||
func_178685_a(this.bipedRightLeg, this.field_178731_d);
|
||||
func_178685_a(this.bipedLeftArm, this.field_178734_a);
|
||||
func_178685_a(this.bipedRightArm, this.field_178732_b);
|
||||
func_178685_a(this.bipedBody, this.field_178730_v);
|
||||
}
|
||||
|
||||
public void func_178725_a() {
|
||||
this.bipedRightArm.render(0.0625F);
|
||||
this.field_178732_b.render(0.0625F);
|
||||
}
|
||||
|
||||
public void func_178726_b() {
|
||||
this.bipedLeftArm.render(0.0625F);
|
||||
this.field_178734_a.render(0.0625F);
|
||||
}
|
||||
|
||||
public void postRenderHiddenArm(float p_178718_1_) {
|
||||
if (this.isAlex) {
|
||||
++this.bipedRightArm.rotationPointX;
|
||||
this.bipedRightArm.postRender(p_178718_1_);
|
||||
--this.bipedRightArm.rotationPointX;
|
||||
} else {
|
||||
this.bipedRightArm.postRender(p_178718_1_);
|
||||
}
|
||||
}
|
||||
|
||||
public static void func_178685_a(ModelRenderer p_178685_0_, ModelRenderer p_178685_1_)
|
||||
{
|
||||
p_178685_1_.rotateAngleX = p_178685_0_.rotateAngleX;
|
||||
p_178685_1_.rotateAngleY = p_178685_0_.rotateAngleY;
|
||||
p_178685_1_.rotateAngleZ = p_178685_0_.rotateAngleZ;
|
||||
p_178685_1_.rotationPointX = p_178685_0_.rotationPointX;
|
||||
p_178685_1_.rotationPointY = p_178685_0_.rotationPointY;
|
||||
p_178685_1_.rotationPointZ = p_178685_0_.rotationPointZ;
|
||||
}
|
||||
|
||||
}
|
||||
23
src/main/java/net/lax1dude/eaglercraft/ModelLocation.java
Normal file
23
src/main/java/net/lax1dude/eaglercraft/ModelLocation.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.glemu.HighPolyMesh;
|
||||
|
||||
public class ModelLocation {
|
||||
|
||||
public final String path;
|
||||
private boolean loadAttempted = false;
|
||||
private HighPolyMesh mesh;
|
||||
|
||||
public ModelLocation(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public HighPolyMesh getModel() {
|
||||
if(!loadAttempted) {
|
||||
mesh = EaglerAdapter.loadMesh(path);
|
||||
loadAttempted = true;
|
||||
}
|
||||
return mesh;
|
||||
}
|
||||
|
||||
}
|
||||
412
src/main/java/net/lax1dude/eaglercraft/NoCatchParse.java
Normal file
412
src/main/java/net/lax1dude/eaglercraft/NoCatchParse.java
Normal file
@@ -0,0 +1,412 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public class NoCatchParse {
|
||||
|
||||
public static final int INT_EXCEPTION = Integer.MIN_VALUE;
|
||||
public static final float FLOAT_EXCEPTION = Float.NaN;
|
||||
public static final double DOUBLE_EXCEPTION = Double.NaN;
|
||||
|
||||
public static int parseInt(String s) {
|
||||
return parseInt(s, 10, false, INT_EXCEPTION);
|
||||
}
|
||||
|
||||
public static int parseInt(String s, int radix) {
|
||||
return parseInt(s, radix, false, INT_EXCEPTION);
|
||||
}
|
||||
|
||||
public static int parseInt(String s, int radix, boolean log) {
|
||||
return parseInt(s, radix, log, INT_EXCEPTION);
|
||||
}
|
||||
|
||||
public static int parseInt(String s, int radix, boolean log, int exceptionResult) {
|
||||
if (s == null) {
|
||||
if (log) {
|
||||
System.err.println("parseInt: string was null");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
if (s.isEmpty()) {
|
||||
if (log) {
|
||||
System.err.println("parseInt: string was empty");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
|
||||
if (log) {
|
||||
System.err.println("parseInt: invalid radix '" + radix + "'");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
tryFail: {
|
||||
int result = 0;
|
||||
boolean negative = false;
|
||||
int i = 0, len = s.length();
|
||||
int limit = -Integer.MAX_VALUE;
|
||||
int multmin;
|
||||
int digit;
|
||||
|
||||
if (len > 0) {
|
||||
char firstChar = s.charAt(0);
|
||||
if (firstChar < '0') { // Possible leading "+" or "-"
|
||||
if (firstChar == '-') {
|
||||
negative = true;
|
||||
limit = Integer.MIN_VALUE;
|
||||
} else if (firstChar != '+')
|
||||
break tryFail;
|
||||
|
||||
if (len == 1)
|
||||
break tryFail;
|
||||
i++;
|
||||
}
|
||||
multmin = limit / radix;
|
||||
while (i < len) {
|
||||
// Accumulating negatively avoids surprises near MAX_VALUE
|
||||
digit = Character.digit(s.charAt(i++), radix);
|
||||
if (digit < 0 || result < multmin) {
|
||||
|
||||
break tryFail;
|
||||
}
|
||||
result *= radix;
|
||||
if (result < limit + digit) {
|
||||
break tryFail;
|
||||
}
|
||||
result -= digit;
|
||||
}
|
||||
} else {
|
||||
break tryFail;
|
||||
}
|
||||
int ret = negative ? result : -result;
|
||||
if (ret == exceptionResult) {
|
||||
System.err.println(
|
||||
"parseInt: number '" + s + "' was parsed successfully but it is equal to exceptionResult");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
if (log) {
|
||||
System.err.println("parseInt: cannot parse '" + s + "'");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
public static double parseDouble(String s) {
|
||||
return parseDouble(s, false, DOUBLE_EXCEPTION);
|
||||
}
|
||||
|
||||
public static double parseDouble(String s, boolean log) {
|
||||
return parseDouble(s, log, DOUBLE_EXCEPTION);
|
||||
}
|
||||
|
||||
public static double parseDouble(String s, boolean log, double exceptionResult) {
|
||||
if (s == null) {
|
||||
if (log) {
|
||||
System.err.println("parseDouble: string was null");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
if (s.isEmpty()) {
|
||||
if (log) {
|
||||
System.err.println("parseDouble: string was empty");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
tryFail: {
|
||||
int start = 0;
|
||||
int end = s.length();
|
||||
while (s.charAt(start) <= ' ') {
|
||||
if (++start == end) {
|
||||
break tryFail;
|
||||
}
|
||||
}
|
||||
while (s.charAt(end - 1) <= ' ') {
|
||||
--end;
|
||||
}
|
||||
|
||||
boolean negative = false;
|
||||
int index = start;
|
||||
if (s.charAt(index) == '-') {
|
||||
++index;
|
||||
negative = true;
|
||||
} else if (s.charAt(index) == '+') {
|
||||
++index;
|
||||
}
|
||||
if (index == end) {
|
||||
break tryFail;
|
||||
}
|
||||
char c = s.charAt(index);
|
||||
|
||||
long mantissa = 0;
|
||||
int exp = 0;
|
||||
boolean hasOneDigit = false;
|
||||
if (c != '.') {
|
||||
hasOneDigit = true;
|
||||
if (c < '0' || c > '9') {
|
||||
break tryFail;
|
||||
}
|
||||
while (index < end && s.charAt(index) == '0') {
|
||||
++index;
|
||||
}
|
||||
while (index < end) {
|
||||
c = s.charAt(index);
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
if (mantissa < Long.MAX_VALUE / 10 - 9) {
|
||||
mantissa = mantissa * 10 + (c - '0');
|
||||
} else {
|
||||
++exp;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
if (index < end && s.charAt(index) == '.') {
|
||||
++index;
|
||||
while (index < end) {
|
||||
c = s.charAt(index);
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
if (mantissa < Long.MAX_VALUE / 10 - 9) {
|
||||
mantissa = mantissa * 10 + (c - '0');
|
||||
--exp;
|
||||
}
|
||||
++index;
|
||||
hasOneDigit = true;
|
||||
}
|
||||
if (!hasOneDigit) {
|
||||
break tryFail;
|
||||
}
|
||||
}
|
||||
if (index < end) {
|
||||
c = s.charAt(index);
|
||||
if (c != 'e' && c != 'E') {
|
||||
break tryFail;
|
||||
}
|
||||
++index;
|
||||
boolean negativeExp = false;
|
||||
if (index == end) {
|
||||
break tryFail;
|
||||
}
|
||||
if (s.charAt(index) == '-') {
|
||||
++index;
|
||||
negativeExp = true;
|
||||
} else if (s.charAt(index) == '+') {
|
||||
++index;
|
||||
}
|
||||
int numExp = 0;
|
||||
hasOneDigit = false;
|
||||
while (index < end) {
|
||||
c = s.charAt(index);
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
numExp = 10 * numExp + (c - '0');
|
||||
hasOneDigit = true;
|
||||
++index;
|
||||
}
|
||||
if (!hasOneDigit) {
|
||||
break tryFail;
|
||||
}
|
||||
if (negativeExp) {
|
||||
numExp = -numExp;
|
||||
}
|
||||
exp += numExp;
|
||||
}
|
||||
if (exp > 308 || exp == 308 && mantissa > 17976931348623157L) {
|
||||
return !negative ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
|
||||
}
|
||||
if (negative) {
|
||||
mantissa = -mantissa;
|
||||
}
|
||||
return mantissa * doubleDecimalExponent(exp);
|
||||
}
|
||||
if (log) {
|
||||
System.err.println("parseDouble: cannot parse '" + s + "'");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
public static double doubleDecimalExponent(int n) {
|
||||
double d;
|
||||
if (n < 0) {
|
||||
d = 0.1;
|
||||
n = -n;
|
||||
} else {
|
||||
d = 10;
|
||||
}
|
||||
double result = 1;
|
||||
while (n != 0) {
|
||||
if (n % 2 != 0) {
|
||||
result *= d;
|
||||
}
|
||||
d *= d;
|
||||
n /= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float parseFloat(String s) {
|
||||
return parseFloat(s, false, FLOAT_EXCEPTION);
|
||||
}
|
||||
|
||||
public static float parseFloat(String s, boolean log) {
|
||||
return parseFloat(s, log, FLOAT_EXCEPTION);
|
||||
}
|
||||
|
||||
public static float parseFloat(String s, boolean log, float exceptionResult) {
|
||||
if (s == null) {
|
||||
if (log) {
|
||||
System.err.println("parseFloat: string was null");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
if (s.isEmpty()) {
|
||||
if (log) {
|
||||
System.err.println("parseFloat: string was empty");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
tryFail: {
|
||||
int start = 0;
|
||||
int end = s.length();
|
||||
while (s.charAt(start) <= ' ') {
|
||||
if (++start == end) {
|
||||
break tryFail;
|
||||
}
|
||||
}
|
||||
while (s.charAt(end - 1) <= ' ') {
|
||||
--end;
|
||||
}
|
||||
|
||||
boolean negative = false;
|
||||
int index = start;
|
||||
if (s.charAt(index) == '-') {
|
||||
++index;
|
||||
negative = true;
|
||||
} else if (s.charAt(index) == '+') {
|
||||
++index;
|
||||
}
|
||||
if (index == end) {
|
||||
break tryFail;
|
||||
}
|
||||
char c = s.charAt(index);
|
||||
|
||||
int mantissa = 0;
|
||||
int exp = 0;
|
||||
|
||||
boolean hasOneDigit = false;
|
||||
if (c != '.') {
|
||||
hasOneDigit = true;
|
||||
if (c < '0' || c > '9') {
|
||||
break tryFail;
|
||||
}
|
||||
|
||||
while (index < end && s.charAt(index) == '0') {
|
||||
++index;
|
||||
}
|
||||
while (index < end) {
|
||||
c = s.charAt(index);
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
if (mantissa < (Integer.MAX_VALUE / 10) - 9) {
|
||||
mantissa = mantissa * 10 + (c - '0');
|
||||
} else {
|
||||
++exp;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < end && s.charAt(index) == '.') {
|
||||
++index;
|
||||
while (index < end) {
|
||||
c = s.charAt(index);
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
if (mantissa < (Integer.MAX_VALUE / 10) - 9) {
|
||||
mantissa = mantissa * 10 + (c - '0');
|
||||
--exp;
|
||||
}
|
||||
++index;
|
||||
hasOneDigit = true;
|
||||
}
|
||||
if (!hasOneDigit) {
|
||||
break tryFail;
|
||||
}
|
||||
}
|
||||
if (index < end) {
|
||||
c = s.charAt(index);
|
||||
if (c != 'e' && c != 'E') {
|
||||
break tryFail;
|
||||
}
|
||||
++index;
|
||||
boolean negativeExp = false;
|
||||
if (index == end) {
|
||||
break tryFail;
|
||||
}
|
||||
if (s.charAt(index) == '-') {
|
||||
++index;
|
||||
negativeExp = true;
|
||||
} else if (s.charAt(index) == '+') {
|
||||
++index;
|
||||
}
|
||||
int numExp = 0;
|
||||
hasOneDigit = false;
|
||||
while (index < end) {
|
||||
c = s.charAt(index);
|
||||
if (c < '0' || c > '9') {
|
||||
break;
|
||||
}
|
||||
numExp = 10 * numExp + (c - '0');
|
||||
hasOneDigit = true;
|
||||
++index;
|
||||
}
|
||||
if (!hasOneDigit) {
|
||||
break tryFail;
|
||||
}
|
||||
if (negativeExp) {
|
||||
numExp = -numExp;
|
||||
}
|
||||
exp += numExp;
|
||||
}
|
||||
if (exp > 38 || exp == 38 && mantissa > 34028234) {
|
||||
return !negative ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY;
|
||||
}
|
||||
if (negative) {
|
||||
mantissa = -mantissa;
|
||||
}
|
||||
return mantissa * floatDecimalExponent(exp);
|
||||
}
|
||||
if (log) {
|
||||
System.err.println("parseFloat: cannot parse '" + s + "'");
|
||||
}
|
||||
return exceptionResult;
|
||||
}
|
||||
|
||||
private static float floatDecimalExponent(int n) {
|
||||
double d;
|
||||
if (n < 0) {
|
||||
d = 0.1;
|
||||
n = -n;
|
||||
} else {
|
||||
d = 10;
|
||||
}
|
||||
double result = 1;
|
||||
while (n != 0) {
|
||||
if (n % 2 != 0) {
|
||||
result *= d;
|
||||
}
|
||||
d *= d;
|
||||
n /= 2;
|
||||
}
|
||||
return (float) result;
|
||||
}
|
||||
}
|
||||
13
src/main/java/net/lax1dude/eaglercraft/PKT.java
Normal file
13
src/main/java/net/lax1dude/eaglercraft/PKT.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public class PKT {
|
||||
|
||||
public final String channel;
|
||||
public final byte[] data;
|
||||
|
||||
public PKT(String channel, byte[] data) {
|
||||
this.channel = channel;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
97
src/main/java/net/lax1dude/eaglercraft/ProfileUUID.java
Normal file
97
src/main/java/net/lax1dude/eaglercraft/ProfileUUID.java
Normal file
@@ -0,0 +1,97 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public class ProfileUUID {
|
||||
|
||||
public final long msb;
|
||||
public final long lsb;
|
||||
|
||||
public ProfileUUID(long msb, long lsb) {
|
||||
this.msb = msb;
|
||||
this.lsb = lsb;
|
||||
}
|
||||
|
||||
public ProfileUUID(byte[] uuid) {
|
||||
long msb = 0;
|
||||
long lsb = 0;
|
||||
for (int i = 0; i < 8; i++)
|
||||
msb = (msb << 8) | (uuid[i] & 0xff);
|
||||
for (int i = 8; i < 16; i++)
|
||||
lsb = (lsb << 8) | (uuid[i] & 0xff);
|
||||
this.msb = msb;
|
||||
this.lsb = lsb;
|
||||
}
|
||||
|
||||
public ProfileUUID(String uuid) {
|
||||
String[] components = uuid.split("-");
|
||||
if (components.length != 5)
|
||||
throw new IllegalArgumentException("Invalid UUID string: " + uuid);
|
||||
for (int i = 0; i < 5; i++)
|
||||
components[i] = "0x" + components[i];
|
||||
|
||||
long mostSigBits = Long.decode(components[0]).longValue();
|
||||
mostSigBits <<= 16;
|
||||
mostSigBits |= Long.decode(components[1]).longValue();
|
||||
mostSigBits <<= 16;
|
||||
mostSigBits |= Long.decode(components[2]).longValue();
|
||||
|
||||
long leastSigBits = Long.decode(components[3]).longValue();
|
||||
leastSigBits <<= 48;
|
||||
leastSigBits |= Long.decode(components[4]).longValue();
|
||||
|
||||
this.msb = mostSigBits;
|
||||
this.lsb = leastSigBits;
|
||||
}
|
||||
|
||||
private static byte long7(long x) { return (byte)(x >> 56); }
|
||||
private static byte long6(long x) { return (byte)(x >> 48); }
|
||||
private static byte long5(long x) { return (byte)(x >> 40); }
|
||||
private static byte long4(long x) { return (byte)(x >> 32); }
|
||||
private static byte long3(long x) { return (byte)(x >> 24); }
|
||||
private static byte long2(long x) { return (byte)(x >> 16); }
|
||||
private static byte long1(long x) { return (byte)(x >> 8); }
|
||||
private static byte long0(long x) { return (byte)(x ); }
|
||||
|
||||
public byte[] getBytes() {
|
||||
byte[] ret = new byte[16];
|
||||
ret[0] = long7(msb);
|
||||
ret[1] = long6(msb);
|
||||
ret[2] = long5(msb);
|
||||
ret[3] = long4(msb);
|
||||
ret[4] = long3(msb);
|
||||
ret[5] = long2(msb);
|
||||
ret[6] = long1(msb);
|
||||
ret[7] = long0(msb);
|
||||
ret[8] = long7(lsb);
|
||||
ret[9] = long6(lsb);
|
||||
ret[10] = long5(lsb);
|
||||
ret[11] = long4(lsb);
|
||||
ret[12] = long3(lsb);
|
||||
ret[13] = long2(lsb);
|
||||
ret[14] = long1(lsb);
|
||||
ret[15] = long0(lsb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (digits(msb >> 32, 8) + "-" + digits(msb >> 16, 4) + "-" + digits(msb, 4) + "-"
|
||||
+ digits(lsb >> 48, 4) + "-" + digits(lsb, 12));
|
||||
}
|
||||
|
||||
private static String digits(long val, int digits) {
|
||||
long hi = 1L << (digits * 4);
|
||||
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
long hilo = msb ^ lsb;
|
||||
return ((int) (hilo >> 32)) ^ (int) hilo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof ProfileUUID) && ((ProfileUUID)o).lsb == lsb && ((ProfileUUID)o).msb == msb;
|
||||
}
|
||||
|
||||
}
|
||||
15
src/main/java/net/lax1dude/eaglercraft/RelayEntry.java
Normal file
15
src/main/java/net/lax1dude/eaglercraft/RelayEntry.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
public class RelayEntry {
|
||||
|
||||
public final String address;
|
||||
public final String comment;
|
||||
public final boolean primary;
|
||||
|
||||
public RelayEntry(String address, String comment, boolean primary) {
|
||||
this.address = address;
|
||||
this.comment = comment;
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
}
|
||||
334
src/main/java/net/lax1dude/eaglercraft/RelayManager.java
Normal file
334
src/main/java/net/lax1dude/eaglercraft/RelayManager.java
Normal file
@@ -0,0 +1,334 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket00Handshake;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacketFFErrorCode;
|
||||
import net.minecraft.src.NBTBase;
|
||||
import net.minecraft.src.NBTTagCompound;
|
||||
import net.minecraft.src.NBTTagList;
|
||||
|
||||
public class RelayManager {
|
||||
|
||||
private final List<RelayServer> relays = new ArrayList<>();
|
||||
private long lastPingThrough = 0l;
|
||||
|
||||
public void load(NBTTagList relayConfig) {
|
||||
relays.clear();
|
||||
if(relayConfig != null && relayConfig.tagCount() > 0) {
|
||||
boolean gotAPrimary = false;
|
||||
for(int i = 0, l = relayConfig.tagCount(); i < l; ++i) {
|
||||
NBTBase relay = relayConfig.tagAt(i);
|
||||
if(relay instanceof NBTTagCompound) {
|
||||
NBTTagCompound relayee = (NBTTagCompound) relay;
|
||||
boolean p = relayee.getBoolean("primary");
|
||||
if(p) {
|
||||
if(gotAPrimary) {
|
||||
p = false;
|
||||
}else {
|
||||
gotAPrimary = true;
|
||||
}
|
||||
}
|
||||
relays.add(new RelayServer(relayee.getString("addr"), relayee.getString("comment"), p));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(relays.size() == 0) {
|
||||
for(int i = 0, l = ConfigConstants.relays.size(); i < l; ++i) {
|
||||
relays.add(new RelayServer(ConfigConstants.relays.get(i)));
|
||||
}
|
||||
}
|
||||
sort();
|
||||
}
|
||||
|
||||
public void save() {
|
||||
NBTTagList lst = new NBTTagList();
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
RelayServer srv = relays.get(i);
|
||||
NBTTagCompound etr = new NBTTagCompound();
|
||||
etr.setString("addr", srv.address);
|
||||
etr.setString("comment", srv.comment);
|
||||
etr.setBoolean("primary", srv.isPrimary());
|
||||
lst.appendTag(etr);
|
||||
}
|
||||
LocalStorageManager.gameSettingsStorage.setTag("relays", lst);
|
||||
LocalStorageManager.saveStorageG();
|
||||
}
|
||||
|
||||
private void sort() {
|
||||
if(relays.size() == 0) {
|
||||
return;
|
||||
}
|
||||
int j = -1;
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
if(relays.get(i).isPrimary()) {
|
||||
if(j == -1) {
|
||||
j = i;
|
||||
}else {
|
||||
relays.get(i).setPrimary(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(j == -1) {
|
||||
boolean found = false;
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
RelayServer srv = relays.get(i);
|
||||
if(srv.getPing() > 0l) {
|
||||
found = true;
|
||||
srv.setPrimary(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found) {
|
||||
relays.get(0).setPrimary(true);
|
||||
}
|
||||
}else {
|
||||
RelayServer srv = relays.remove(j);
|
||||
relays.add(0, srv);
|
||||
}
|
||||
}
|
||||
|
||||
public void ping() {
|
||||
lastPingThrough = EaglerAdapter.steadyTimeMillis();
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
relays.get(i).ping();
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
relays.get(i).update();
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
relays.get(i).close();
|
||||
}
|
||||
}
|
||||
|
||||
public int count() {
|
||||
return relays.size();
|
||||
}
|
||||
|
||||
public RelayServer get(int idx) {
|
||||
return relays.get(idx);
|
||||
}
|
||||
|
||||
public void add(String addr, String comment, boolean primary) {
|
||||
lastPingThrough = 0l;
|
||||
int i = relays.size();
|
||||
relays.add(new RelayServer(addr, comment, false));
|
||||
if(primary) {
|
||||
setPrimary0(i);
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
public void addNew(String addr, String comment, boolean primary) {
|
||||
lastPingThrough = 0l;
|
||||
int i = relays.size();
|
||||
int j = primary || i == 0 ? 0 : 1;
|
||||
RelayServer newServer = new RelayServer(addr, comment, false);
|
||||
relays.add(j, newServer);
|
||||
newServer.ping();
|
||||
if(primary) {
|
||||
setPrimary0(j);
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
public void setPrimary(int idx) {
|
||||
setPrimary0(idx);
|
||||
save();
|
||||
}
|
||||
|
||||
private void setPrimary0(int idx) {
|
||||
if(idx >= 0 && idx < relays.size()) {
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
RelayServer srv = relays.get(i);
|
||||
if(srv.isPrimary()) {
|
||||
srv.setPrimary(false);
|
||||
}
|
||||
}
|
||||
RelayServer pr = relays.remove(idx);
|
||||
pr.setPrimary(true);
|
||||
relays.add(0, pr);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(int idx) {
|
||||
RelayServer srv = relays.remove(idx);
|
||||
srv.close();
|
||||
sort();
|
||||
save();
|
||||
}
|
||||
|
||||
public RelayServer getPrimary() {
|
||||
if(relays.size() > 0) {
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
RelayServer srv = relays.get(i);
|
||||
if(srv.isPrimary()) {
|
||||
return srv;
|
||||
}
|
||||
}
|
||||
sort();
|
||||
save();
|
||||
return getPrimary();
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public RelayServerSocket connectHandshake(RelayServer relay, int type, String code) {
|
||||
RelayServerSocket sock = relay.openSocket();
|
||||
while(!sock.isClosed()) {
|
||||
if(sock.isOpen()) {
|
||||
sock.writePacket(new IPacket00Handshake(type, IntegratedServer.preferredRelayVersion, code));
|
||||
while(!sock.isClosed()) {
|
||||
IPacket pkt = sock.nextPacket();
|
||||
if(pkt != null) {
|
||||
if(pkt instanceof IPacket00Handshake) {
|
||||
return sock;
|
||||
}else if(pkt instanceof IPacketFFErrorCode) {
|
||||
IPacketFFErrorCode ipkt = (IPacketFFErrorCode) pkt;
|
||||
System.err.println("Relay [" + relay.address + "] failed: " + IPacketFFErrorCode.code2string(ipkt.code) +
|
||||
"(" + ipkt.code + "): " + ipkt.desc);
|
||||
Throwable t;
|
||||
while((t = sock.getException()) != null) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
sock.close();
|
||||
return null;
|
||||
}else {
|
||||
System.err.println("Relay [" + relay.address + "] unexpected packet: " + pkt.getClass().getSimpleName());
|
||||
sock.close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
EaglerAdapter.sleep(20);
|
||||
}
|
||||
}
|
||||
EaglerAdapter.sleep(20);
|
||||
}
|
||||
System.err.println("Relay [" + relay.address + "] connection failed!");
|
||||
Throwable t;
|
||||
while((t = sock.getException()) != null) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final List<RelayServer> brokenServers = new LinkedList<>();
|
||||
|
||||
public RelayServerSocket getWorkingRelay(Consumer<String> progressCallback, int type, String code) {
|
||||
brokenServers.clear();
|
||||
if(relays.size() > 0) {
|
||||
long millis = EaglerAdapter.steadyTimeMillis();
|
||||
if(millis - lastPingThrough < 10000l) {
|
||||
RelayServer relay = getPrimary();
|
||||
if(relay.getPing() > 0l && relay.getPingCompatible().isCompatible()) {
|
||||
progressCallback.accept(relay.address);
|
||||
RelayServerSocket sock = connectHandshake(relay, type, code);
|
||||
if(sock != null) {
|
||||
if(!sock.isFailed()) {
|
||||
return sock;
|
||||
}
|
||||
}else {
|
||||
brokenServers.add(relay);
|
||||
}
|
||||
}
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
RelayServer relayEtr = relays.get(i);
|
||||
if(relayEtr != relay) {
|
||||
if(relayEtr.getPing() > 0l && relayEtr.getPingCompatible().isCompatible()) {
|
||||
progressCallback.accept(relayEtr.address);
|
||||
RelayServerSocket sock = connectHandshake(relayEtr, type, code);
|
||||
if(sock != null) {
|
||||
if(!sock.isFailed()) {
|
||||
return sock;
|
||||
}
|
||||
}else {
|
||||
brokenServers.add(relayEtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return getWorkingCodeRelayActive(progressCallback, type, code);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private RelayServerSocket getWorkingCodeRelayActive(Consumer<String> progressCallback, int type, String code) {
|
||||
if(relays.size() > 0) {
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
RelayServer srv = relays.get(i);
|
||||
if(!brokenServers.contains(srv)) {
|
||||
progressCallback.accept(srv.address);
|
||||
RelayServerSocket sock = connectHandshake(srv, type, code);
|
||||
if(sock != null) {
|
||||
if(!sock.isFailed()) {
|
||||
return sock;
|
||||
}
|
||||
}else {
|
||||
brokenServers.add(srv);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void loadDefaults() {
|
||||
int setPrimary = relays.size();
|
||||
eee: for(RelayEntry etr : ConfigConstants.relays) {
|
||||
for(RelayServer exEtr : relays) {
|
||||
if(exEtr.address.equalsIgnoreCase(etr.address)) {
|
||||
continue eee;
|
||||
}
|
||||
}
|
||||
relays.add(new RelayServer(etr));
|
||||
}
|
||||
setPrimary(setPrimary);
|
||||
}
|
||||
|
||||
public String makeNewRelayName() {
|
||||
String str = "Relay Server #" + (relays.size() + 1);
|
||||
for(int i = relays.size() + 2, l = relays.size() + 50; i < l; ++i) {
|
||||
if(str.equalsIgnoreCase("Relay Server #" + i)) {
|
||||
str = "Relay Server #" + (i + 1);
|
||||
}
|
||||
}
|
||||
eee: while(true) {
|
||||
for(int i = 0, l = relays.size(); i < l; ++i) {
|
||||
if(str.equalsIgnoreCase(relays.get(i).comment)) {
|
||||
str = str + "_";
|
||||
continue eee;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public RelayServer getByURI(String uri) {
|
||||
Iterator<RelayServer> itr = relays.iterator();
|
||||
while(itr.hasNext()) {
|
||||
RelayServer rl = itr.next();
|
||||
if(rl.address.equals(uri)) {
|
||||
return rl;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
26
src/main/java/net/lax1dude/eaglercraft/RelayQuery.java
Normal file
26
src/main/java/net/lax1dude/eaglercraft/RelayQuery.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit;
|
||||
|
||||
public interface RelayQuery {
|
||||
|
||||
public static enum VersionMismatch {
|
||||
COMPATIBLE, CLIENT_OUTDATED, RELAY_OUTDATED, UNKNOWN;
|
||||
public boolean isCompatible() {
|
||||
return this == COMPATIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isQueryOpen();
|
||||
boolean isQueryFailed();
|
||||
RateLimit isQueryRateLimit();
|
||||
void close();
|
||||
|
||||
int getVersion();
|
||||
String getComment();
|
||||
String getBrand();
|
||||
long getPing();
|
||||
|
||||
VersionMismatch getCompatible();
|
||||
|
||||
}
|
||||
118
src/main/java/net/lax1dude/eaglercraft/RelayServer.java
Normal file
118
src/main/java/net/lax1dude/eaglercraft/RelayServer.java
Normal file
@@ -0,0 +1,118 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch;
|
||||
import net.minecraft.src.Minecraft;
|
||||
|
||||
public class RelayServer {
|
||||
|
||||
public final String address;
|
||||
public final String comment;
|
||||
private boolean primary;
|
||||
|
||||
private RelayQuery query = null;
|
||||
private int queriedVersion = -1;
|
||||
private String queriedComment;
|
||||
private String queriedVendor;
|
||||
private VersionMismatch queriedCompatible;
|
||||
private long ping = 0l;
|
||||
private long workingPing = 0l;
|
||||
public long lastPing = 0l;
|
||||
|
||||
public RelayServer(String address, String comment, boolean primary) {
|
||||
this.address = address;
|
||||
this.comment = comment;
|
||||
this.primary = primary;
|
||||
}
|
||||
|
||||
public RelayServer(RelayEntry etr) {
|
||||
this(etr.address, etr.comment, etr.primary);
|
||||
}
|
||||
|
||||
public boolean isPrimary() {
|
||||
return primary;
|
||||
}
|
||||
|
||||
public void setPrimary(boolean primaryee) {
|
||||
primary = primaryee;
|
||||
}
|
||||
|
||||
public long getPing() {
|
||||
return ping;
|
||||
}
|
||||
|
||||
public long getWorkingPing() {
|
||||
return workingPing;
|
||||
}
|
||||
|
||||
public int getPingVersion() {
|
||||
return queriedVersion;
|
||||
}
|
||||
|
||||
public String getPingComment() {
|
||||
return queriedComment == null ? "" : queriedComment;
|
||||
}
|
||||
|
||||
public String getPingVendor() {
|
||||
return queriedVendor == null ? "" : queriedVendor;
|
||||
}
|
||||
|
||||
public VersionMismatch getPingCompatible() {
|
||||
return queriedCompatible;
|
||||
}
|
||||
|
||||
public void pingBlocking() {
|
||||
ping();
|
||||
while(getPing() < 0l) {
|
||||
EaglerAdapter.sleep(250);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
public void ping() {
|
||||
close();
|
||||
query = EaglerAdapter.openRelayQuery(address);
|
||||
queriedVersion = -1;
|
||||
queriedComment = null;
|
||||
queriedVendor = null;
|
||||
queriedCompatible = VersionMismatch.UNKNOWN;
|
||||
ping = -1l;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if(query != null && !query.isQueryOpen()) {
|
||||
if(query.isQueryFailed()) {
|
||||
queriedVersion = -1;
|
||||
queriedComment = null;
|
||||
queriedVendor = null;
|
||||
queriedCompatible = VersionMismatch.UNKNOWN;
|
||||
ping = 0l;
|
||||
}else {
|
||||
queriedVersion = query.getVersion();
|
||||
queriedComment = query.getComment();
|
||||
queriedVendor = query.getBrand();
|
||||
ping = query.getPing();
|
||||
queriedCompatible = query.getCompatible();
|
||||
workingPing = ping;
|
||||
}
|
||||
lastPing = EaglerAdapter.steadyTimeMillis();
|
||||
query = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if(query != null && query.isQueryOpen()) {
|
||||
query.close();
|
||||
query = null;
|
||||
queriedVersion = -1;
|
||||
queriedComment = null;
|
||||
queriedVendor = null;
|
||||
queriedCompatible = VersionMismatch.UNKNOWN;
|
||||
ping = 0l;
|
||||
}
|
||||
}
|
||||
|
||||
public RelayServerSocket openSocket() {
|
||||
return EaglerAdapter.openRelayConnection(address, Minecraft.getMinecraft().gameSettings.relayTimeout * 1000);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket;
|
||||
|
||||
public interface RelayServerSocket {
|
||||
|
||||
boolean isOpen();
|
||||
boolean isClosed();
|
||||
void close();
|
||||
|
||||
boolean isFailed();
|
||||
Throwable getException();
|
||||
|
||||
void writePacket(IPacket pkt);
|
||||
|
||||
IPacket readPacket();
|
||||
IPacket nextPacket();
|
||||
|
||||
RateLimit getRatelimitHistory();
|
||||
|
||||
String getURI();
|
||||
|
||||
}
|
||||
20
src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java
Normal file
20
src/main/java/net/lax1dude/eaglercraft/RelayWorldsQuery.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.RelayQuery.VersionMismatch;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit;
|
||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld;
|
||||
|
||||
public interface RelayWorldsQuery {
|
||||
|
||||
boolean isQueryOpen();
|
||||
boolean isQueryFailed();
|
||||
RateLimit isQueryRateLimit();
|
||||
void close();
|
||||
|
||||
List<LocalWorld> getWorlds();
|
||||
|
||||
VersionMismatch getCompatible();
|
||||
|
||||
}
|
||||
258
src/main/java/net/lax1dude/eaglercraft/SHA1Digest.java
Normal file
258
src/main/java/net/lax1dude/eaglercraft/SHA1Digest.java
Normal file
@@ -0,0 +1,258 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
|
||||
/**
|
||||
* implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
|
||||
*
|
||||
* It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
|
||||
* is the "endienness" of the word processing!
|
||||
*/
|
||||
public class SHA1Digest
|
||||
extends GeneralDigest
|
||||
{
|
||||
private static final int DIGEST_LENGTH = 20;
|
||||
|
||||
private int H1, H2, H3, H4, H5;
|
||||
|
||||
private int[] X = new int[80];
|
||||
private int xOff;
|
||||
|
||||
/**
|
||||
* Standard constructor
|
||||
*/
|
||||
public SHA1Digest()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor. This will copy the state of the provided
|
||||
* message digest.
|
||||
*/
|
||||
public SHA1Digest(SHA1Digest t)
|
||||
{
|
||||
super(t);
|
||||
|
||||
H1 = t.H1;
|
||||
H2 = t.H2;
|
||||
H3 = t.H3;
|
||||
H4 = t.H4;
|
||||
H5 = t.H5;
|
||||
|
||||
System.arraycopy(t.X, 0, X, 0, t.X.length);
|
||||
xOff = t.xOff;
|
||||
}
|
||||
|
||||
public String getAlgorithmName()
|
||||
{
|
||||
return "SHA-1";
|
||||
}
|
||||
|
||||
public int getDigestSize()
|
||||
{
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
protected void processWord(
|
||||
byte[] in,
|
||||
int inOff)
|
||||
{
|
||||
X[xOff++] = ((in[inOff] & 0xff) << 24) | ((in[inOff + 1] & 0xff) << 16)
|
||||
| ((in[inOff + 2] & 0xff) << 8) | ((in[inOff + 3] & 0xff));
|
||||
|
||||
if (xOff == 16)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void unpackWord(
|
||||
int word,
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
out[outOff] = (byte)(word >>> 24);
|
||||
out[outOff + 1] = (byte)(word >>> 16);
|
||||
out[outOff + 2] = (byte)(word >>> 8);
|
||||
out[outOff + 3] = (byte)word;
|
||||
}
|
||||
|
||||
protected void processLength(
|
||||
long bitLength)
|
||||
{
|
||||
if (xOff > 14)
|
||||
{
|
||||
processBlock();
|
||||
}
|
||||
|
||||
X[14] = (int)(bitLength >>> 32);
|
||||
X[15] = (int)(bitLength & 0xffffffff);
|
||||
}
|
||||
|
||||
public int doFinal(
|
||||
byte[] out,
|
||||
int outOff)
|
||||
{
|
||||
finish();
|
||||
|
||||
unpackWord(H1, out, outOff);
|
||||
unpackWord(H2, out, outOff + 4);
|
||||
unpackWord(H3, out, outOff + 8);
|
||||
unpackWord(H4, out, outOff + 12);
|
||||
unpackWord(H5, out, outOff + 16);
|
||||
|
||||
reset();
|
||||
|
||||
return DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset the chaining variables
|
||||
*/
|
||||
public void reset()
|
||||
{
|
||||
super.reset();
|
||||
|
||||
H1 = 0x67452301;
|
||||
H2 = 0xefcdab89;
|
||||
H3 = 0x98badcfe;
|
||||
H4 = 0x10325476;
|
||||
H5 = 0xc3d2e1f0;
|
||||
|
||||
xOff = 0;
|
||||
for (int i = 0; i != X.length; i++)
|
||||
{
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Additive constants
|
||||
//
|
||||
private static final int Y1 = 0x5a827999;
|
||||
private static final int Y2 = 0x6ed9eba1;
|
||||
private static final int Y3 = 0x8f1bbcdc;
|
||||
private static final int Y4 = 0xca62c1d6;
|
||||
|
||||
private int f(
|
||||
int u,
|
||||
int v,
|
||||
int w)
|
||||
{
|
||||
return ((u & v) | ((~u) & w));
|
||||
}
|
||||
|
||||
private int h(
|
||||
int u,
|
||||
int v,
|
||||
int w)
|
||||
{
|
||||
return (u ^ v ^ w);
|
||||
}
|
||||
|
||||
private int g(
|
||||
int u,
|
||||
int v,
|
||||
int w)
|
||||
{
|
||||
return ((u & v) | (u & w) | (v & w));
|
||||
}
|
||||
|
||||
private int rotateLeft(
|
||||
int x,
|
||||
int n)
|
||||
{
|
||||
return (x << n) | (x >>> (32 - n));
|
||||
}
|
||||
|
||||
protected void processBlock()
|
||||
{
|
||||
//
|
||||
// expand 16 word block into 80 word block.
|
||||
//
|
||||
for (int i = 16; i <= 79; i++)
|
||||
{
|
||||
X[i] = rotateLeft((X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]), 1);
|
||||
}
|
||||
|
||||
//
|
||||
// set up working variables.
|
||||
//
|
||||
int A = H1;
|
||||
int B = H2;
|
||||
int C = H3;
|
||||
int D = H4;
|
||||
int E = H5;
|
||||
|
||||
//
|
||||
// round 1
|
||||
//
|
||||
for (int j = 0; j <= 19; j++)
|
||||
{
|
||||
int t = rotateLeft(A, 5) + f(B, C, D) + E + X[j] + Y1;
|
||||
|
||||
E = D;
|
||||
D = C;
|
||||
C = rotateLeft(B, 30);
|
||||
B = A;
|
||||
A = t;
|
||||
}
|
||||
|
||||
//
|
||||
// round 2
|
||||
//
|
||||
for (int j = 20; j <= 39; j++)
|
||||
{
|
||||
int t = rotateLeft(A, 5) + h(B, C, D) + E + X[j] + Y2;
|
||||
|
||||
E = D;
|
||||
D = C;
|
||||
C = rotateLeft(B, 30);
|
||||
B = A;
|
||||
A = t;
|
||||
}
|
||||
|
||||
//
|
||||
// round 3
|
||||
//
|
||||
for (int j = 40; j <= 59; j++)
|
||||
{
|
||||
int t = rotateLeft(A, 5) + g(B, C, D) + E + X[j] + Y3;
|
||||
|
||||
E = D;
|
||||
D = C;
|
||||
C = rotateLeft(B, 30);
|
||||
B = A;
|
||||
A = t;
|
||||
}
|
||||
|
||||
//
|
||||
// round 4
|
||||
//
|
||||
for (int j = 60; j <= 79; j++)
|
||||
{
|
||||
int t = rotateLeft(A, 5) + h(B, C, D) + E + X[j] + Y4;
|
||||
|
||||
E = D;
|
||||
D = C;
|
||||
C = rotateLeft(B, 30);
|
||||
B = A;
|
||||
A = t;
|
||||
}
|
||||
|
||||
H1 += A;
|
||||
H2 += B;
|
||||
H3 += C;
|
||||
H4 += D;
|
||||
H5 += E;
|
||||
|
||||
//
|
||||
// reset the offset and clean out the word buffer.
|
||||
//
|
||||
xOff = 0;
|
||||
for (int i = 0; i != X.length; i++)
|
||||
{
|
||||
X[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
132
src/main/java/net/lax1dude/eaglercraft/ServerQuery.java
Normal file
132
src/main/java/net/lax1dude/eaglercraft/ServerQuery.java
Normal file
@@ -0,0 +1,132 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit;
|
||||
|
||||
public interface ServerQuery {
|
||||
|
||||
public static final long defaultTimeout = 10000l;
|
||||
|
||||
public static class QueryResponse {
|
||||
public final String responseType;
|
||||
private final Object responseData;
|
||||
public final String serverVersion;
|
||||
public final String serverBrand;
|
||||
public final String serverName;
|
||||
public final long serverTime;
|
||||
public final long clientTime;
|
||||
public final boolean serverCracked;
|
||||
public final RateLimit rateLimitStatus;
|
||||
public final boolean rateLimitIsTCP;
|
||||
public final long ping;
|
||||
public QueryResponse(JSONObject obj, long ping) {
|
||||
this.responseType = obj.getString("type").toLowerCase();
|
||||
this.ping = ping;
|
||||
if(this.responseType.equals("blocked") || this.responseType.equals("locked")) {
|
||||
this.responseData = null;
|
||||
this.serverVersion = "Unknown";
|
||||
this.serverBrand = "Unknown";
|
||||
this.serverName = "Unknown";
|
||||
this.serverTime = 0l;
|
||||
this.clientTime = EaglerAdapter.steadyTimeMillis();
|
||||
this.serverCracked = false;
|
||||
this.rateLimitStatus = this.responseType.equals("locked") ? RateLimit.LOCKED : RateLimit.BLOCKED;
|
||||
this.rateLimitIsTCP = false;
|
||||
}else {
|
||||
this.responseData = obj.get("data");
|
||||
this.serverVersion = obj.getString("vers");
|
||||
this.serverBrand = obj.getString("brand");
|
||||
this.serverName = obj.getString("name");
|
||||
this.serverTime = obj.getLong("time");
|
||||
this.clientTime = EaglerAdapter.steadyTimeMillis();
|
||||
this.serverCracked = obj.optBoolean("cracked", false);
|
||||
this.rateLimitStatus = null;
|
||||
this.rateLimitIsTCP = false;
|
||||
}
|
||||
}
|
||||
public QueryResponse(boolean lockedNotBlocked, long ping) {
|
||||
this.ping = ping;
|
||||
this.responseType = lockedNotBlocked ? "locked" : "blocked";
|
||||
this.responseData = null;
|
||||
this.serverVersion = "Unknown";
|
||||
this.serverBrand = "Unknown";
|
||||
this.serverName = "Unknown";
|
||||
this.serverTime = 0l;
|
||||
this.clientTime = EaglerAdapter.steadyTimeMillis();
|
||||
this.serverCracked = false;
|
||||
this.rateLimitStatus = lockedNotBlocked ? RateLimit.LOCKED : RateLimit.BLOCKED;
|
||||
this.rateLimitIsTCP = true;
|
||||
}
|
||||
public boolean isResponseString() {
|
||||
return responseData instanceof String;
|
||||
}
|
||||
public boolean isResponseJSON() {
|
||||
return responseData instanceof JSONObject;
|
||||
}
|
||||
public String getResponseString() {
|
||||
return (String)responseData;
|
||||
}
|
||||
public JSONObject getResponseJSON() {
|
||||
return (JSONObject)responseData;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isQueryOpen();
|
||||
public void close();
|
||||
|
||||
public void send(String str);
|
||||
|
||||
public default void send(JSONObject obj) {
|
||||
send(obj.toString());
|
||||
}
|
||||
|
||||
public int responseAvailable();
|
||||
public int responseBinaryAvailable();
|
||||
public QueryResponse getResponse();
|
||||
public byte[] getBinaryResponse();
|
||||
|
||||
// normally I wouldn't resort to race conditions but TeaVM has no
|
||||
// java.util.concurrent classes for semaphore-like behavior
|
||||
|
||||
public default boolean awaitResponseAvailable(long timeout) {
|
||||
long start = EaglerAdapter.steadyTimeMillis();
|
||||
while(isQueryOpen() && responseAvailable() <= 0 && (timeout <= 0l || EaglerAdapter.steadyTimeMillis() - start < timeout)) {
|
||||
EaglerAdapter.sleep(10);
|
||||
}
|
||||
return responseAvailable() > 0;
|
||||
}
|
||||
|
||||
public default boolean awaitResponseAvailable() {
|
||||
return awaitResponseAvailable(defaultTimeout);
|
||||
}
|
||||
|
||||
public default boolean awaitResponseBinaryAvailable(long timeout) {
|
||||
long start = EaglerAdapter.steadyTimeMillis();
|
||||
while(isQueryOpen() && responseBinaryAvailable() <= 0 && (timeout <= 0l || EaglerAdapter.steadyTimeMillis() - start < timeout)) {
|
||||
EaglerAdapter.sleep(10);
|
||||
}
|
||||
return responseBinaryAvailable() > 0;
|
||||
}
|
||||
|
||||
public default boolean awaitResponseBinaryAvailable() {
|
||||
return awaitResponseBinaryAvailable(defaultTimeout);
|
||||
}
|
||||
|
||||
public default QueryResponse awaitResponse(long timeout) {
|
||||
return awaitResponseAvailable(timeout) ? getResponse() : null;
|
||||
}
|
||||
|
||||
public default QueryResponse awaitResponse() {
|
||||
return awaitResponseAvailable() ? getResponse() : null;
|
||||
}
|
||||
|
||||
public default byte[] awaitResponseBinary(long timeout) {
|
||||
return awaitResponseBinaryAvailable(timeout) ? getBinaryResponse() : null;
|
||||
}
|
||||
|
||||
public default byte[] awaitResponseBinary() {
|
||||
return awaitResponseBinaryAvailable() ? getBinaryResponse() : null;
|
||||
}
|
||||
|
||||
}
|
||||
38
src/main/java/net/lax1dude/eaglercraft/TextureLocation.java
Normal file
38
src/main/java/net/lax1dude/eaglercraft/TextureLocation.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.RenderEngine;
|
||||
|
||||
public class TextureLocation {
|
||||
|
||||
private String path;
|
||||
private int glObject;
|
||||
|
||||
public TextureLocation(String path) {
|
||||
this.path = path;
|
||||
this.glObject = -1;
|
||||
locations.add(this);
|
||||
}
|
||||
|
||||
public static void freeTextures() {
|
||||
for(TextureLocation l : locations) {
|
||||
l.glObject = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void bindTexture() {
|
||||
RenderEngine r = Minecraft.getMinecraft().renderEngine;
|
||||
if(glObject == -1) {
|
||||
glObject = r.getTexture(path);
|
||||
if(glObject == -1) {
|
||||
System.err.println("could not load: "+path);
|
||||
}
|
||||
}
|
||||
r.bindTexture(glObject);
|
||||
}
|
||||
|
||||
private static final ArrayList<TextureLocation> locations = new ArrayList<>();
|
||||
|
||||
}
|
||||
559
src/main/java/net/lax1dude/eaglercraft/TextureTerrainMap.java
Normal file
559
src/main/java/net/lax1dude/eaglercraft/TextureTerrainMap.java
Normal file
@@ -0,0 +1,559 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.FramebufferGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.TextureGL;
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.Block;
|
||||
import net.minecraft.src.GLAllocation;
|
||||
import net.minecraft.src.Icon;
|
||||
import net.minecraft.src.IconRegister;
|
||||
import net.minecraft.src.RenderManager;
|
||||
|
||||
//supports only 16x16 textures, mipmap is four levels deep
|
||||
public class TextureTerrainMap implements IconRegister {
|
||||
|
||||
private static class TerrainIconV2 implements Icon {
|
||||
|
||||
public final TextureTerrainMap map;
|
||||
public final String name;
|
||||
public final int id;
|
||||
public final int size;
|
||||
private TextureGL frames = null;
|
||||
private int[] framesIdx = null;
|
||||
|
||||
protected int originX;
|
||||
protected int originY;
|
||||
private float minU;
|
||||
private float maxU;
|
||||
private float minV;
|
||||
private float maxV;
|
||||
|
||||
protected int originX_center;
|
||||
protected int originY_center;
|
||||
private float minU_center;
|
||||
private float maxU_center;
|
||||
private float minV_center;
|
||||
private float maxV_center;
|
||||
|
||||
protected int frameCounter = 0;
|
||||
protected int frameCurrent = 0;
|
||||
|
||||
private TerrainIconV2(int id, int s, TextureTerrainMap map, String name) {
|
||||
this.id = id;
|
||||
this.size = s;
|
||||
this.map = map;
|
||||
this.name = name;
|
||||
|
||||
if(s != 1 && s != 2) {
|
||||
throw new IllegalArgumentException("Size " + s + " (" + (s * 16) + "px) is not supported on this texture map");
|
||||
}
|
||||
|
||||
int tw = s * 16 + 32;
|
||||
|
||||
int adjId = id;
|
||||
if(s == 2) {
|
||||
adjId = (map.width / tw - 1) * (map.height / tw - 1) - id;
|
||||
}
|
||||
|
||||
this.originX = (adjId % (map.width / tw)) * tw;
|
||||
this.originY = (adjId / (map.width / tw)) * tw;
|
||||
this.minU = (float)originX / (float)map.width;
|
||||
this.minV = (float)originY / (float)map.height;
|
||||
this.maxU = (float)(originX + tw) / (float)map.width;
|
||||
this.maxV = (float)(originY + tw) / (float)map.height;
|
||||
this.originX_center = originX + 16;
|
||||
this.originY_center = originY + 16;
|
||||
this.minU_center = (float)(originX_center + 0.025f) / (float)map.width;
|
||||
this.minV_center = (float)(originY_center + 0.025f) / (float)map.height;
|
||||
this.maxU_center = (float)(originX_center + 16 - 0.025f) / (float)map.width;
|
||||
this.maxV_center = (float)(originY_center + 16 - 0.025f) / (float)map.height;
|
||||
}
|
||||
|
||||
private void free() {
|
||||
if(frames != null) {
|
||||
EaglerAdapter._wglDeleteTextures(frames);
|
||||
frames = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOriginX() {
|
||||
return originX_center;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOriginY() {
|
||||
return originY_center;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinU() {
|
||||
return minU_center;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxU() {
|
||||
return maxU_center;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInterpolatedU(double var1) {
|
||||
float var3 = this.maxU_center - this.minU_center;
|
||||
return this.minU_center + var3 * ((float) var1 * size / 16.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinV() {
|
||||
return minV_center;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxV() {
|
||||
return maxV_center;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getInterpolatedV(double var1) {
|
||||
float var3 = this.maxV_center - this.minV_center;
|
||||
return this.minV_center + var3 * ((float) var1 * size / 16.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconName() {
|
||||
return name == null ? "missingno" : name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSheetWidth() {
|
||||
return map.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSheetHeight() {
|
||||
return map.height;
|
||||
}
|
||||
|
||||
private void updateAnimation() {
|
||||
if(frames != null) {
|
||||
this.frameCounter = (this.frameCounter + 1) % this.framesIdx.length;
|
||||
int i = framesIdx[this.frameCounter];
|
||||
if (this.frameCurrent != i) {
|
||||
this.frameCurrent = i;
|
||||
map.copyFrame(this, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
byte[] data = Minecraft.getMinecraft().texturePackList.getSelectedTexturePack().getResourceAsBytes("/" + map.basePath + name + ".png");
|
||||
if(data == null) {
|
||||
map.replaceTexture(this, map.missingData);
|
||||
}else {
|
||||
EaglerImage img = EaglerAdapter.loadPNG(data);
|
||||
if(img == null) {
|
||||
map.replaceTexture(this, map.missingData);
|
||||
}else {
|
||||
int ss = size * 16;
|
||||
int divs = img.h / ss;
|
||||
if(divs == 1) {
|
||||
map.replaceTexture(this, generateMip(img));
|
||||
this.frames = null;
|
||||
this.framesIdx = null;
|
||||
}else {
|
||||
map.replaceTexture(this, generateMip(img.getSubImage(0, 0, ss, ss)));
|
||||
|
||||
EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, -1);
|
||||
frames = EaglerAdapter._wglGenTextures();
|
||||
EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, frames);
|
||||
|
||||
EaglerImage mipLvl = populateAlpha(img);
|
||||
uploadBuffer.clear();
|
||||
uploadBuffer.put(mipLvl.data);
|
||||
uploadBuffer.flip();
|
||||
EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 0, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0,
|
||||
EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer);
|
||||
|
||||
mipLvl = generateLevel(mipLvl);
|
||||
uploadBuffer.clear();
|
||||
uploadBuffer.put(mipLvl.data);
|
||||
uploadBuffer.flip();
|
||||
EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 1, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0,
|
||||
EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer);
|
||||
|
||||
mipLvl = generateLevel(mipLvl);
|
||||
uploadBuffer.clear();
|
||||
uploadBuffer.put(mipLvl.data);
|
||||
uploadBuffer.flip();
|
||||
EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 2, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0,
|
||||
EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer);
|
||||
|
||||
mipLvl = generateLevel(mipLvl);
|
||||
uploadBuffer.clear();
|
||||
uploadBuffer.put(mipLvl.data);
|
||||
uploadBuffer.flip();
|
||||
EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 3, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0,
|
||||
EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer);
|
||||
|
||||
mipLvl = generateLevel(mipLvl);
|
||||
uploadBuffer.clear();
|
||||
uploadBuffer.put(mipLvl.data);
|
||||
uploadBuffer.flip();
|
||||
EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, 4, EaglerAdapter.GL_RGBA, mipLvl.w, mipLvl.h, 0,
|
||||
EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer);
|
||||
|
||||
EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MAX_LEVEL, 4);
|
||||
|
||||
String dat = EaglerMisc.bytesToString(Minecraft.getMinecraft().texturePackList.getSelectedTexturePack().getResourceAsBytes("/" + map.basePath + name + ".txt"));
|
||||
if(dat != null) System.out.println("Found animation info for: " + map.basePath + name + ".png");
|
||||
if(dat == null || (dat = dat.trim()).isEmpty()) {
|
||||
framesIdx = new int[divs];
|
||||
for(int i = 0; i < divs; ++i) {
|
||||
framesIdx[i] = i;
|
||||
}
|
||||
}else {
|
||||
String[] fd = dat.split(",");
|
||||
int len = 0;
|
||||
for(int i = 0; i < fd.length; ++i) {
|
||||
int j = fd[i].indexOf('*');
|
||||
len += (j == -1 ? 1 : Integer.parseInt(fd[i].substring(j + 1)));
|
||||
}
|
||||
framesIdx = new int[len];
|
||||
len = 0;
|
||||
for(int i = 0; i < fd.length; ++i) {
|
||||
int j = fd[i].indexOf('*');
|
||||
if(j == -1) {
|
||||
framesIdx[len++] = Integer.parseInt(fd[i]);
|
||||
}else {
|
||||
int c = Integer.parseInt(fd[i].substring(0, j));
|
||||
int l = Integer.parseInt(fd[i].substring(j + 1));
|
||||
for(int k = 0; k < l; ++k) {
|
||||
framesIdx[len++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final String basePath;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private TerrainIconV2 missingImage;
|
||||
private ArrayList<TerrainIconV2> iconList;
|
||||
public final int texture;
|
||||
private final EaglerImage[] missingData;
|
||||
public final FramebufferGL copyFramebuffer;
|
||||
|
||||
private int[] nextSlot = new int[3];
|
||||
|
||||
private static final IntBuffer uploadBuffer = EaglerAdapter.isWebGL ? IntBuffer.wrap(new int[0xFFFF]) :
|
||||
ByteBuffer.allocateDirect(0xFFFF << 2).order(ByteOrder.nativeOrder()).asIntBuffer();
|
||||
|
||||
public TextureTerrainMap(int size, String par2, String par3Str, EaglerImage par4BufferedImage) {
|
||||
this.width = size;
|
||||
this.height = size;
|
||||
this.basePath = par3Str;
|
||||
this.missingImage = new TerrainIconV2(nextSlot[1]++, 1, this, null);
|
||||
this.iconList = new ArrayList<>();
|
||||
this.texture = EaglerAdapter.glGenTextures();
|
||||
this.copyFramebuffer = EaglerAdapter._wglCreateFramebuffer();
|
||||
EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, texture);
|
||||
int levelW = width;
|
||||
int levelH = height;
|
||||
IntBuffer blank = GLAllocation.createDirectIntBuffer(levelW * levelH);
|
||||
for(int i = 0; i < 5; ++i) {
|
||||
blank.clear().limit(levelW * levelH);
|
||||
for(int j = 0; j < blank.limit(); ++j) {
|
||||
blank.put(j, ((j / levelW + (j % levelW)) % 2 == 0) ? 0xffff00ff : 0xff000000);
|
||||
}
|
||||
EaglerAdapter.glTexImage2D(EaglerAdapter.GL_TEXTURE_2D, i, EaglerAdapter.GL_RGBA, levelW, levelH, 0, EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, blank);
|
||||
levelW /= 2;
|
||||
levelH /= 2;
|
||||
}
|
||||
EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MIN_FILTER, EaglerAdapter.GL_NEAREST_MIPMAP_LINEAR);
|
||||
EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MAG_FILTER, EaglerAdapter.GL_NEAREST);
|
||||
EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_WRAP_S, EaglerAdapter.GL_CLAMP);
|
||||
EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_WRAP_T, EaglerAdapter.GL_CLAMP);
|
||||
EaglerAdapter.glTexParameteri(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MAX_LEVEL, 4);
|
||||
EaglerAdapter.glTexParameterf(EaglerAdapter.GL_TEXTURE_2D, EaglerAdapter.GL_TEXTURE_MAX_ANISOTROPY, 1.0f);
|
||||
replaceTexture(missingImage, missingData = generateMip(par4BufferedImage));
|
||||
}
|
||||
|
||||
public static EaglerImage[] generateMip(EaglerImage src16x16) {
|
||||
EaglerImage[] ret = new EaglerImage[5];
|
||||
ret[0] = populateAlpha(create3x3_V2(src16x16));
|
||||
ret[1] = generateLevel(ret[0]);
|
||||
ret[2] = generateLevel(ret[1]);
|
||||
ret[3] = generateLevel(ret[2]);
|
||||
ret[4] = generateLevel(ret[3]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static EaglerImage generateLevel(EaglerImage src) {
|
||||
EaglerImage e = new EaglerImage(src.w / 2, src.h / 2, true);
|
||||
for(int y = 0; y < e.h; ++y) {
|
||||
for(int x = 0; x < e.w; ++x) {
|
||||
int x2 = x * 2;
|
||||
int y2 = y * 2;
|
||||
int a = src.data[y2 * src.w + x2];
|
||||
int b = src.data[y2 * src.w + x2 + 1];
|
||||
int c = src.data[(y2 + 1) * src.w + x2];
|
||||
int d = src.data[(y2 + 1) * src.w + x2 + 1];
|
||||
int ca = (((a >> 24) & 255) + ((b >> 24) & 255) + ((c >> 24) & 255) + ((d >> 24) & 255)) >> 2;
|
||||
int cr = (((a >> 16) & 255) + ((b >> 16) & 255) + ((c >> 16) & 255) + ((d >> 16) & 255)) >> 2;
|
||||
int cg = (((a >> 8) & 255) + ((b >> 8) & 255) + ((c >> 8) & 255) + ((d >> 8) & 255)) >> 2;
|
||||
int cb = ((a & 255) + (b & 255) + (c & 255) + (d & 255)) >> 2;
|
||||
e.data[y * e.w + x] = (ca << 24) | (cr << 16) | (cg << 8) | cb;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
public static EaglerImage populateAlpha(EaglerImage src) {
|
||||
EaglerImage ret = new EaglerImage(src.w, src.h, true);
|
||||
int reducedR = 0;
|
||||
int reducedG = 0;
|
||||
int reducedB = 0;
|
||||
int divisor = 0;
|
||||
int[] array = src.data;
|
||||
for(int i = 0; i < array.length; ++i) {
|
||||
int x = array[i];
|
||||
int a = (x >> 24) & 255;
|
||||
if(a > 2) {
|
||||
reducedR += (x >> 16) & 255;
|
||||
reducedG += (x >> 8) & 255;
|
||||
reducedB += x & 255;
|
||||
++divisor;
|
||||
}
|
||||
}
|
||||
if(divisor == 0) {
|
||||
reducedR = 0;
|
||||
reducedG = 0;
|
||||
reducedB = 0;
|
||||
}else {
|
||||
reducedR /= divisor;
|
||||
reducedG /= divisor;
|
||||
reducedB /= divisor;
|
||||
}
|
||||
int reducedR2, reducedG2, reducedB2, blend1, blend2, blend3, blend4, j;
|
||||
int alpha = (reducedR << 16) | (reducedG << 8) | reducedB;
|
||||
for(int i = 0; i < array.length; ++i) {
|
||||
int x = array[i];
|
||||
int a = (x >> 24) & 255;
|
||||
if(a < 2) {
|
||||
reducedR2 = 0;
|
||||
reducedG2 = 0;
|
||||
reducedB2 = 0;
|
||||
divisor = 0;
|
||||
blend1 = i + 1;
|
||||
blend2 = i - 1;
|
||||
blend3 = i + src.w;
|
||||
blend4 = i - src.w;
|
||||
if(blend1 >= 0 && blend1 < array.length) {
|
||||
j = array[blend1];
|
||||
if(((x >> 24) & 255) > 2){
|
||||
reducedR2 += (x >> 16) & 255;
|
||||
reducedG2 += (x >> 8) & 255;
|
||||
reducedB2 += x & 255;
|
||||
++divisor;
|
||||
}
|
||||
}
|
||||
if(blend2 >= 0 && blend2 < array.length) {
|
||||
j = array[blend2];
|
||||
if(((x >> 24) & 255) > 2){
|
||||
reducedR2 += (x >> 16) & 255;
|
||||
reducedG2 += (x >> 8) & 255;
|
||||
reducedB2 += x & 255;
|
||||
++divisor;
|
||||
}
|
||||
}
|
||||
if(blend3 >= 0 && blend3 < array.length) {
|
||||
j = array[blend3];
|
||||
if(((x >> 24) & 255) > 2){
|
||||
reducedR2 += (x >> 16) & 255;
|
||||
reducedG2 += (x >> 8) & 255;
|
||||
reducedB2 += x & 255;
|
||||
++divisor;
|
||||
}
|
||||
}
|
||||
if(blend4 >= 0 && blend4 < array.length) {
|
||||
j = array[blend4];
|
||||
if(((x >> 24) & 255) > 2){
|
||||
reducedR2 += (x >> 16) & 255;
|
||||
reducedG2 += (x >> 8) & 255;
|
||||
reducedB2 += x & 255;
|
||||
++divisor;
|
||||
}
|
||||
}
|
||||
if(divisor == 0) {
|
||||
ret.data[i] = alpha;
|
||||
}else {
|
||||
ret.data[i] = ((reducedR2 / divisor) << 16) | ((reducedG2 / divisor) << 8) | (reducedB2 / divisor);
|
||||
}
|
||||
}else {
|
||||
ret.data[i] = src.data[i];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static EaglerImage create3x3_V2(EaglerImage src) {
|
||||
EaglerImage ret = new EaglerImage(src.w + 32, src.h + 32, true);
|
||||
for(int y = 0; y < src.h; ++y) {
|
||||
for(int x = 0; x < src.w; ++x) {
|
||||
int pixel = src.data[y * src.w + x];
|
||||
|
||||
ret.data[(y + 16) * ret.w + (x + 16)] = pixel;
|
||||
|
||||
if(x < 16) {
|
||||
ret.data[(y + 16) * ret.w + x] = pixel;
|
||||
}
|
||||
|
||||
if(y < 16) {
|
||||
ret.data[y * ret.w + (x + 16)] = pixel;
|
||||
}
|
||||
|
||||
if(x < 16 && y < 16) {
|
||||
ret.data[y * ret.w + x] = pixel;
|
||||
}
|
||||
|
||||
int mw = src.w - 16;
|
||||
int mh = src.h - 16;
|
||||
|
||||
if(x >= mw) {
|
||||
ret.data[(y + 16) * ret.w + src.w + (x - mw + 16)] = pixel;
|
||||
}
|
||||
|
||||
if(y >= mh) {
|
||||
ret.data[(y - mh + src.h + 16) * ret.w + (x + 16)] = pixel;
|
||||
}
|
||||
|
||||
if(x >= mw && y >= mh) {
|
||||
ret.data[(y - mh + src.h + 16) * ret.w + src.w + (x - mw + 16)] = pixel;
|
||||
}
|
||||
|
||||
if(x >= mw && y < 16) {
|
||||
ret.data[y * ret.w + src.w + (x - mw + 16)] = pixel;
|
||||
}
|
||||
|
||||
if(x < 16 && y >= mh) {
|
||||
ret.data[(y - mh + src.h + 16) * ret.w + x] = pixel;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void refreshTextures() {
|
||||
for(TerrainIconV2 t : iconList) {
|
||||
t.free();
|
||||
}
|
||||
iconList.clear();
|
||||
nextSlot = new int[3];
|
||||
nextSlot[1] = 1;
|
||||
Block[] var1 = Block.blocksList;
|
||||
int var2 = var1.length;
|
||||
|
||||
for (int var3 = 0; var3 < var2; ++var3) {
|
||||
Block var4 = var1[var3];
|
||||
|
||||
if (var4 != null) {
|
||||
var4.registerIcons(this);
|
||||
}
|
||||
}
|
||||
|
||||
Minecraft.getMinecraft().renderGlobal.registerDestroyBlockIcons(this);
|
||||
RenderManager.instance.updateIcons(this);
|
||||
|
||||
for(TerrainIconV2 t : iconList) {
|
||||
t.loadData();
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceTexture(TerrainIconV2 icon, EaglerImage[] textures) {
|
||||
int divisor = 1;
|
||||
EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, texture);
|
||||
for(int i = 0; i < 5; i++) {
|
||||
uploadBuffer.clear();
|
||||
uploadBuffer.put(textures[i].data);
|
||||
uploadBuffer.flip();
|
||||
EaglerAdapter.glTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, icon.originX / divisor, icon.originY / divisor,
|
||||
(16 * icon.size + 32) / divisor, (16 * icon.size + 32) / divisor, EaglerAdapter.GL_RGBA, EaglerAdapter.GL_UNSIGNED_BYTE, uploadBuffer);
|
||||
divisor *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFrame(TerrainIconV2 icon, int frame) {
|
||||
int off = icon.size * 16;
|
||||
int divisor = 1;
|
||||
EaglerAdapter._wglBindFramebuffer(EaglerAdapter._wGL_FRAMEBUFFER, copyFramebuffer);
|
||||
EaglerAdapter._wglReadBuffer(EaglerAdapter._wGL_COLOR_ATTACHMENT0);
|
||||
for(int i = 0; i < 5; i++) {
|
||||
EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, icon.frames);
|
||||
EaglerAdapter._wglFramebufferTexture2D(EaglerAdapter._wGL_COLOR_ATTACHMENT0, icon.frames, i);
|
||||
EaglerAdapter.glBindTexture(EaglerAdapter.GL_TEXTURE_2D, texture);
|
||||
|
||||
// 0, -1
|
||||
EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, icon.originX_center / divisor, (icon.originY_center - 16) / divisor,
|
||||
0, (frame * off + off - 16 / divisor), off, 16 / divisor);
|
||||
|
||||
// -1, 0
|
||||
EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, (icon.originX_center - 16) / divisor, icon.originY_center / divisor,
|
||||
off - 16 / divisor, frame * off, 16 / divisor, off);
|
||||
|
||||
// 0, 0
|
||||
EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, icon.originX_center / divisor, icon.originY_center / divisor,
|
||||
0, frame * off, off, off);
|
||||
|
||||
// 0, 1
|
||||
EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, icon.originX_center / divisor, (icon.originY_center + 16 * icon.size) / divisor,
|
||||
0, frame * off, off, 16 / divisor);
|
||||
|
||||
// 1, 0
|
||||
EaglerAdapter.glCopyTexSubImage2D(EaglerAdapter.GL_TEXTURE_2D, i, (icon.originX_center + 16 * icon.size) / divisor, icon.originY_center / divisor,
|
||||
0, frame * off, 16 / divisor, off);
|
||||
|
||||
off /= 2;
|
||||
divisor *= 2;
|
||||
}
|
||||
EaglerAdapter._wglBindFramebuffer(EaglerAdapter._wGL_FRAMEBUFFER, null);
|
||||
}
|
||||
|
||||
public void updateAnimations() {
|
||||
for(TerrainIconV2 t : iconList) {
|
||||
t.updateAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public Icon registerIcon(String par1Str, int w) {
|
||||
if(w != 1 && w != 2) {
|
||||
System.err.println("Error, texture '" + par1Str + "' was registered with size " + w + ", the terrain texure map only supports size 1 and 2 (16px and 32px)");
|
||||
return missingImage;
|
||||
}else if(par1Str != null) {
|
||||
for(TerrainIconV2 t : iconList) {
|
||||
if(par1Str.equals(t.name) && w == t.size) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
TerrainIconV2 ret = new TerrainIconV2(nextSlot[w]++, w, this, par1Str);
|
||||
iconList.add(ret);
|
||||
return ret;
|
||||
}else{
|
||||
return missingImage;
|
||||
}
|
||||
}
|
||||
|
||||
public Icon getMissingIcon() {
|
||||
return missingImage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import net.minecraft.src.INetworkManager;
|
||||
import net.minecraft.src.NetHandler;
|
||||
import net.minecraft.src.Packet;
|
||||
|
||||
public class WebsocketNetworkManager implements INetworkManager {
|
||||
|
||||
private NetHandler netHandler;
|
||||
private String serverURI;
|
||||
|
||||
public WebsocketNetworkManager(String uri, String eagler, NetHandler netHandler) throws IOException {
|
||||
this.serverURI = uri;
|
||||
this.netHandler = netHandler;
|
||||
if(!EaglerAdapter.startConnection(uri)) {
|
||||
throw new IOException("websocket to "+uri+" failed");
|
||||
}
|
||||
EaglerAdapter.setDebugVar("minecraftServer", uri);
|
||||
}
|
||||
|
||||
public void setNetHandler(NetHandler netHandler) {
|
||||
this.netHandler = netHandler;
|
||||
}
|
||||
|
||||
private ByteArrayOutputStream sendBuffer = new ByteArrayOutputStream();
|
||||
|
||||
public void addToSendQueue(Packet var1) {
|
||||
try {
|
||||
sendBuffer.reset();
|
||||
DataOutputStream yee = new DataOutputStream(sendBuffer);
|
||||
Packet.writePacket(var1, yee);
|
||||
EaglerAdapter.writePacket(sendBuffer.toByteArray());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void wakeThreads() {
|
||||
}
|
||||
|
||||
private static class ByteBufferDirectInputStream extends InputStream {
|
||||
private ByteBuffer buf;
|
||||
private ByteBufferDirectInputStream(ByteBuffer b) {
|
||||
this.buf = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return buf.remaining() > 0 ? ((int)buf.get() & 0xFF) : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return buf.remaining();
|
||||
}
|
||||
}
|
||||
|
||||
private ByteBuffer oldChunkBuffer = null;
|
||||
private LinkedList<ByteBuffer> readChunks = new LinkedList<>();
|
||||
|
||||
public void processReadPackets() {
|
||||
readChunks.clear();
|
||||
|
||||
if(oldChunkBuffer != null) {
|
||||
readChunks.add(oldChunkBuffer);
|
||||
}
|
||||
|
||||
byte[] packet;
|
||||
while((packet = EaglerAdapter.readPacket()) != null) {
|
||||
readChunks.add(ByteBuffer.wrap(packet));
|
||||
}
|
||||
if(!readChunks.isEmpty()) {
|
||||
int cap = 0;
|
||||
for(ByteBuffer b : readChunks) {
|
||||
cap += b.limit();
|
||||
}
|
||||
|
||||
ByteBuffer stream = ByteBuffer.allocate(cap);
|
||||
for(ByteBuffer b : readChunks) {
|
||||
stream.put(b);
|
||||
}
|
||||
stream.flip();
|
||||
|
||||
DataInputStream packetStream = new DataInputStream(new ByteBufferDirectInputStream(stream));
|
||||
while(stream.hasRemaining()) {
|
||||
stream.mark();
|
||||
try {
|
||||
Packet pkt = Packet.readPacket(packetStream, false);
|
||||
pkt.processPacket(this.netHandler);
|
||||
} catch (EOFException e) {
|
||||
stream.reset();
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
continue;
|
||||
} catch (Throwable e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if(stream.hasRemaining()) {
|
||||
oldChunkBuffer = stream.slice();
|
||||
}else {
|
||||
oldChunkBuffer = null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void serverShutdown() {
|
||||
if(EaglerAdapter.connectionOpen()) {
|
||||
EaglerAdapter.endConnection();
|
||||
EaglerAdapter.setDebugVar("minecraftServer", "null");
|
||||
}
|
||||
}
|
||||
|
||||
public int packetSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void networkShutdown(String var1, Object... var2) {
|
||||
serverShutdown();
|
||||
}
|
||||
|
||||
public void closeConnections() {
|
||||
if(EaglerAdapter.connectionOpen()) {
|
||||
EaglerAdapter.endConnection();
|
||||
EaglerAdapter.setDebugVar("minecraftServer", "null");
|
||||
}
|
||||
}
|
||||
|
||||
public String getServerURI() {
|
||||
return this.serverURI;
|
||||
}
|
||||
|
||||
}
|
||||
121
src/main/java/net/lax1dude/eaglercraft/WorkerNetworkManager.java
Normal file
121
src/main/java/net/lax1dude/eaglercraft/WorkerNetworkManager.java
Normal file
@@ -0,0 +1,121 @@
|
||||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.src.INetworkManager;
|
||||
import net.minecraft.src.NetHandler;
|
||||
import net.minecraft.src.Packet;
|
||||
|
||||
public class WorkerNetworkManager implements INetworkManager {
|
||||
|
||||
private NetHandler theNetHandler;
|
||||
private String ipcChannel;
|
||||
private boolean hasClosed;
|
||||
|
||||
public WorkerNetworkManager(String ipcChannel, NetHandler netHandler) {
|
||||
this.ipcChannel = ipcChannel;
|
||||
this.theNetHandler = netHandler;
|
||||
this.hasClosed = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNetHandler(NetHandler var1) {
|
||||
theNetHandler = var1;
|
||||
}
|
||||
|
||||
private ByteArrayOutputStream sendBuffer = new ByteArrayOutputStream();
|
||||
|
||||
@Override
|
||||
public void addToSendQueue(Packet var1) {
|
||||
try {
|
||||
sendBuffer.reset();
|
||||
Packet.writePacket(var1, new DataOutputStream(sendBuffer));
|
||||
EaglerAdapter.sendToIntegratedServer("NET|" + ipcChannel, sendBuffer.toByteArray());
|
||||
}catch(IOException e) {
|
||||
System.err.println("Failed to serialize minecraft packet '" + var1.getClass().getSimpleName() + "' for IPC channel 'NET|" + ipcChannel + "'");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wakeThreads() {
|
||||
// no
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processReadPackets() {
|
||||
PKT ipcPacket;
|
||||
while((ipcPacket = EaglerAdapter.recieveFromIntegratedServer("NET|" + ipcChannel)) != null) {
|
||||
byte[] bytes = ipcPacket.data;
|
||||
try {
|
||||
EaglerInputStream bai = new EaglerInputStream(bytes);
|
||||
int pktId = bai.read();
|
||||
|
||||
if(pktId == -1) {
|
||||
System.err.println("Recieved invalid '-1' packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
Packet pkt = Packet.getNewPacket(pktId);
|
||||
|
||||
if(pkt == null) {
|
||||
System.err.println("Recieved invalid '" + pktId + "' packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
pkt.readPacketData(new DataInputStream(bai));
|
||||
|
||||
//System.out.println("[Client][" + ipcChannel + "]: packet 0x" + Integer.toHexString(pkt.getPacketId()) + " class '" + pkt.getClass().getSimpleName() + "' recieved");
|
||||
|
||||
try {
|
||||
pkt.processPacket(theNetHandler);
|
||||
}catch(Throwable t) {
|
||||
System.err.println("Could not process minecraft packet 0x" + Integer.toHexString(pkt.getPacketId()) + " class '" + pkt.getClass().getSimpleName() + "' on channel 'NET|" + ipcChannel + "'");
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
}catch(IOException ex) {
|
||||
System.err.println("Could not deserialize a " + bytes.length + " byte long minecraft packet of type '" + (bytes.length <= 0 ? -1 : (int)(bytes[0] & 0xFF)) + "' on channel 'NET|" + ipcChannel + "'");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serverShutdown() {
|
||||
if(!hasClosed) {
|
||||
hasClosed = true;
|
||||
IntegratedServer.closeChannel(ipcChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void networkShutdown(String var1, Object... var2) {
|
||||
if(!hasClosed) {
|
||||
hasClosed = true;
|
||||
IntegratedServer.closeChannel(ipcChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int packetSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeConnections() {
|
||||
if(!hasClosed) {
|
||||
hasClosed = true;
|
||||
IntegratedServer.closeChannel(ipcChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerURI() {
|
||||
return "[integrated]";
|
||||
}
|
||||
|
||||
}
|
||||
1653
src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java
Normal file
1653
src/main/java/net/lax1dude/eaglercraft/glemu/EaglerAdapterGL30.java
Normal file
File diff suppressed because it is too large
Load Diff
295
src/main/java/net/lax1dude/eaglercraft/glemu/EffectPipeline.java
Normal file
295
src/main/java/net/lax1dude/eaglercraft/glemu/EffectPipeline.java
Normal file
@@ -0,0 +1,295 @@
|
||||
package net.lax1dude.eaglercraft.glemu;
|
||||
|
||||
import static net.lax1dude.eaglercraft.EaglerAdapter.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import net.lax1dude.eaglercraft.EaglercraftRandom;
|
||||
import net.lax1dude.eaglercraft.adapter.Tessellator;
|
||||
import net.minecraft.src.Minecraft;
|
||||
import net.minecraft.src.EntityLiving;
|
||||
import net.minecraft.src.GLAllocation;
|
||||
import net.minecraft.src.MathHelper;
|
||||
|
||||
public class EffectPipeline {
|
||||
|
||||
private static FramebufferGL noiseGenFramebuffer = null;
|
||||
private static TextureGL noiseGenTexture = null;
|
||||
|
||||
private static ProgramGL noiseProgram = null;
|
||||
private static TextureGL noiseSourceTexture = null;
|
||||
private static UniformGL noiseCounter = null;
|
||||
|
||||
private static BufferArrayGL renderQuadArray = null;
|
||||
private static BufferGL renderQuadBuffer;
|
||||
|
||||
private static final int NOISE_WIDTH = 128;
|
||||
private static final int NOISE_HEIGHT = 128;
|
||||
|
||||
private static boolean hasInit = false;
|
||||
|
||||
public static void updateNoiseTexture(int viewportW, int viewportH, float intensity) {
|
||||
if(!hasInit) {
|
||||
hasInit = true;
|
||||
String src = fileContents("/glsl/adderallNoise.glsl");
|
||||
if(src != null) {
|
||||
renderQuadArray = _wglCreateVertexArray();
|
||||
renderQuadBuffer = _wglCreateBuffer();
|
||||
|
||||
IntBuffer upload = (isWebGL ? IntBuffer.wrap(new int[12]) : ByteBuffer.allocateDirect(12 << 2).order(ByteOrder.nativeOrder()).asIntBuffer());
|
||||
upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(0.0f));
|
||||
upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(1.0f));
|
||||
upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(0.0f));
|
||||
upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(1.0f));
|
||||
upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(1.0f));
|
||||
upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(0.0f));
|
||||
upload.flip();
|
||||
|
||||
_wglBindVertexArray0(renderQuadArray);
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, renderQuadBuffer);
|
||||
_wglBufferData0(_wGL_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW);
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 2, _wGL_FLOAT, false, 8, 0);
|
||||
|
||||
ShaderGL pvert_shader = _wglCreateShader(_wGL_VERTEX_SHADER);
|
||||
|
||||
_wglShaderSource(pvert_shader, _wgetShaderHeader() + "\n" + fileContents("/glsl/pvert.glsl"));
|
||||
_wglCompileShader(pvert_shader);
|
||||
|
||||
if (!_wglGetShaderCompiled(pvert_shader)) System.err.println(("\n" + _wglGetShaderInfoLog(pvert_shader)).replace("\n", "\n[/glsl/pvert.glsl] ") + "\n");
|
||||
|
||||
ShaderGL noise_shader = _wglCreateShader(_wGL_FRAGMENT_SHADER);
|
||||
_wglShaderSource(noise_shader, _wgetShaderHeader() + "\n" + src);
|
||||
_wglCompileShader(noise_shader);
|
||||
|
||||
if (!_wglGetShaderCompiled(noise_shader)) System.err.println(("\n" + _wglGetShaderInfoLog(noise_shader)).replace("\n", "\n[/glsl/fxaa.glsl] ") + "\n");
|
||||
|
||||
noiseProgram = _wglCreateProgram();
|
||||
_wglAttachShader(noiseProgram, pvert_shader);
|
||||
_wglAttachShader(noiseProgram, noise_shader);
|
||||
_wglLinkProgram(noiseProgram);
|
||||
_wglDetachShader(noiseProgram, pvert_shader);
|
||||
_wglDetachShader(noiseProgram, noise_shader);
|
||||
_wglDeleteShader(pvert_shader);
|
||||
_wglDeleteShader(noise_shader);
|
||||
|
||||
if(!_wglGetProgramLinked(noiseProgram)) {
|
||||
System.err.println(("\n"+_wglGetProgramInfoLog(noiseProgram)).replace("\n", "\n[/glsl/fxaa.glsl][LINKER] ") + "\n");
|
||||
noiseProgram = null;
|
||||
throw new RuntimeException("Invalid shader code");
|
||||
}
|
||||
|
||||
noiseCounter = _wglGetUniformLocation(noiseProgram, "counter");
|
||||
|
||||
noiseSourceTexture = _wglGenTextures();
|
||||
glBindTexture(_wGL_TEXTURE_2D, noiseSourceTexture);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_NEAREST);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_NEAREST);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_REPEAT);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_REPEAT);
|
||||
|
||||
EaglercraftRandom noiseRandom = new EaglercraftRandom(696969696969l);
|
||||
|
||||
byte[] b = new byte[NOISE_WIDTH * NOISE_HEIGHT];
|
||||
noiseRandom.nextBytes(b);
|
||||
|
||||
ByteBuffer buf = GLAllocation.createDirectByteBuffer(NOISE_WIDTH * NOISE_HEIGHT);
|
||||
buf.put(b);
|
||||
buf.flip();
|
||||
|
||||
_wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_R8, NOISE_WIDTH, NOISE_HEIGHT, 0, _wGL_RED, _wGL_UNSIGNED_BYTE, buf);
|
||||
|
||||
noiseGenFramebuffer = _wglCreateFramebuffer();
|
||||
noiseGenTexture = _wglGenTextures();
|
||||
|
||||
glBindTexture(_wGL_TEXTURE_2D, noiseGenTexture);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_LINEAR);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_LINEAR);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_REPEAT);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_REPEAT);
|
||||
|
||||
_wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA, NOISE_WIDTH, NOISE_HEIGHT, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, (ByteBuffer)null);
|
||||
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, noiseGenFramebuffer);
|
||||
_wglFramebufferTexture2D(_wGL_COLOR_ATTACHMENT0, noiseGenTexture);
|
||||
}
|
||||
}
|
||||
|
||||
if(noiseProgram != null) {
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, noiseGenFramebuffer);
|
||||
_wglViewport(0, 0, NOISE_WIDTH, NOISE_HEIGHT);
|
||||
_wglUseProgram(noiseProgram);
|
||||
|
||||
long l = steadyTimeMillis();
|
||||
if(timer > 0l && l - timer < 20000l) {
|
||||
counter += (float)((l - timer) * 0.0007) * intensity;
|
||||
if(counter > 10000.0f) {
|
||||
counter = 0.0f;
|
||||
}
|
||||
}
|
||||
timer = l;
|
||||
|
||||
_wglUniform1f(noiseCounter, counter * 3.0f);
|
||||
|
||||
_wglBindVertexArray0(renderQuadArray);
|
||||
glActiveTexture(_wGL_TEXTURE0);
|
||||
glBindTexture(_wGL_TEXTURE_2D, noiseSourceTexture);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_BLEND);
|
||||
glColorMask(true, true, true, true);
|
||||
glDepthMask(false);
|
||||
_wglDrawArrays(_wGL_TRIANGLES, 0, 6);
|
||||
glColorMask(true, true, true, false);
|
||||
glDepthMask(true);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_CULL_FACE);
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, null);
|
||||
_wglViewport(0, 0, viewportW, viewportH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static float counter = 0.0f;
|
||||
private static long timer = 0l;
|
||||
|
||||
public static void drawNoise(int viewportW, int viewportH, float intensity) {
|
||||
if(noiseProgram == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
glActiveTexture(_wGL_TEXTURE0);
|
||||
glBindTexture(_wGL_TEXTURE_2D, noiseGenTexture);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
glPushMatrix(); // 1
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
float aspect = (float) viewportW / viewportH;
|
||||
|
||||
float bb = 3.0f * intensity;
|
||||
float intensityModifier = 0.0f;
|
||||
|
||||
EntityLiving lv = Minecraft.getMinecraft().renderViewEntity;
|
||||
if(lv != null) {
|
||||
int j = lv.getBrightnessForRender(0.0f);
|
||||
intensityModifier = Math.min(1.0f - ((j / 65536) / 256.0f), 1.0f - ((j % 65536) / 256.0f)) * 3.0f;
|
||||
bb += intensityModifier * bb;
|
||||
}
|
||||
|
||||
glColor4f(0.0166f * bb, 0.0166f * bb, 0.0166f * bb, 0.0f);
|
||||
|
||||
glPushMatrix(); // 2
|
||||
|
||||
_wglBlendColor(0.0f, 0.0f, 0.0f, 1.0f - (intensity * 0.1f));
|
||||
glBlendFunc(GL_DST_COLOR, GL_CONSTANT_ALPHA);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPushMatrix();
|
||||
glScalef(1.5f, 1.25f * aspect, 1.0f);
|
||||
drawGradientTextureRect(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
if(intensityModifier > 1.5f) {
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
glColor4f(0.8f, 1.0f, 0.5f, (intensityModifier - 1.5f) * 0.03f * intensity);
|
||||
glPushMatrix();
|
||||
glScalef(0.5f, 0.5f, 1.0f);
|
||||
drawGradientTextureRect(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
glPopMatrix();
|
||||
glColor4f(0.05f, 0.05f, 0.05f, 0.0f);
|
||||
glBlendFunc(GL_DST_COLOR, GL_CONSTANT_ALPHA);
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix(); // 2
|
||||
|
||||
float fs1 = MathHelper.sin(counter) + MathHelper.sin(counter * 0.7f + 0.3f) * 0.5f;
|
||||
fs1 = fs1 * 0.1f;
|
||||
float fs3 = MathHelper.sin(counter * 0.7f) + MathHelper.sin(counter * 1.1f + 0.6f) * 0.4f
|
||||
+ MathHelper.sin(counter * 2.3f + 1.1f) * 0.2f + MathHelper.sin(counter * 3.3f + 0.75f) * 0.3f;
|
||||
|
||||
glPushMatrix(); // 1.5
|
||||
glRotatef(50.0f * fs1, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
_wglBlendColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
for(int i = 0; i < 4; ++i) {
|
||||
float fs2 = MathHelper.sin(counter * 0.7f + i * i * 0.2f) + MathHelper.sin(counter * 2.2f + 0.44f + i * 0.3f) * 0.2f +
|
||||
MathHelper.sin(counter * 5.0f + 0.7f + i * i * 0.5f) * 0.2f;
|
||||
|
||||
glPushMatrix(); // 2
|
||||
|
||||
glRotatef(90.0f * i, 0.0f, 0.0f, 1.0f);
|
||||
glTranslatef(-fs1 * 0.1f, 0.3f + Math.max(fs3 * 0.25f + 0.1f, -0.25f), 0.0f);
|
||||
|
||||
glRotatef(45.0f, 0.0f, 0.0f, 1.0f);
|
||||
glScalef(1.5f, 0.7f, 1.0f);
|
||||
glTranslatef(0.0f, 1.0f, 0.0f);
|
||||
|
||||
float f1 = Math.max(fs1 * 0.5f + 1.0f, 0.0f);
|
||||
glColor4f(0.1f * bb * f1, 0.1f * bb * f1, 0.1f * bb * f1, 0.0f);
|
||||
|
||||
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPushMatrix();
|
||||
|
||||
glTranslatef(-counter * 0.2f + fs1 * 1.4f, -counter * 0.2f, 0.0f);
|
||||
glScalef(3.0f * 1.5f, 0.5f * aspect, 1.0f);
|
||||
|
||||
drawGradientTextureRect(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glPopMatrix();
|
||||
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glTranslatef(0.0f, Math.max(fs2 * 0.5f + 1.0f, 0.0f) * 0.8f, 0.0f);
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
|
||||
glPushMatrix();
|
||||
|
||||
glTranslatef(-counter * 0.2f, counter * 0.2f, 0.0f);
|
||||
glScalef(3.0f * 1.5f, 0.3f * aspect, 1.0f);
|
||||
|
||||
glRotatef(190.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
glColor4f(0.1f * bb, 0.1f * bb, 0.1f * bb, 0.0f);
|
||||
|
||||
drawGradientTextureRect(1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix(); // 2
|
||||
}
|
||||
|
||||
glPopMatrix(); // 1.5
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix(); // 1
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
private static void drawGradientTextureRect(float r1, float g1, float b1, float a1, float r2, float g2, float b2, float a2) {
|
||||
Tessellator var9 = Tessellator.instance;
|
||||
var9.startDrawingQuads();
|
||||
var9.setColorRGBA_F(r2, g2, b2, a2);
|
||||
var9.addVertexWithUV(-1.0, -1.0, 0.0, 0.0, 0.0);
|
||||
var9.addVertexWithUV(1.0, -1.0, 0.0, 1.0, 0.0);
|
||||
var9.setColorRGBA_F(r1, g1, b1, a1);
|
||||
var9.addVertexWithUV(1.0, 1.0, 0.0, 1.0, 1.0);
|
||||
var9.addVertexWithUV(-1.0, 1.0, 0.0, 0.0, 1.0);
|
||||
var9.draw();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package net.lax1dude.eaglercraft.glemu;
|
||||
|
||||
import static net.lax1dude.eaglercraft.EaglerAdapter.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import net.lax1dude.eaglercraft.EaglerAdapter;
|
||||
import net.minecraft.src.Minecraft;
|
||||
|
||||
public class EffectPipelineFXAA {
|
||||
|
||||
private static boolean isUsingFXAA = false;
|
||||
|
||||
private static FramebufferGL framebuffer = null;
|
||||
private static RenderbufferGL framebuffer_color = null;
|
||||
private static RenderbufferGL framebuffer_depth = null;
|
||||
|
||||
private static ProgramGL fxaaProgram = null;
|
||||
private static TextureGL fxaaSourceTexture = null;
|
||||
private static UniformGL fxaaScreenSize = null;
|
||||
|
||||
private static BufferArrayGL renderQuadArray = null;
|
||||
private static BufferGL renderQuadBuffer;
|
||||
|
||||
public static int displayWidth = -1;
|
||||
public static int displayHeight = -1;
|
||||
public static int width = -1;
|
||||
public static int height = -1;
|
||||
|
||||
private static int[] originalViewport = new int[4];
|
||||
|
||||
private static int state = 1;
|
||||
private static int newState = -1;
|
||||
private static boolean msaaInit = false;
|
||||
|
||||
private static void initFXAA() {
|
||||
if(fxaaProgram == null) {
|
||||
renderQuadArray = _wglCreateVertexArray();
|
||||
renderQuadBuffer = _wglCreateBuffer();
|
||||
|
||||
IntBuffer upload = (isWebGL ? IntBuffer.wrap(new int[12]) : ByteBuffer.allocateDirect(12 << 2).order(ByteOrder.nativeOrder()).asIntBuffer());
|
||||
upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(0.0f));
|
||||
upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(1.0f));
|
||||
upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(0.0f));
|
||||
upload.put(Float.floatToRawIntBits(0.0f)); upload.put(Float.floatToRawIntBits(1.0f));
|
||||
upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(1.0f));
|
||||
upload.put(Float.floatToRawIntBits(1.0f)); upload.put(Float.floatToRawIntBits(0.0f));
|
||||
upload.flip();
|
||||
|
||||
_wglBindVertexArray0(renderQuadArray);
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, renderQuadBuffer);
|
||||
_wglBufferData0(_wGL_ARRAY_BUFFER, upload, _wGL_STATIC_DRAW);
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 2, _wGL_FLOAT, false, 8, 0);
|
||||
|
||||
ShaderGL pvert_shader = _wglCreateShader(_wGL_VERTEX_SHADER);
|
||||
|
||||
_wglShaderSource(pvert_shader, _wgetShaderHeader() + "\n" + fileContents("/glsl/pvert.glsl"));
|
||||
_wglCompileShader(pvert_shader);
|
||||
|
||||
if (!_wglGetShaderCompiled(pvert_shader)) System.err.println(("\n" + _wglGetShaderInfoLog(pvert_shader)).replace("\n", "\n[/glsl/pvert.glsl] ") + "\n");
|
||||
|
||||
ShaderGL fxaa_shader = _wglCreateShader(_wGL_FRAGMENT_SHADER);
|
||||
_wglShaderSource(fxaa_shader, _wgetShaderHeader() + "\n" + fileContents("/glsl/fxaa.glsl"));
|
||||
_wglCompileShader(fxaa_shader);
|
||||
|
||||
if (!_wglGetShaderCompiled(fxaa_shader)) System.err.println(("\n" + _wglGetShaderInfoLog(fxaa_shader)).replace("\n", "\n[/glsl/fxaa.glsl] ") + "\n");
|
||||
|
||||
fxaaProgram = _wglCreateProgram();
|
||||
_wglAttachShader(fxaaProgram, pvert_shader);
|
||||
_wglAttachShader(fxaaProgram, fxaa_shader);
|
||||
_wglLinkProgram(fxaaProgram);
|
||||
_wglDetachShader(fxaaProgram, pvert_shader);
|
||||
_wglDetachShader(fxaaProgram, fxaa_shader);
|
||||
_wglDeleteShader(pvert_shader);
|
||||
_wglDeleteShader(fxaa_shader);
|
||||
|
||||
if(!_wglGetProgramLinked(fxaaProgram)) {
|
||||
System.err.println(("\n"+_wglGetProgramInfoLog(fxaaProgram)).replace("\n", "\n[/glsl/fxaa.glsl][LINKER] ") + "\n");
|
||||
fxaaProgram = null;
|
||||
throw new RuntimeException("Invalid shader code");
|
||||
}
|
||||
|
||||
_wglUseProgram(fxaaProgram);
|
||||
|
||||
UniformGL c = _wglGetUniformLocation(fxaaProgram, "f_color");
|
||||
if(c != null) _wglUniform1i(c, 0);
|
||||
|
||||
fxaaScreenSize = _wglGetUniformLocation(fxaaProgram, "screenSize");
|
||||
}
|
||||
|
||||
destroy();
|
||||
|
||||
isUsingFXAA = true;
|
||||
framebuffer = _wglCreateFramebuffer();
|
||||
fxaaSourceTexture = _wglGenTextures();
|
||||
|
||||
glBindTexture(_wGL_TEXTURE_2D, fxaaSourceTexture);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_NEAREST);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_NEAREST);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_CLAMP);
|
||||
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_CLAMP);
|
||||
_wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA8, width, height, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, (ByteBuffer)null);
|
||||
|
||||
|
||||
framebuffer_depth = _wglCreateRenderBuffer();
|
||||
_wglBindRenderbuffer(framebuffer_depth);
|
||||
_wglRenderbufferStorage(_wGL_DEPTH_COMPONENT32F, width, height);
|
||||
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer);
|
||||
_wglFramebufferTexture2D(_wGL_COLOR_ATTACHMENT0, fxaaSourceTexture);
|
||||
_wglFramebufferRenderbuffer(_wGL_DEPTH_ATTACHMENT, framebuffer_depth);
|
||||
}
|
||||
|
||||
private static void initMSAA() {
|
||||
destroy();
|
||||
msaaInit = true;
|
||||
framebuffer = _wglCreateFramebuffer();
|
||||
framebuffer_color = _wglCreateRenderBuffer();
|
||||
framebuffer_depth = _wglCreateRenderBuffer();
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer);
|
||||
_wglBindRenderbuffer(framebuffer_color);
|
||||
_wglRenderbufferStorageMultisample(state == 2 ? 4 : 8, _wGL_RGBA8, width, height);
|
||||
_wglBindRenderbuffer(framebuffer_depth);
|
||||
_wglRenderbufferStorageMultisample(state == 2 ? 4 : 8, _wGL_DEPTH_COMPONENT32F, width, height);
|
||||
_wglFramebufferRenderbuffer(_wGL_COLOR_ATTACHMENT0, framebuffer_color);
|
||||
_wglFramebufferRenderbuffer(_wGL_DEPTH_ATTACHMENT, framebuffer_depth);
|
||||
}
|
||||
|
||||
public static void destroy() {
|
||||
isUsingFXAA = false;
|
||||
msaaInit = false;
|
||||
if(framebuffer != null) _wglDeleteFramebuffer(framebuffer);
|
||||
if(framebuffer_color != null) _wglDeleteRenderbuffer(framebuffer_color);
|
||||
if(framebuffer_depth != null) _wglDeleteRenderbuffer(framebuffer_depth);
|
||||
if(fxaaSourceTexture != null) _wglDeleteTextures(fxaaSourceTexture);
|
||||
framebuffer = null;
|
||||
framebuffer_color = null;
|
||||
framebuffer_depth = null;
|
||||
fxaaSourceTexture = null;
|
||||
}
|
||||
|
||||
public static void beginPipelineRender() {
|
||||
if(displayWidth <= 0 || displayHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
int mode = Minecraft.getMinecraft().gameSettings.antialiasMode;
|
||||
if(mode == 0) newState = 0;
|
||||
if(mode == 1) newState = Minecraft.getMinecraft().gameSettings.fancyGraphics ? 1 : 0;
|
||||
if(mode == 2) newState = 1;
|
||||
if(mode == 3) newState = 2;
|
||||
if(mode == 4) newState = 3;
|
||||
if(newState == 0) {
|
||||
state = newState;
|
||||
destroy();
|
||||
return;
|
||||
}
|
||||
if(newState != state && !(newState == 3 && state == 2)) {
|
||||
destroy();
|
||||
}
|
||||
//_wglGetParameter(_wGL_VIEWPORT, 4, originalViewport);
|
||||
if (displayWidth != width || displayHeight != height || state != newState) {
|
||||
state = newState;
|
||||
width = displayWidth;
|
||||
height = displayHeight;
|
||||
originalViewport[0] = 0;
|
||||
originalViewport[1] = 0;
|
||||
originalViewport[2] = width;
|
||||
originalViewport[3] = height;
|
||||
if(state == 1) {
|
||||
if(isUsingFXAA == false) {
|
||||
initFXAA();
|
||||
}else {
|
||||
glBindTexture(_wGL_TEXTURE_2D, fxaaSourceTexture);
|
||||
_wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA8, width, height, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, (ByteBuffer)null);
|
||||
_wglBindRenderbuffer(framebuffer_depth);
|
||||
_wglRenderbufferStorage(_wGL_DEPTH_COMPONENT32F, width, height);
|
||||
}
|
||||
}else if(state == 2 || state == 3) {
|
||||
if(msaaInit == false) {
|
||||
initMSAA();
|
||||
}else {
|
||||
_wglBindRenderbuffer(framebuffer_color);
|
||||
_wglRenderbufferStorageMultisample(state == 2 ? 4 : 8, _wGL_RGBA8, width, height);
|
||||
_wglBindRenderbuffer(framebuffer_depth);
|
||||
_wglRenderbufferStorageMultisample(state == 2 ? 4 : 8, _wGL_DEPTH_COMPONENT32F, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer);
|
||||
_wglViewport(0, 0, width, height);
|
||||
if(!EaglerAdapter.isWebGL && (state == 2 || state == 3)) {
|
||||
_wglEnable(_wGL_MULTISAMPLE);
|
||||
_wglEnable(_wGL_LINE_SMOOTH);
|
||||
}
|
||||
}
|
||||
|
||||
public static void endPipelineRender() {
|
||||
if(displayWidth <= 0 || displayHeight <= 0 || state == 0) {
|
||||
return;
|
||||
}
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, null);
|
||||
_wglClear(_wGL_COLOR_BUFFER_BIT | _wGL_DEPTH_BUFFER_BIT);
|
||||
if(state == 1) {
|
||||
_wglViewport(originalViewport[0], originalViewport[1], originalViewport[2], originalViewport[3]);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(_wGL_TEXTURE_2D, fxaaSourceTexture);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDepthMask(false);
|
||||
_wglUseProgram(fxaaProgram);
|
||||
_wglUniform2f(fxaaScreenSize, 1.0f / width, 1.0f / height);
|
||||
_wglBindVertexArray0(renderQuadArray);
|
||||
_wglDrawArrays(_wGL_TRIANGLES, 0, 6);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(true);
|
||||
}else if(state == 2 || state == 3) {
|
||||
if(!EaglerAdapter.isWebGL) {
|
||||
_wglDisable(_wGL_MULTISAMPLE);
|
||||
_wglDisable(_wGL_LINE_SMOOTH);
|
||||
}
|
||||
_wglViewport(originalViewport[0], originalViewport[1], originalViewport[2], originalViewport[3]);
|
||||
_wglBindFramebuffer(_wGL_READ_FRAMEBUFFER, framebuffer);
|
||||
_wglBindFramebuffer(_wGL_DRAW_FRAMEBUFFER, null);
|
||||
_wglDrawBuffer(_wGL_COLOR_ATTACHMENT0);
|
||||
_wglBlitFramebuffer(0, 0, width, height, 0, 0, width, height, _wGL_COLOR_BUFFER_BIT, _wGL_NEAREST);
|
||||
_wglBindFramebuffer(_wGL_READ_FRAMEBUFFER, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,636 @@
|
||||
package net.lax1dude.eaglercraft.glemu;
|
||||
|
||||
import static net.lax1dude.eaglercraft.EaglerAdapter.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ProgramGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ShaderGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.UniformGL;
|
||||
import net.lax1dude.eaglercraft.glemu.vector.Vector2f;
|
||||
import net.lax1dude.eaglercraft.glemu.vector.Vector4f;
|
||||
|
||||
public class FixedFunctionShader {
|
||||
|
||||
private static final FixedFunctionShader[] instances = new FixedFunctionShader[4096]; //lol
|
||||
private static final List<FixedFunctionShader> instanceList = new ArrayList<>();
|
||||
|
||||
public static void refreshCoreGL() {
|
||||
for(int i = 0; i < instances.length; ++i) {
|
||||
if(instances[i] != null) {
|
||||
_wglDeleteProgram(instances[i].globject);
|
||||
instances[i] = null;
|
||||
}
|
||||
}
|
||||
instanceList.clear();
|
||||
shaderSource = null;
|
||||
}
|
||||
|
||||
public static final int COLOR = 1;
|
||||
public static final int NORMAL = 2;
|
||||
public static final int TEXTURE0 = 4;
|
||||
public static final int TEXTURE1 = 8;
|
||||
public static final int TEXGEN = 16;
|
||||
public static final int LIGHTING = 32;
|
||||
public static final int FOG = 64;
|
||||
public static final int ALPHATEST = 128;
|
||||
public static final int UNIT0 = 256;
|
||||
public static final int UNIT1 = 512;
|
||||
public static final int FIX_ANISOTROPIC = 1024;
|
||||
public static final int SWAP_RB = 2048;
|
||||
|
||||
public static FixedFunctionShader instance(int i) {
|
||||
FixedFunctionShader s = instances[i];
|
||||
if(s == null) {
|
||||
boolean CC_a_color = false;
|
||||
boolean CC_a_normal = false;
|
||||
boolean CC_a_texture0 = false;
|
||||
boolean CC_a_texture1 = false;
|
||||
boolean CC_TEX_GEN_STRQ = false;
|
||||
boolean CC_lighting = false;
|
||||
boolean CC_fog = false;
|
||||
boolean CC_alphatest = false;
|
||||
boolean CC_unit0 = false;
|
||||
boolean CC_unit1 = false;
|
||||
boolean CC_anisotropic = false;
|
||||
boolean CC_swap_rb = false;
|
||||
if((i & COLOR) == COLOR) {
|
||||
CC_a_color = true;
|
||||
}
|
||||
if((i & NORMAL) == NORMAL) {
|
||||
CC_a_normal = true;
|
||||
}
|
||||
if((i & TEXTURE0) == TEXTURE0) {
|
||||
CC_a_texture0 = true;
|
||||
}
|
||||
if((i & TEXTURE1) == TEXTURE1) {
|
||||
CC_a_texture1 = true;
|
||||
}
|
||||
if((i & TEXGEN) == TEXGEN) {
|
||||
CC_TEX_GEN_STRQ = true;
|
||||
}
|
||||
if((i & LIGHTING) == LIGHTING) {
|
||||
CC_lighting = true;
|
||||
}
|
||||
if((i & FOG) == FOG) {
|
||||
CC_fog = true;
|
||||
}
|
||||
if((i & ALPHATEST) == ALPHATEST) {
|
||||
CC_alphatest = true;
|
||||
}
|
||||
if((i & UNIT0) == UNIT0) {
|
||||
CC_unit0 = true;
|
||||
}
|
||||
if((i & UNIT1) == UNIT1) {
|
||||
CC_unit1 = true;
|
||||
}
|
||||
if((i & FIX_ANISOTROPIC) == FIX_ANISOTROPIC) {
|
||||
CC_anisotropic = true;
|
||||
}
|
||||
if((i & SWAP_RB) == SWAP_RB) {
|
||||
CC_swap_rb = true;
|
||||
}
|
||||
s = new FixedFunctionShader(i, CC_a_color, CC_a_normal, CC_a_texture0, CC_a_texture1, CC_TEX_GEN_STRQ, CC_lighting,
|
||||
CC_fog, CC_alphatest, CC_unit0, CC_unit1, CC_anisotropic, CC_swap_rb);
|
||||
instances[i] = s;
|
||||
instanceList.add(s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private static String shaderSource = null;
|
||||
|
||||
private final boolean enable_color;
|
||||
private final boolean enable_normal;
|
||||
private final boolean enable_texture0;
|
||||
private final boolean enable_texture1;
|
||||
private final boolean enable_TEX_GEN_STRQ;
|
||||
private final boolean enable_lighting;
|
||||
private final boolean enable_fog;
|
||||
private final boolean enable_alphatest;
|
||||
private final boolean enable_unit0;
|
||||
private final boolean enable_unit1;
|
||||
private final boolean enable_anisotropic_fix;
|
||||
private final boolean enable_swap_rb;
|
||||
private final ProgramGL globject;
|
||||
|
||||
private UniformGL u_matrix_m = null;
|
||||
private UniformGL u_matrix_p = null;
|
||||
private UniformGL u_matrix_t = null;
|
||||
|
||||
private UniformGL u_fogColor = null;
|
||||
//private UniformGL u_fogMode = null;
|
||||
//private UniformGL u_fogStart = null;
|
||||
//private UniformGL u_fogEnd = null;
|
||||
//private UniformGL u_fogDensity = null;
|
||||
private UniformGL u_fogParam = null;
|
||||
|
||||
private UniformGL u_colorUniform = null;
|
||||
private UniformGL u_normalUniform = null;
|
||||
|
||||
private UniformGL u_alphaTestF = null;
|
||||
|
||||
//private UniformGL u_textureGenS_M = null;
|
||||
//private UniformGL u_textureGenT_M = null;
|
||||
//private UniformGL u_textureGenR_M = null;
|
||||
//private UniformGL u_textureGenQ_M = null;
|
||||
private UniformGL u_textureGen_M = null;
|
||||
private UniformGL u_textureGenS_V = null;
|
||||
private UniformGL u_textureGenT_V = null;
|
||||
private UniformGL u_textureGenR_V = null;
|
||||
private UniformGL u_textureGenQ_V = null;
|
||||
|
||||
private UniformGL u_texCoordV0 = null;
|
||||
private UniformGL u_texCoordV1 = null;
|
||||
|
||||
private UniformGL u_light0Pos = null;
|
||||
private UniformGL u_light1Pos = null;
|
||||
//private UniformGL u_invertNormals = null;
|
||||
|
||||
private UniformGL u_anisotropic_fix = null;
|
||||
|
||||
private final int a_position;
|
||||
private final int a_texture0;
|
||||
private final int a_color;
|
||||
private final int a_normal;
|
||||
private final int a_texture1;
|
||||
|
||||
private final int attributeIndexesToEnable;
|
||||
|
||||
public final StreamBuffer streamBuffer;
|
||||
public boolean bufferIsInitialized = false;
|
||||
|
||||
private FixedFunctionShader(int j, boolean CC_a_color, boolean CC_a_normal, boolean CC_a_texture0, boolean CC_a_texture1, boolean CC_TEX_GEN_STRQ, boolean CC_lighting,
|
||||
boolean CC_fog, boolean CC_alphatest, boolean CC_unit0, boolean CC_unit1, boolean CC_anisotropic_fix, boolean CC_swap_rb) {
|
||||
enable_color = CC_a_color;
|
||||
enable_normal = CC_a_normal;
|
||||
enable_texture0 = CC_a_texture0;
|
||||
enable_texture1 = CC_a_texture1;
|
||||
enable_TEX_GEN_STRQ = CC_TEX_GEN_STRQ;
|
||||
enable_lighting = CC_lighting;
|
||||
enable_fog = CC_fog;
|
||||
enable_alphatest = CC_alphatest;
|
||||
enable_unit0 = CC_unit0;
|
||||
enable_unit1 = CC_unit1;
|
||||
enable_anisotropic_fix = CC_anisotropic_fix;
|
||||
enable_swap_rb = CC_swap_rb;
|
||||
|
||||
if(shaderSource == null) {
|
||||
shaderSource = fileContents("/glsl/core.glsl");
|
||||
}
|
||||
|
||||
String source = "";
|
||||
if(enable_color) source += "\n#define CC_a_color\n";
|
||||
if(enable_normal) source += "#define CC_a_normal\n";
|
||||
if(enable_texture0) source += "#define CC_a_texture0\n";
|
||||
if(enable_texture1) source += "#define CC_a_texture1\n";
|
||||
if(enable_TEX_GEN_STRQ) source += "#define CC_TEX_GEN_STRQ\n";
|
||||
if(enable_lighting) source += "#define CC_lighting\n";
|
||||
if(enable_fog) source += "#define CC_fog\n";
|
||||
if(enable_alphatest) source += "#define CC_alphatest\n";
|
||||
if(enable_unit0) source += "#define CC_unit0\n";
|
||||
if(enable_unit1) source += "#define CC_unit1\n";
|
||||
if(enable_anisotropic_fix) source += "#define CC_patch_anisotropic\n";
|
||||
if(enable_swap_rb) source += "#define CC_swap_rb\n";
|
||||
source += shaderSource;
|
||||
|
||||
ShaderGL v = _wglCreateShader(_wGL_VERTEX_SHADER);
|
||||
_wglShaderSource(v, _wgetShaderHeader()+"\n#define CC_VERT\n"+source);
|
||||
_wglCompileShader(v);
|
||||
|
||||
if(!_wglGetShaderCompiled(v)) {
|
||||
System.err.println(("\n\n"+_wglGetShaderInfoLog(v)).replace("\n", "\n[/glsl/core.glsl][CC_VERT] "));
|
||||
throw new RuntimeException("broken shader file");
|
||||
}
|
||||
|
||||
ShaderGL f = _wglCreateShader(_wGL_FRAGMENT_SHADER);
|
||||
_wglShaderSource(f, _wgetShaderHeader()+"\n#define CC_FRAG\n"+source);
|
||||
_wglCompileShader(f);
|
||||
|
||||
if(!_wglGetShaderCompiled(f)) {
|
||||
System.err.println(("\n\n"+_wglGetShaderInfoLog(f)).replace("\n", "\n[/glsl/core.glsl][CC_FRAG] "));
|
||||
throw new RuntimeException("broken shader file");
|
||||
}
|
||||
|
||||
globject = _wglCreateProgram();
|
||||
_wglAttachShader(globject, v);
|
||||
_wglAttachShader(globject, f);
|
||||
|
||||
int i = 0;
|
||||
a_position = i++;
|
||||
_wglBindAttributeLocation(globject, a_position, "a_position");
|
||||
|
||||
if(enable_texture0) {
|
||||
a_texture0 = i++;
|
||||
_wglBindAttributeLocation(globject, a_texture0, "a_texture0");
|
||||
}else {
|
||||
a_texture0 = -1;
|
||||
}
|
||||
if(enable_color) {
|
||||
a_color = i++;
|
||||
_wglBindAttributeLocation(globject, a_color, "a_color");
|
||||
}else {
|
||||
a_color = -1;
|
||||
}
|
||||
if(enable_normal) {
|
||||
a_normal = i++;
|
||||
_wglBindAttributeLocation(globject, a_normal, "a_normal");
|
||||
}else {
|
||||
a_normal = -1;
|
||||
}
|
||||
if(enable_texture1) {
|
||||
a_texture1 = i++;
|
||||
_wglBindAttributeLocation(globject, a_texture1, "a_texture1");
|
||||
}else {
|
||||
a_texture1 = -1;
|
||||
}
|
||||
|
||||
attributeIndexesToEnable = i;
|
||||
|
||||
_wglLinkProgram(globject);
|
||||
|
||||
_wglDetachShader(globject, v);
|
||||
_wglDetachShader(globject, f);
|
||||
_wglDeleteShader(v);
|
||||
_wglDeleteShader(f);
|
||||
|
||||
if(!_wglGetProgramLinked(globject)) {
|
||||
System.err.println(("\n\n"+_wglGetProgramInfoLog(globject)).replace("\n", "\n[LINKER] "));
|
||||
throw new RuntimeException("broken shader file");
|
||||
}
|
||||
|
||||
_wglUseProgram(globject);
|
||||
|
||||
u_matrix_m = _wglGetUniformLocation(globject, "matrix_m");
|
||||
u_matrix_p = _wglGetUniformLocation(globject, "matrix_p");
|
||||
u_matrix_t = _wglGetUniformLocation(globject, "matrix_t");
|
||||
|
||||
u_colorUniform = _wglGetUniformLocation(globject, "colorUniform");
|
||||
|
||||
if(enable_lighting) {
|
||||
u_normalUniform = _wglGetUniformLocation(globject, "normalUniform");
|
||||
//u_invertNormals = _wglGetUniformLocation(globject, "invertNormals");
|
||||
u_light0Pos = _wglGetUniformLocation(globject, "light0Pos");
|
||||
u_light1Pos = _wglGetUniformLocation(globject, "light1Pos");
|
||||
}
|
||||
|
||||
if(enable_fog) {
|
||||
u_fogColor = _wglGetUniformLocation(globject, "fogColor");
|
||||
//u_fogMode = _wglGetUniformLocation(globject, "fogMode");
|
||||
//u_fogStart = _wglGetUniformLocation(globject, "fogStart");
|
||||
//u_fogEnd = _wglGetUniformLocation(globject, "fogEnd");
|
||||
//u_fogDensity = _wglGetUniformLocation(globject, "fogDensity");
|
||||
u_fogParam = _wglGetUniformLocation(globject, "fogParam");
|
||||
}
|
||||
|
||||
if(enable_alphatest) {
|
||||
u_alphaTestF = _wglGetUniformLocation(globject, "alphaTestF");
|
||||
}
|
||||
|
||||
if(enable_TEX_GEN_STRQ) {
|
||||
//u_textureGenS_M = _wglGetUniformLocation(globject, "textureGenS_M");
|
||||
//u_textureGenT_M = _wglGetUniformLocation(globject, "textureGenT_M");
|
||||
//u_textureGenR_M = _wglGetUniformLocation(globject, "textureGenR_M");
|
||||
//u_textureGenQ_M = _wglGetUniformLocation(globject, "textureGenQ_M");
|
||||
u_textureGen_M = _wglGetUniformLocation(globject, "textureGen_M");
|
||||
u_textureGenS_V = _wglGetUniformLocation(globject, "textureGenS_V");
|
||||
u_textureGenT_V = _wglGetUniformLocation(globject, "textureGenT_V");
|
||||
u_textureGenR_V = _wglGetUniformLocation(globject, "textureGenR_V");
|
||||
u_textureGenQ_V = _wglGetUniformLocation(globject, "textureGenQ_V");
|
||||
}
|
||||
|
||||
if(enable_anisotropic_fix) {
|
||||
u_anisotropic_fix = _wglGetUniformLocation(globject, "anisotropic_fix");
|
||||
_wglUniform2f(u_anisotropic_fix, 1024.0f * 63.0f / 64.0f, 1024.0f * 63.0f / 64.0f);
|
||||
}
|
||||
|
||||
_wglUniform1i(_wglGetUniformLocation(globject, "tex0"), 0);
|
||||
_wglUniform1i(_wglGetUniformLocation(globject, "tex1"), 1);
|
||||
|
||||
u_texCoordV0 = _wglGetUniformLocation(globject, "texCoordV0");
|
||||
u_texCoordV1 = _wglGetUniformLocation(globject, "texCoordV1");
|
||||
|
||||
streamBuffer = new StreamBuffer(0x8000, 3, 8, (vertexArray, vertexBuffer) -> {
|
||||
_wglBindVertexArray0(vertexArray);
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, vertexBuffer);
|
||||
setupArrayForProgram();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void setupArrayForProgram() {
|
||||
_wglEnableVertexAttribArray(a_position);
|
||||
_wglVertexAttribPointer(a_position, 3, _wGL_FLOAT, false, 32, 0);
|
||||
if(enable_texture0) {
|
||||
_wglEnableVertexAttribArray(a_texture0);
|
||||
_wglVertexAttribPointer(a_texture0, 2, _wGL_FLOAT, false, 32, 12);
|
||||
}
|
||||
if(enable_color) {
|
||||
_wglEnableVertexAttribArray(a_color);
|
||||
_wglVertexAttribPointer(a_color, 4, _wGL_UNSIGNED_BYTE, true, 32, 20);
|
||||
}
|
||||
if(enable_normal) {
|
||||
_wglEnableVertexAttribArray(a_normal);
|
||||
_wglVertexAttribPointer(a_normal, 4, _wGL_UNSIGNED_BYTE, true, 32, 24);
|
||||
}
|
||||
if(enable_texture1) {
|
||||
_wglEnableVertexAttribArray(a_texture1);
|
||||
_wglVertexAttribPointer(a_texture1, 2, _wGL_SHORT, false, 32, 28);
|
||||
}
|
||||
}
|
||||
|
||||
public void useProgram() {
|
||||
_wglUseProgram(globject);
|
||||
}
|
||||
|
||||
public void unuseProgram() {
|
||||
|
||||
}
|
||||
|
||||
public static void optimize() {
|
||||
FixedFunctionShader pp;
|
||||
for(int i = 0, l = instanceList.size(); i < l; ++i) {
|
||||
instanceList.get(i).streamBuffer.optimize();
|
||||
}
|
||||
}
|
||||
|
||||
private float[] matBuffer = new float[16];
|
||||
|
||||
private Vector4f light0Pos = new Vector4f();
|
||||
private Vector4f light1Pos = new Vector4f();
|
||||
private Vector2f anisotropicFix = new Vector2f(0.0f, 0.0f);
|
||||
|
||||
private int fogMode = 0;
|
||||
|
||||
private float fogColorR = 0.0f;
|
||||
private float fogColorG = 0.0f;
|
||||
private float fogColorB = 0.0f;
|
||||
private float fogColorA = 0.0f;
|
||||
|
||||
private float fogStart = 0.0f;
|
||||
private float fogEnd = 0.0f;
|
||||
|
||||
private float fogDensity = 0.0f;
|
||||
|
||||
private float alphaTestValue = 0.0f;
|
||||
|
||||
private float tex0x = 0.0f;
|
||||
private float tex0y = 0.0f;
|
||||
|
||||
private float tex1x = 0.0f;
|
||||
private float tex1y = 0.0f;
|
||||
|
||||
private float colorUniformR = 0.0f;
|
||||
private float colorUniformG = 0.0f;
|
||||
private float colorUniformB = 0.0f;
|
||||
private float colorUniformA = 0.0f;
|
||||
|
||||
private float normalUniformX = 0.0f;
|
||||
private float normalUniformY = 0.0f;
|
||||
private float normalUniformZ = 0.0f;
|
||||
|
||||
private int anisotropicFixSerial = -1;
|
||||
private int colorSerial = -1;
|
||||
private int normalSerial = -1;
|
||||
private int tex0Serial = -1;
|
||||
private int tex1Serial = -1;
|
||||
private int texPlaneSerial = -1;
|
||||
private int texSSerial = -1;
|
||||
private int texTSerial = -1;
|
||||
private int texRSerial = -1;
|
||||
private int texQSerial = -1;
|
||||
private int fogColorSerial = -1;
|
||||
private int fogCfgSerial = -1;
|
||||
private int matModelSerialCounter = -1;
|
||||
private int matProjSerialCounter = -1;
|
||||
private int matTexSerialCounter = -1;
|
||||
private int lightPos0Serial = -1;
|
||||
private int lightPos1Serial = -1;
|
||||
|
||||
private int texS_plane = -1;
|
||||
private float texS_X = -999.0f;
|
||||
private float texS_Y = -999.0f;
|
||||
private float texS_Z = -999.0f;
|
||||
private float texS_W = -999.0f;
|
||||
|
||||
private int texT_plane = -1;
|
||||
private float texT_X = -999.0f;
|
||||
private float texT_Y = -999.0f;
|
||||
private float texT_Z = -999.0f;
|
||||
private float texT_W = -999.0f;
|
||||
|
||||
private int texR_plane = -1;
|
||||
private float texR_X = -999.0f;
|
||||
private float texR_Y = -999.0f;
|
||||
private float texR_Z = -999.0f;
|
||||
private float texR_W = -999.0f;
|
||||
|
||||
private int texQ_plane = -1;
|
||||
private float texQ_X = -999.0f;
|
||||
private float texQ_Y = -999.0f;
|
||||
private float texQ_Z = -999.0f;
|
||||
private float texQ_W = -999.0f;
|
||||
|
||||
public void update() {
|
||||
if(anisotropicFixSerial != EaglerAdapterGL30.anisotropicFixSerial) {
|
||||
float x = EaglerAdapterGL30.anisotropicFixX;
|
||||
float y = EaglerAdapterGL30.anisotropicFixY;
|
||||
anisotropicFixSerial = EaglerAdapterGL30.anisotropicFixSerial;
|
||||
if(anisotropicFix.x != x || anisotropicFix.y != y) {
|
||||
anisotropicFix.x = x;
|
||||
anisotropicFix.y = y;
|
||||
_wglUniform2f(u_anisotropic_fix, x, y);
|
||||
}
|
||||
}
|
||||
if(colorSerial != EaglerAdapterGL30.colorSerial) {
|
||||
float r = EaglerAdapterGL30.colorR;
|
||||
float g = EaglerAdapterGL30.colorG;
|
||||
float b = EaglerAdapterGL30.colorB;
|
||||
float a = EaglerAdapterGL30.colorA;
|
||||
colorSerial = EaglerAdapterGL30.colorSerial;
|
||||
if(colorUniformR != r || colorUniformG != g || colorUniformB != b || colorUniformA != a) {
|
||||
colorUniformR = r;
|
||||
colorUniformG = g;
|
||||
colorUniformB = b;
|
||||
colorUniformA = a;
|
||||
_wglUniform4f(u_colorUniform, r, g, b, a);
|
||||
}
|
||||
}
|
||||
if(normalSerial != EaglerAdapterGL30.normalSerial) {
|
||||
float x = EaglerAdapterGL30.normalX;
|
||||
float y = EaglerAdapterGL30.normalY;
|
||||
float z = EaglerAdapterGL30.normalZ;
|
||||
normalSerial = EaglerAdapterGL30.normalSerial;
|
||||
if(normalUniformX != x || normalUniformY != y || normalUniformZ != z) {
|
||||
normalUniformX = x;
|
||||
normalUniformY = y;
|
||||
normalUniformZ = z;
|
||||
_wglUniform3f(u_normalUniform, x, y, z);
|
||||
}
|
||||
}
|
||||
if(tex0Serial != EaglerAdapterGL30.tex0Serial) {
|
||||
float x = EaglerAdapterGL30.tex0X;
|
||||
float y = EaglerAdapterGL30.tex0Y;
|
||||
tex0Serial = EaglerAdapterGL30.tex0Serial;
|
||||
if(tex0x != x || tex0y != y) {
|
||||
tex0x = x;
|
||||
tex0y = y;
|
||||
_wglUniform2f(u_texCoordV0, x, y);
|
||||
}
|
||||
}
|
||||
if(tex1Serial != EaglerAdapterGL30.tex1Serial) {
|
||||
float x = EaglerAdapterGL30.tex1X;
|
||||
float y = EaglerAdapterGL30.tex1Y;
|
||||
tex1Serial = EaglerAdapterGL30.tex1Serial;
|
||||
if(tex1x != x || tex1y != y) {
|
||||
tex1x = x;
|
||||
tex1y = y;
|
||||
_wglUniform2f(u_texCoordV1, x, y);
|
||||
}
|
||||
}
|
||||
if(texPlaneSerial != EaglerAdapterGL30.texPlaneSerial) {
|
||||
int s = EaglerAdapterGL30.texS_plane;
|
||||
int t = EaglerAdapterGL30.texT_plane;
|
||||
int r = EaglerAdapterGL30.texR_plane;
|
||||
int q = EaglerAdapterGL30.texQ_plane;
|
||||
texPlaneSerial = EaglerAdapterGL30.texPlaneSerial;
|
||||
if(texS_plane != s || texT_plane != t || texR_plane != r || texQ_plane != q) {
|
||||
texS_plane = s;
|
||||
texT_plane = t;
|
||||
texR_plane = r;
|
||||
texQ_plane = q;
|
||||
_wglUniform4i(u_textureGen_M, s, t, r, q);
|
||||
}
|
||||
}
|
||||
if(texSSerial != EaglerAdapterGL30.texSSerial) {
|
||||
float x = EaglerAdapterGL30.texS_X;
|
||||
float y = EaglerAdapterGL30.texS_Y;
|
||||
float z = EaglerAdapterGL30.texS_Z;
|
||||
float w = EaglerAdapterGL30.texS_W;
|
||||
texSSerial = EaglerAdapterGL30.texSSerial;
|
||||
if(texS_X != x || texS_Y != y || texS_Z != z || texS_W != w) {
|
||||
texS_X = x;
|
||||
texS_Y = y;
|
||||
texS_Z = z;
|
||||
texS_W = w;
|
||||
_wglUniform4f(u_textureGenS_V, x, y, z, w);
|
||||
}
|
||||
}
|
||||
if(texTSerial != EaglerAdapterGL30.texTSerial) {
|
||||
float x = EaglerAdapterGL30.texT_X;
|
||||
float y = EaglerAdapterGL30.texT_Y;
|
||||
float z = EaglerAdapterGL30.texT_Z;
|
||||
float w = EaglerAdapterGL30.texT_W;
|
||||
texTSerial = EaglerAdapterGL30.texTSerial;
|
||||
if(texT_X != x || texT_Y != y || texT_Z != z || texT_W != w) {
|
||||
texT_X = x;
|
||||
texT_Y = y;
|
||||
texT_Z = z;
|
||||
texT_W = w;
|
||||
_wglUniform4f(u_textureGenT_V, x, y, z, w);
|
||||
}
|
||||
}
|
||||
if(texRSerial != EaglerAdapterGL30.texRSerial) {
|
||||
float x = EaglerAdapterGL30.texR_X;
|
||||
float y = EaglerAdapterGL30.texR_Y;
|
||||
float z = EaglerAdapterGL30.texR_Z;
|
||||
float w = EaglerAdapterGL30.texR_W;
|
||||
texRSerial = EaglerAdapterGL30.texRSerial;
|
||||
if(texR_X != x || texR_Y != y || texR_Z != z || texR_W != w) {
|
||||
texR_X = x;
|
||||
texR_Y = y;
|
||||
texR_Z = z;
|
||||
texR_W = w;
|
||||
_wglUniform4f(u_textureGenR_V, x, y, z, w);
|
||||
}
|
||||
}
|
||||
if(texQSerial != EaglerAdapterGL30.texQSerial) {
|
||||
float x = EaglerAdapterGL30.texQ_X;
|
||||
float y = EaglerAdapterGL30.texQ_Y;
|
||||
float z = EaglerAdapterGL30.texQ_Z;
|
||||
float w = EaglerAdapterGL30.texQ_W;
|
||||
texQSerial = EaglerAdapterGL30.texQSerial;
|
||||
if(texQ_X != x || texQ_Y != y || texQ_Z != z || texQ_W != w) {
|
||||
texQ_X = x;
|
||||
texQ_Y = y;
|
||||
texQ_Z = z;
|
||||
texQ_W = w;
|
||||
_wglUniform4f(u_textureGenQ_V, x, y, z, w);
|
||||
}
|
||||
}
|
||||
if(fogColorSerial != EaglerAdapterGL30.fogColorSerial) {
|
||||
float r = EaglerAdapterGL30.fogColorR;
|
||||
float g = EaglerAdapterGL30.fogColorG;
|
||||
float b = EaglerAdapterGL30.fogColorB;
|
||||
float a = EaglerAdapterGL30.fogColorA;
|
||||
fogColorSerial = EaglerAdapterGL30.fogColorSerial;
|
||||
if(fogColorR != r || fogColorG != g || fogColorB != b || fogColorA != a) {
|
||||
fogColorR = r;
|
||||
fogColorG = g;
|
||||
fogColorB = b;
|
||||
fogColorA = a;
|
||||
_wglUniform4f(u_fogColor, r, g, b, a);
|
||||
}
|
||||
}
|
||||
if(fogCfgSerial != EaglerAdapterGL30.fogCfgSerial) {
|
||||
int fogModex = EaglerAdapterGL30.fogMode;
|
||||
float fogStarty = EaglerAdapterGL30.fogStart;
|
||||
float fogEndz = EaglerAdapterGL30.fogEnd - fogStarty;
|
||||
float fogDensityw = EaglerAdapterGL30.fogDensity;
|
||||
fogCfgSerial = EaglerAdapterGL30.fogCfgSerial;
|
||||
if(fogMode != fogModex || fogStart != fogStarty ||
|
||||
fogEnd != fogEndz || fogDensity != fogDensityw) {
|
||||
fogMode = fogModex;
|
||||
fogStart = fogStarty;
|
||||
fogEnd = fogEndz;
|
||||
fogDensity = fogDensityw;
|
||||
_wglUniform4f(u_fogParam, fogModex, fogStarty, fogEndz, fogDensityw);
|
||||
}
|
||||
}
|
||||
float limit = EaglerAdapterGL30.alphaThresh;
|
||||
if(alphaTestValue != limit) {
|
||||
alphaTestValue = limit;
|
||||
_wglUniform1f(u_alphaTestF, limit);
|
||||
}
|
||||
float[] matCopyBuffer = matBuffer;
|
||||
int i = EaglerAdapterGL30.matModelPointer;
|
||||
int j = EaglerAdapterGL30.matModelVSerial[i];
|
||||
if(matModelSerialCounter != j) {
|
||||
matModelSerialCounter = j;
|
||||
EaglerAdapterGL30.matModelV[i].store(matCopyBuffer);
|
||||
_wglUniformMat4fv(u_matrix_m, matCopyBuffer);
|
||||
}
|
||||
i = EaglerAdapterGL30.matProjPointer;
|
||||
j = EaglerAdapterGL30.matProjVSerial[i];
|
||||
if(matProjSerialCounter != j) {
|
||||
matProjSerialCounter = j;
|
||||
EaglerAdapterGL30.matProjV[i].store(matCopyBuffer);
|
||||
_wglUniformMat4fv(u_matrix_p, matCopyBuffer);
|
||||
}
|
||||
i = EaglerAdapterGL30.matTexPointer;
|
||||
j = EaglerAdapterGL30.matTexVSerial[i];
|
||||
if(matTexSerialCounter != j) {
|
||||
matTexSerialCounter = j;
|
||||
EaglerAdapterGL30.matTexV[i].store(matCopyBuffer);
|
||||
_wglUniformMat4fv(u_matrix_t, matCopyBuffer);
|
||||
}
|
||||
if(lightPos0Serial != EaglerAdapterGL30.lightPos0Serial) {
|
||||
lightPos0Serial = EaglerAdapterGL30.lightPos0Serial;
|
||||
Vector4f pos = EaglerAdapterGL30.lightPos0vec;
|
||||
if(!pos.equals(light0Pos)) {
|
||||
light0Pos.set(pos);
|
||||
_wglUniform3f(u_light0Pos, pos.x, pos.y, pos.z);
|
||||
}
|
||||
}
|
||||
if(lightPos1Serial != EaglerAdapterGL30.lightPos1Serial) {
|
||||
lightPos1Serial = EaglerAdapterGL30.lightPos1Serial;
|
||||
Vector4f pos = EaglerAdapterGL30.lightPos1vec;
|
||||
if(!pos.equals(light1Pos)) {
|
||||
light1Pos.set(pos);
|
||||
_wglUniform3f(u_light1Pos, pos.x, pos.y, pos.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package net.lax1dude.eaglercraft.glemu;
|
||||
|
||||
public class GLObjectMap<T> {
|
||||
private Object[] values;
|
||||
private int size;
|
||||
private int insertIndex;
|
||||
public int allocatedObjects;
|
||||
|
||||
public GLObjectMap(int initialSize) {
|
||||
this.values = new Object[initialSize];
|
||||
this.size = initialSize;
|
||||
this.insertIndex = 0;
|
||||
this.allocatedObjects = 0;
|
||||
}
|
||||
|
||||
public int register(T obj) {
|
||||
int start = insertIndex;
|
||||
do {
|
||||
++insertIndex;
|
||||
if(insertIndex >= size) {
|
||||
insertIndex = 0;
|
||||
}
|
||||
if(insertIndex == start) {
|
||||
resize();
|
||||
return register(obj);
|
||||
}
|
||||
}while(values[insertIndex] != null);
|
||||
values[insertIndex] = obj;
|
||||
++allocatedObjects;
|
||||
return insertIndex;
|
||||
}
|
||||
|
||||
public T free(int obj) {
|
||||
if(obj >= size || obj < 0) return null;
|
||||
Object ret = values[obj];
|
||||
values[obj] = null;
|
||||
--allocatedObjects;
|
||||
return (T) ret;
|
||||
}
|
||||
|
||||
public T get(int obj) {
|
||||
if(obj >= size || obj < 0) return null;
|
||||
return (T) values[obj];
|
||||
}
|
||||
|
||||
private void resize() {
|
||||
int oldSize = size;
|
||||
size += size / 2;
|
||||
Object[] oldValues = values;
|
||||
values = new Object[size];
|
||||
System.arraycopy(oldValues, 0, values, 0, oldSize);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package net.lax1dude.eaglercraft.glemu;
|
||||
|
||||
import static net.lax1dude.eaglercraft.EaglerAdapter.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class GameOverlayFramebuffer {
|
||||
|
||||
private long age = -1l;
|
||||
|
||||
private int currentWidth = -1;
|
||||
private int currentHeight = -1;
|
||||
|
||||
private FramebufferGL framebuffer = null;
|
||||
private TextureGL framebufferColor = null;
|
||||
private RenderbufferGL depthBuffer = null;
|
||||
|
||||
public void beginRender(int width, int height) {
|
||||
if(framebuffer == null) {
|
||||
framebuffer = _wglCreateFramebuffer();
|
||||
depthBuffer = _wglCreateRenderBuffer();
|
||||
framebufferColor = _wglGenTextures();
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer);
|
||||
glBindTexture(_wGL_TEXTURE_2D, framebufferColor);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
_wglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
_wglFramebufferTexture2D(_wGL_COLOR_ATTACHMENT0, framebufferColor, 0);
|
||||
_wglBindRenderbuffer(depthBuffer);
|
||||
_wglFramebufferRenderbuffer(_wGL_DEPTH_ATTACHMENT, depthBuffer);
|
||||
}
|
||||
|
||||
if(currentWidth != width || currentHeight != height) {
|
||||
currentWidth = width;
|
||||
currentHeight = height;
|
||||
glBindTexture(_wGL_TEXTURE_2D, framebufferColor);
|
||||
_wglTexImage2D(_wGL_TEXTURE_2D, 0, _wGL_RGBA8, width, height, 0, _wGL_RGBA, _wGL_UNSIGNED_BYTE, (ByteBuffer)null);
|
||||
_wglBindRenderbuffer(depthBuffer);
|
||||
_wglRenderbufferStorage(0x81A5, width, height);
|
||||
}
|
||||
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, framebuffer);
|
||||
}
|
||||
|
||||
public void endRender() {
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, null);
|
||||
age = steadyTimeMillis();
|
||||
}
|
||||
|
||||
public long getAge() {
|
||||
return age == -1l ? -1l : (steadyTimeMillis() - age);
|
||||
}
|
||||
|
||||
public void bindTexture() {
|
||||
glBindTexture(_wGL_TEXTURE_2D, framebufferColor);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if(framebuffer != null) {
|
||||
_wglDeleteFramebuffer(framebuffer);
|
||||
_wglDeleteRenderbuffer(depthBuffer);
|
||||
_wglDeleteTextures(framebufferColor);
|
||||
framebuffer = null;
|
||||
depthBuffer = null;
|
||||
framebufferColor = null;
|
||||
age = -1l;
|
||||
_wglBindFramebuffer(_wGL_FRAMEBUFFER, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
119
src/main/java/net/lax1dude/eaglercraft/glemu/HighPolyMesh.java
Normal file
119
src/main/java/net/lax1dude/eaglercraft/glemu/HighPolyMesh.java
Normal file
@@ -0,0 +1,119 @@
|
||||
package net.lax1dude.eaglercraft.glemu;
|
||||
|
||||
import static net.lax1dude.eaglercraft.EaglerAdapter.*;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.lax1dude.eaglercraft.EaglerInputStream;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.BufferArrayGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.BufferGL;
|
||||
import net.minecraft.src.GLAllocation;
|
||||
|
||||
public class HighPolyMesh {
|
||||
|
||||
final BufferArrayGL vertexArray;
|
||||
final BufferGL vertexBuffer;
|
||||
final BufferGL indexBuffer;
|
||||
|
||||
public final int vertexCount;
|
||||
public final int indexCount;
|
||||
|
||||
public final boolean hasTexture;
|
||||
|
||||
public HighPolyMesh(BufferArrayGL vertexArray, BufferGL vertexBuffer, BufferGL indexBuffer, int vertexCount,
|
||||
int indexCount, boolean hasTexture) {
|
||||
this.vertexArray = vertexArray;
|
||||
this.vertexBuffer = vertexBuffer;
|
||||
this.indexBuffer = indexBuffer;
|
||||
this.vertexCount = vertexCount;
|
||||
this.indexCount = indexCount;
|
||||
this.hasTexture = hasTexture;
|
||||
}
|
||||
|
||||
public void free() {
|
||||
_wglDeleteVertexArray(vertexArray);
|
||||
_wglDeleteBuffer(vertexBuffer);
|
||||
_wglDeleteBuffer(indexBuffer);
|
||||
}
|
||||
|
||||
static final byte[] headerSequence = "!EAG%mdl".getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
static HighPolyMesh loadMeshData(byte[] mesh) throws IOException {
|
||||
DataInputStream mdlIn = new DataInputStream(new EaglerInputStream(mesh));
|
||||
|
||||
byte[] hd = new byte[headerSequence.length];
|
||||
mdlIn.read(hd);
|
||||
if(!Arrays.equals(headerSequence, hd)) {
|
||||
throw new IOException("Not an Eaglercraft HighPoly Mesh");
|
||||
}
|
||||
|
||||
char CT = (char)mdlIn.read();
|
||||
|
||||
boolean textureEnabled;
|
||||
if(CT == 'C') {
|
||||
textureEnabled = false;
|
||||
}else if(CT == 'T') {
|
||||
textureEnabled = true;
|
||||
}else {
|
||||
throw new IOException("Unsupported mesh type '" + CT + "'!");
|
||||
}
|
||||
|
||||
mdlIn.skipBytes(mdlIn.readUnsignedShort());
|
||||
|
||||
int vertexCount = mdlIn.readInt();
|
||||
int indexCount = mdlIn.readInt();
|
||||
int byteIndexCount = indexCount;
|
||||
if(byteIndexCount % 2 != 0) { // must round up to int
|
||||
byteIndexCount += 1;
|
||||
}
|
||||
int stride = textureEnabled ? 24 : 16;
|
||||
|
||||
int intsOfVertex = vertexCount * stride / 4;
|
||||
int intsOfIndex = byteIndexCount / 2;
|
||||
int intsTotal = intsOfIndex + intsOfVertex;
|
||||
IntBuffer up1 = GLAllocation.createDirectIntBuffer(intsTotal);
|
||||
|
||||
for(int i = 0; i < intsTotal; ++i) {
|
||||
int ch1 = mdlIn.read();
|
||||
int ch2 = mdlIn.read();
|
||||
int ch3 = mdlIn.read();
|
||||
int ch4 = mdlIn.read();
|
||||
if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EOFException(); // rip
|
||||
up1.put((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
|
||||
}
|
||||
|
||||
BufferArrayGL vertexArray = _wglCreateVertexArray();
|
||||
_wglBindVertexArray0(vertexArray);
|
||||
|
||||
up1.position(0).limit(intsOfVertex);
|
||||
|
||||
BufferGL vertexBuffer = _wglCreateBuffer();
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, vertexBuffer);
|
||||
_wglBufferData0(_wGL_ARRAY_BUFFER, up1, _wGL_STATIC_DRAW);
|
||||
|
||||
up1.position(intsOfVertex).limit(intsTotal);
|
||||
|
||||
BufferGL indexBuffer = _wglCreateBuffer();
|
||||
_wglBindBuffer(_wGL_ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
_wglBufferData0(_wGL_ELEMENT_ARRAY_BUFFER, up1, _wGL_STATIC_DRAW);
|
||||
|
||||
_wglEnableVertexAttribArray(0);
|
||||
_wglVertexAttribPointer(0, 3, _wGL_FLOAT, false, stride, 0);
|
||||
|
||||
if(textureEnabled) {
|
||||
_wglEnableVertexAttribArray(1);
|
||||
_wglVertexAttribPointer(1, 2, _wGL_FLOAT, false, stride, 16);
|
||||
}
|
||||
|
||||
_wglEnableVertexAttribArray(textureEnabled ? 2 : 1);
|
||||
_wglVertexAttribPointer(textureEnabled ? 2 : 1, 4, _wGL_UNSIGNED_BYTE, true, stride, 12);
|
||||
|
||||
return new HighPolyMesh(vertexArray, vertexBuffer, indexBuffer, vertexCount, indexCount, textureEnabled);
|
||||
}
|
||||
|
||||
}
|
||||
2417
src/main/java/net/lax1dude/eaglercraft/glemu/RealOpenGLEnums.java
Normal file
2417
src/main/java/net/lax1dude/eaglercraft/glemu/RealOpenGLEnums.java
Normal file
File diff suppressed because it is too large
Load Diff
189
src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java
Normal file
189
src/main/java/net/lax1dude/eaglercraft/glemu/StreamBuffer.java
Normal file
@@ -0,0 +1,189 @@
|
||||
package net.lax1dude.eaglercraft.glemu;
|
||||
|
||||
import static net.lax1dude.eaglercraft.EaglerAdapter.*;
|
||||
|
||||
public class StreamBuffer {
|
||||
|
||||
public static final int poolSize = 16;
|
||||
|
||||
public final int initialSize;
|
||||
public final int initialCount;
|
||||
public final int maxCount;
|
||||
|
||||
protected static final PoolInstance[] pool = new PoolInstance[poolSize];
|
||||
protected static int poolBufferID = 0;
|
||||
|
||||
static {
|
||||
for(int i = 0; i < poolSize; ++i) {
|
||||
pool[i] = new PoolInstance();
|
||||
}
|
||||
}
|
||||
|
||||
protected static class PoolInstance {
|
||||
|
||||
protected BufferGL vertexBuffer = null;
|
||||
protected int vertexBufferSize = 0;
|
||||
|
||||
}
|
||||
|
||||
private static PoolInstance fillPoolInstance() {
|
||||
PoolInstance ret = pool[poolBufferID++];
|
||||
if(poolBufferID > poolSize - 1) {
|
||||
poolBufferID = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void resizeInstance(PoolInstance instance, int requiredMemory) {
|
||||
if(instance.vertexBuffer == null) {
|
||||
instance.vertexBuffer = _wglCreateBuffer();
|
||||
}
|
||||
if(instance.vertexBufferSize < requiredMemory) {
|
||||
int newSize = (requiredMemory & 0xFFFFF000) + 0x2000;
|
||||
_wglBindBuffer(_wGL_ARRAY_BUFFER, instance.vertexBuffer);
|
||||
_wglBufferData00(_wGL_ARRAY_BUFFER, newSize, _wGL_STREAM_DRAW);
|
||||
instance.vertexBufferSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
protected StreamBufferInstance[] buffers;
|
||||
|
||||
protected int currentBufferId = 0;
|
||||
protected int overflowCounter = 0;
|
||||
|
||||
protected final IStreamBufferInitializer initializer;
|
||||
|
||||
public static class StreamBufferInstance {
|
||||
|
||||
protected PoolInstance poolInstance = null;
|
||||
protected BufferArrayGL vertexArray = null;
|
||||
|
||||
public boolean bindQuad16 = false;
|
||||
public boolean bindQuad32 = false;
|
||||
|
||||
public BufferArrayGL getVertexArray() {
|
||||
return vertexArray;
|
||||
}
|
||||
|
||||
public BufferGL getVertexBuffer() {
|
||||
return poolInstance.vertexBuffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static interface IStreamBufferInitializer {
|
||||
void initialize(BufferArrayGL vertexArray, BufferGL vertexBuffer);
|
||||
}
|
||||
|
||||
public StreamBuffer(int initialSize, int initialCount, int maxCount, IStreamBufferInitializer initializer) {
|
||||
if(maxCount > poolSize) {
|
||||
maxCount = poolSize;
|
||||
}
|
||||
this.buffers = new StreamBufferInstance[initialCount];
|
||||
for(int i = 0; i < this.buffers.length; ++i) {
|
||||
StreamBufferInstance j = new StreamBufferInstance();
|
||||
j.poolInstance = fillPoolInstance();
|
||||
this.buffers[i] = j;
|
||||
}
|
||||
this.initialSize = initialSize;
|
||||
this.initialCount = initialCount;
|
||||
this.maxCount = maxCount;
|
||||
this.initializer = initializer;
|
||||
}
|
||||
|
||||
public StreamBufferInstance getBuffer(int requiredMemory) {
|
||||
StreamBufferInstance next = buffers[(currentBufferId++) % buffers.length];
|
||||
resizeInstance(next.poolInstance, requiredMemory);
|
||||
if(next.vertexArray == null) {
|
||||
next.vertexArray = _wglCreateVertexArray();
|
||||
initializer.initialize(next.vertexArray, next.poolInstance.vertexBuffer);
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
public void optimize() {
|
||||
overflowCounter += currentBufferId - buffers.length;
|
||||
if(overflowCounter < -25) {
|
||||
int newCount = buffers.length - 1 + ((overflowCounter + 25) / 5);
|
||||
if(newCount < initialCount) {
|
||||
newCount = initialCount;
|
||||
}
|
||||
if(newCount < buffers.length) {
|
||||
StreamBufferInstance[] newArray = new StreamBufferInstance[newCount];
|
||||
for(int i = 0; i < buffers.length; ++i) {
|
||||
if(i < newArray.length) {
|
||||
newArray[i] = buffers[i];
|
||||
}else {
|
||||
if(buffers[i].vertexArray != null) {
|
||||
_wglDeleteVertexArray(buffers[i].vertexArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
buffers = newArray;
|
||||
refill();
|
||||
}
|
||||
overflowCounter = 0;
|
||||
}else if(overflowCounter > 15) {
|
||||
int newCount = buffers.length + 1 + ((overflowCounter - 15) / 5);
|
||||
if(newCount > maxCount) {
|
||||
newCount = maxCount;
|
||||
}
|
||||
if(newCount > buffers.length) {
|
||||
StreamBufferInstance[] newArray = new StreamBufferInstance[newCount];
|
||||
for(int i = 0; i < newArray.length; ++i) {
|
||||
if(i < buffers.length) {
|
||||
newArray[i] = buffers[i];
|
||||
}else {
|
||||
newArray[i] = new StreamBufferInstance();
|
||||
}
|
||||
}
|
||||
buffers = newArray;
|
||||
refill();
|
||||
}
|
||||
overflowCounter = 0;
|
||||
}
|
||||
currentBufferId = 0;
|
||||
}
|
||||
|
||||
private void refill() {
|
||||
for(int i = 0; i < buffers.length; ++i) {
|
||||
PoolInstance j = fillPoolInstance();
|
||||
StreamBufferInstance k = buffers[i];
|
||||
if(j != k.poolInstance) {
|
||||
PoolInstance l = k.poolInstance;
|
||||
k.poolInstance = j;
|
||||
if(k.vertexArray != null) {
|
||||
if(j.vertexBuffer == null) {
|
||||
resizeInstance(j, l.vertexBufferSize);
|
||||
}
|
||||
initializer.initialize(k.vertexArray, j.vertexBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
for(int i = 0; i < buffers.length; ++i) {
|
||||
StreamBufferInstance next = buffers[i];
|
||||
if(next.vertexArray != null) {
|
||||
_wglDeleteVertexArray(next.vertexArray);
|
||||
}
|
||||
}
|
||||
buffers = new StreamBufferInstance[initialCount];
|
||||
for(int i = 0; i < initialCount; ++i) {
|
||||
StreamBufferInstance j = new StreamBufferInstance();
|
||||
j.poolInstance = fillPoolInstance();
|
||||
buffers[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
public static void destroyPool() {
|
||||
for(int i = 0; i < pool.length; ++i) {
|
||||
if(pool[i].vertexBuffer != null) {
|
||||
_wglDeleteBuffer(pool[i].vertexBuffer);
|
||||
pool[i].vertexBuffer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
134
src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix.java
Normal file
134
src/main/java/net/lax1dude/eaglercraft/glemu/vector/Matrix.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
* Base class for matrices. When a matrix is constructed it will be the identity
|
||||
* matrix unless otherwise stated.
|
||||
*
|
||||
* @author cix_foo <cix_foo@users.sourceforge.net>
|
||||
* @version $Revision$
|
||||
* $Id$
|
||||
*/
|
||||
public abstract class Matrix implements Serializable {
|
||||
|
||||
/**
|
||||
* Constructor for Matrix.
|
||||
*/
|
||||
protected Matrix() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this matrix to be the identity matrix.
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix setIdentity();
|
||||
|
||||
|
||||
/**
|
||||
* Invert this matrix
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix invert();
|
||||
|
||||
|
||||
/**
|
||||
* Load from a float buffer. The buffer stores the matrix in column major
|
||||
* (OpenGL) order.
|
||||
*
|
||||
* @param buf A float buffer to read from
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix load(FloatBuffer buf);
|
||||
|
||||
|
||||
/**
|
||||
* Load from a float buffer. The buffer stores the matrix in row major
|
||||
* (mathematical) order.
|
||||
*
|
||||
* @param buf A float buffer to read from
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix loadTranspose(FloatBuffer buf);
|
||||
|
||||
|
||||
/**
|
||||
* Negate this matrix
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix negate();
|
||||
|
||||
|
||||
/**
|
||||
* Store this matrix in a float buffer. The matrix is stored in column
|
||||
* major (openGL) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix store(FloatBuffer buf);
|
||||
|
||||
|
||||
/**
|
||||
* Store this matrix in a float buffer. The matrix is stored in row
|
||||
* major (maths) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix storeTranspose(FloatBuffer buf);
|
||||
|
||||
|
||||
/**
|
||||
* Transpose this matrix
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix transpose();
|
||||
|
||||
|
||||
/**
|
||||
* Set this matrix to 0.
|
||||
* @return this
|
||||
*/
|
||||
public abstract Matrix setZero();
|
||||
|
||||
|
||||
/**
|
||||
* @return the determinant of the matrix
|
||||
*/
|
||||
public abstract float determinant();
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
* Holds a 2x2 matrix
|
||||
*
|
||||
* @author cix_foo <cix_foo@users.sourceforge.net>
|
||||
* @version $Revision$
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
public class Matrix2f extends Matrix implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public float m00, m01, m10, m11;
|
||||
|
||||
/**
|
||||
* Constructor for Matrix2f. The matrix is initialised to the identity.
|
||||
*/
|
||||
public Matrix2f() {
|
||||
setIdentity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Matrix2f(Matrix2f src) {
|
||||
load(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from another matrix
|
||||
* @param src The source matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix2f load(Matrix2f src) {
|
||||
return load(src, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the source matrix to the destination matrix.
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix, or null if a new one should be created.
|
||||
* @return The copied matrix
|
||||
*/
|
||||
public static Matrix2f load(Matrix2f src, Matrix2f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix2f();
|
||||
|
||||
dest.m00 = src.m00;
|
||||
dest.m01 = src.m01;
|
||||
dest.m10 = src.m10;
|
||||
dest.m11 = src.m11;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a float buffer. The buffer stores the matrix in column major
|
||||
* (OpenGL) order.
|
||||
*
|
||||
* @param buf A float buffer to read from
|
||||
* @return this
|
||||
*/
|
||||
public Matrix load(FloatBuffer buf) {
|
||||
|
||||
m00 = buf.get();
|
||||
m01 = buf.get();
|
||||
m10 = buf.get();
|
||||
m11 = buf.get();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a float buffer. The buffer stores the matrix in row major
|
||||
* (mathematical) order.
|
||||
*
|
||||
* @param buf A float buffer to read from
|
||||
* @return this
|
||||
*/
|
||||
public Matrix loadTranspose(FloatBuffer buf) {
|
||||
|
||||
m00 = buf.get();
|
||||
m10 = buf.get();
|
||||
m01 = buf.get();
|
||||
m11 = buf.get();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this matrix in a float buffer. The matrix is stored in column
|
||||
* major (openGL) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
*/
|
||||
public Matrix store(FloatBuffer buf) {
|
||||
buf.put(m00);
|
||||
buf.put(m01);
|
||||
buf.put(m10);
|
||||
buf.put(m11);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this matrix in a float buffer. The matrix is stored in row
|
||||
* major (maths) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
*/
|
||||
public Matrix storeTranspose(FloatBuffer buf) {
|
||||
buf.put(m00);
|
||||
buf.put(m10);
|
||||
buf.put(m01);
|
||||
buf.put(m11);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Add two matrices together and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix2f add(Matrix2f left, Matrix2f right, Matrix2f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix2f();
|
||||
|
||||
dest.m00 = left.m00 + right.m00;
|
||||
dest.m01 = left.m01 + right.m01;
|
||||
dest.m10 = left.m10 + right.m10;
|
||||
dest.m11 = left.m11 + right.m11;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract the right matrix from the left and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix2f sub(Matrix2f left, Matrix2f right, Matrix2f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix2f();
|
||||
|
||||
dest.m00 = left.m00 - right.m00;
|
||||
dest.m01 = left.m01 - right.m01;
|
||||
dest.m10 = left.m10 - right.m10;
|
||||
dest.m11 = left.m11 - right.m11;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply the right matrix by the left and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix2f mul(Matrix2f left, Matrix2f right, Matrix2f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix2f();
|
||||
|
||||
float m00 = left.m00 * right.m00 + left.m10 * right.m01;
|
||||
float m01 = left.m01 * right.m00 + left.m11 * right.m01;
|
||||
float m10 = left.m00 * right.m10 + left.m10 * right.m11;
|
||||
float m11 = left.m01 * right.m10 + left.m11 * right.m11;
|
||||
|
||||
dest.m00 = m00;
|
||||
dest.m01 = m01;
|
||||
dest.m10 = m10;
|
||||
dest.m11 = m11;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a Vector by a matrix and return the result in a destination
|
||||
* vector.
|
||||
* @param left The left matrix
|
||||
* @param right The right vector
|
||||
* @param dest The destination vector, or null if a new one is to be created
|
||||
* @return the destination vector
|
||||
*/
|
||||
public static Vector2f transform(Matrix2f left, Vector2f right, Vector2f dest) {
|
||||
if (dest == null)
|
||||
dest = new Vector2f();
|
||||
|
||||
float x = left.m00 * right.x + left.m10 * right.y;
|
||||
float y = left.m01 * right.x + left.m11 * right.y;
|
||||
|
||||
dest.x = x;
|
||||
dest.y = y;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose this matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix transpose() {
|
||||
return transpose(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose this matrix and place the result in another matrix.
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return the transposed matrix
|
||||
*/
|
||||
public Matrix2f transpose(Matrix2f dest) {
|
||||
return transpose(this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose the source matrix and place the result in the destination matrix.
|
||||
* @param src The source matrix or null if a new matrix is to be created
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return the transposed matrix
|
||||
*/
|
||||
public static Matrix2f transpose(Matrix2f src, Matrix2f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix2f();
|
||||
|
||||
float m01 = src.m10;
|
||||
float m10 = src.m01;
|
||||
|
||||
dest.m01 = m01;
|
||||
dest.m10 = m10;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invert this matrix
|
||||
* @return this if successful, null otherwise
|
||||
*/
|
||||
public Matrix invert() {
|
||||
return invert(this, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invert the source matrix and place the result in the destination matrix.
|
||||
* @param src The source matrix to be inverted
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return The inverted matrix, or null if source can't be reverted.
|
||||
*/
|
||||
public static Matrix2f invert(Matrix2f src, Matrix2f dest) {
|
||||
/*
|
||||
*inv(A) = 1/det(A) * adj(A);
|
||||
*/
|
||||
|
||||
float determinant = src.determinant();
|
||||
if (determinant != 0) {
|
||||
if (dest == null)
|
||||
dest = new Matrix2f();
|
||||
float determinant_inv = 1f/determinant;
|
||||
float t00 = src.m11*determinant_inv;
|
||||
float t01 = -src.m01*determinant_inv;
|
||||
float t11 = src.m00*determinant_inv;
|
||||
float t10 = -src.m10*determinant_inv;
|
||||
|
||||
dest.m00 = t00;
|
||||
dest.m01 = t01;
|
||||
dest.m10 = t10;
|
||||
dest.m11 = t11;
|
||||
return dest;
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this matrix
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(m00).append(' ').append(m10).append(' ').append('\n');
|
||||
buf.append(m01).append(' ').append(m11).append(' ').append('\n');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate this matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix negate() {
|
||||
return negate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate this matrix and stash the result in another matrix.
|
||||
* @param dest The destination matrix, or null if a new matrix is to be created
|
||||
* @return the negated matrix
|
||||
*/
|
||||
public Matrix2f negate(Matrix2f dest) {
|
||||
return negate(this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the source matrix and stash the result in the destination matrix.
|
||||
* @param src The source matrix to be negated
|
||||
* @param dest The destination matrix, or null if a new matrix is to be created
|
||||
* @return the negated matrix
|
||||
*/
|
||||
public static Matrix2f negate(Matrix2f src, Matrix2f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix2f();
|
||||
|
||||
dest.m00 = -src.m00;
|
||||
dest.m01 = -src.m01;
|
||||
dest.m10 = -src.m10;
|
||||
dest.m11 = -src.m11;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this matrix to be the identity matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Matrix setIdentity() {
|
||||
return setIdentity(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source matrix to be the identity matrix.
|
||||
* @param src The matrix to set to the identity.
|
||||
* @return The source matrix
|
||||
*/
|
||||
public static Matrix2f setIdentity(Matrix2f src) {
|
||||
src.m00 = 1.0f;
|
||||
src.m01 = 0.0f;
|
||||
src.m10 = 0.0f;
|
||||
src.m11 = 1.0f;
|
||||
return src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this matrix to 0.
|
||||
* @return this
|
||||
*/
|
||||
public Matrix setZero() {
|
||||
return setZero(this);
|
||||
}
|
||||
|
||||
public static Matrix2f setZero(Matrix2f src) {
|
||||
src.m00 = 0.0f;
|
||||
src.m01 = 0.0f;
|
||||
src.m10 = 0.0f;
|
||||
src.m11 = 0.0f;
|
||||
return src;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.vector.Matrix#determinant()
|
||||
*/
|
||||
public float determinant() {
|
||||
return m00 * m11 - m01*m10;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
* Holds a 3x3 matrix.
|
||||
*
|
||||
* @author cix_foo <cix_foo@users.sourceforge.net>
|
||||
* @version $Revision$
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
public class Matrix3f extends Matrix implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public float m00,
|
||||
m01,
|
||||
m02,
|
||||
m10,
|
||||
m11,
|
||||
m12,
|
||||
m20,
|
||||
m21,
|
||||
m22;
|
||||
|
||||
/**
|
||||
* Constructor for Matrix3f. Matrix is initialised to the identity.
|
||||
*/
|
||||
public Matrix3f() {
|
||||
super();
|
||||
setIdentity();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from another matrix
|
||||
* @param src The source matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix3f load(Matrix3f src) {
|
||||
return load(src, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy source matrix to destination matrix
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix, or null of a new matrix is to be created
|
||||
* @return The copied matrix
|
||||
*/
|
||||
public static Matrix3f load(Matrix3f src, Matrix3f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix3f();
|
||||
|
||||
dest.m00 = src.m00;
|
||||
dest.m10 = src.m10;
|
||||
dest.m20 = src.m20;
|
||||
dest.m01 = src.m01;
|
||||
dest.m11 = src.m11;
|
||||
dest.m21 = src.m21;
|
||||
dest.m02 = src.m02;
|
||||
dest.m12 = src.m12;
|
||||
dest.m22 = src.m22;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a float buffer. The buffer stores the matrix in column major
|
||||
* (OpenGL) order.
|
||||
*
|
||||
* @param buf A float buffer to read from
|
||||
* @return this
|
||||
*/
|
||||
public Matrix load(FloatBuffer buf) {
|
||||
|
||||
m00 = buf.get();
|
||||
m01 = buf.get();
|
||||
m02 = buf.get();
|
||||
m10 = buf.get();
|
||||
m11 = buf.get();
|
||||
m12 = buf.get();
|
||||
m20 = buf.get();
|
||||
m21 = buf.get();
|
||||
m22 = buf.get();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a float buffer. The buffer stores the matrix in row major
|
||||
* (maths) order.
|
||||
*
|
||||
* @param buf A float buffer to read from
|
||||
* @return this
|
||||
*/
|
||||
public Matrix loadTranspose(FloatBuffer buf) {
|
||||
|
||||
m00 = buf.get();
|
||||
m10 = buf.get();
|
||||
m20 = buf.get();
|
||||
m01 = buf.get();
|
||||
m11 = buf.get();
|
||||
m21 = buf.get();
|
||||
m02 = buf.get();
|
||||
m12 = buf.get();
|
||||
m22 = buf.get();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this matrix in a float buffer. The matrix is stored in column
|
||||
* major (openGL) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
*/
|
||||
public Matrix store(FloatBuffer buf) {
|
||||
buf.put(m00);
|
||||
buf.put(m01);
|
||||
buf.put(m02);
|
||||
buf.put(m10);
|
||||
buf.put(m11);
|
||||
buf.put(m12);
|
||||
buf.put(m20);
|
||||
buf.put(m21);
|
||||
buf.put(m22);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Matrix store(float[] buf) {
|
||||
buf[0] = m00;
|
||||
buf[1] = m01;
|
||||
buf[2] = m02;
|
||||
buf[3] = m10;
|
||||
buf[4] = m11;
|
||||
buf[5] = m12;
|
||||
buf[6] = m20;
|
||||
buf[7] = m21;
|
||||
buf[8] = m22;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this matrix in a float buffer. The matrix is stored in row
|
||||
* major (maths) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
*/
|
||||
public Matrix storeTranspose(FloatBuffer buf) {
|
||||
buf.put(m00);
|
||||
buf.put(m10);
|
||||
buf.put(m20);
|
||||
buf.put(m01);
|
||||
buf.put(m11);
|
||||
buf.put(m21);
|
||||
buf.put(m02);
|
||||
buf.put(m12);
|
||||
buf.put(m22);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add two matrices together and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix3f add(Matrix3f left, Matrix3f right, Matrix3f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix3f();
|
||||
|
||||
dest.m00 = left.m00 + right.m00;
|
||||
dest.m01 = left.m01 + right.m01;
|
||||
dest.m02 = left.m02 + right.m02;
|
||||
dest.m10 = left.m10 + right.m10;
|
||||
dest.m11 = left.m11 + right.m11;
|
||||
dest.m12 = left.m12 + right.m12;
|
||||
dest.m20 = left.m20 + right.m20;
|
||||
dest.m21 = left.m21 + right.m21;
|
||||
dest.m22 = left.m22 + right.m22;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract the right matrix from the left and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix3f sub(Matrix3f left, Matrix3f right, Matrix3f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix3f();
|
||||
|
||||
dest.m00 = left.m00 - right.m00;
|
||||
dest.m01 = left.m01 - right.m01;
|
||||
dest.m02 = left.m02 - right.m02;
|
||||
dest.m10 = left.m10 - right.m10;
|
||||
dest.m11 = left.m11 - right.m11;
|
||||
dest.m12 = left.m12 - right.m12;
|
||||
dest.m20 = left.m20 - right.m20;
|
||||
dest.m21 = left.m21 - right.m21;
|
||||
dest.m22 = left.m22 - right.m22;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply the right matrix by the left and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix3f mul(Matrix3f left, Matrix3f right, Matrix3f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix3f();
|
||||
|
||||
float m00 =
|
||||
left.m00 * right.m00 + left.m10 * right.m01 + left.m20 * right.m02;
|
||||
float m01 =
|
||||
left.m01 * right.m00 + left.m11 * right.m01 + left.m21 * right.m02;
|
||||
float m02 =
|
||||
left.m02 * right.m00 + left.m12 * right.m01 + left.m22 * right.m02;
|
||||
float m10 =
|
||||
left.m00 * right.m10 + left.m10 * right.m11 + left.m20 * right.m12;
|
||||
float m11 =
|
||||
left.m01 * right.m10 + left.m11 * right.m11 + left.m21 * right.m12;
|
||||
float m12 =
|
||||
left.m02 * right.m10 + left.m12 * right.m11 + left.m22 * right.m12;
|
||||
float m20 =
|
||||
left.m00 * right.m20 + left.m10 * right.m21 + left.m20 * right.m22;
|
||||
float m21 =
|
||||
left.m01 * right.m20 + left.m11 * right.m21 + left.m21 * right.m22;
|
||||
float m22 =
|
||||
left.m02 * right.m20 + left.m12 * right.m21 + left.m22 * right.m22;
|
||||
|
||||
dest.m00 = m00;
|
||||
dest.m01 = m01;
|
||||
dest.m02 = m02;
|
||||
dest.m10 = m10;
|
||||
dest.m11 = m11;
|
||||
dest.m12 = m12;
|
||||
dest.m20 = m20;
|
||||
dest.m21 = m21;
|
||||
dest.m22 = m22;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a Vector by a matrix and return the result in a destination
|
||||
* vector.
|
||||
* @param left The left matrix
|
||||
* @param right The right vector
|
||||
* @param dest The destination vector, or null if a new one is to be created
|
||||
* @return the destination vector
|
||||
*/
|
||||
public static Vector3f transform(Matrix3f left, Vector3f right, Vector3f dest) {
|
||||
if (dest == null)
|
||||
dest = new Vector3f();
|
||||
|
||||
float x = left.m00 * right.x + left.m10 * right.y + left.m20 * right.z;
|
||||
float y = left.m01 * right.x + left.m11 * right.y + left.m21 * right.z;
|
||||
float z = left.m02 * right.x + left.m12 * right.y + left.m22 * right.z;
|
||||
|
||||
dest.x = x;
|
||||
dest.y = y;
|
||||
dest.z = z;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose this matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix transpose() {
|
||||
return transpose(this, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose this matrix and place the result in another matrix
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return the transposed matrix
|
||||
*/
|
||||
public Matrix3f transpose(Matrix3f dest) {
|
||||
return transpose(this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose the source matrix and place the result into the destination matrix
|
||||
* @param src The source matrix to be transposed
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return the transposed matrix
|
||||
*/
|
||||
public static Matrix3f transpose(Matrix3f src, Matrix3f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix3f();
|
||||
float m00 = src.m00;
|
||||
float m01 = src.m10;
|
||||
float m02 = src.m20;
|
||||
float m10 = src.m01;
|
||||
float m11 = src.m11;
|
||||
float m12 = src.m21;
|
||||
float m20 = src.m02;
|
||||
float m21 = src.m12;
|
||||
float m22 = src.m22;
|
||||
|
||||
dest.m00 = m00;
|
||||
dest.m01 = m01;
|
||||
dest.m02 = m02;
|
||||
dest.m10 = m10;
|
||||
dest.m11 = m11;
|
||||
dest.m12 = m12;
|
||||
dest.m20 = m20;
|
||||
dest.m21 = m21;
|
||||
dest.m22 = m22;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the determinant of the matrix
|
||||
*/
|
||||
public float determinant() {
|
||||
float f =
|
||||
m00 * (m11 * m22 - m12 * m21)
|
||||
+ m01 * (m12 * m20 - m10 * m22)
|
||||
+ m02 * (m10 * m21 - m11 * m20);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this matrix
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(m00).append(' ').append(m10).append(' ').append(m20).append(' ').append('\n');
|
||||
buf.append(m01).append(' ').append(m11).append(' ').append(m21).append(' ').append('\n');
|
||||
buf.append(m02).append(' ').append(m12).append(' ').append(m22).append(' ').append('\n');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invert this matrix
|
||||
* @return this if successful, null otherwise
|
||||
*/
|
||||
public Matrix invert() {
|
||||
return invert(this, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invert the source matrix and put the result into the destination matrix
|
||||
* @param src The source matrix to be inverted
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return The inverted matrix if successful, null otherwise
|
||||
*/
|
||||
public static Matrix3f invert(Matrix3f src, Matrix3f dest) {
|
||||
float determinant = src.determinant();
|
||||
|
||||
if (determinant != 0) {
|
||||
if (dest == null)
|
||||
dest = new Matrix3f();
|
||||
/* do it the ordinary way
|
||||
*
|
||||
* inv(A) = 1/det(A) * adj(T), where adj(T) = transpose(Conjugate Matrix)
|
||||
*
|
||||
* m00 m01 m02
|
||||
* m10 m11 m12
|
||||
* m20 m21 m22
|
||||
*/
|
||||
float determinant_inv = 1f/determinant;
|
||||
|
||||
// get the conjugate matrix
|
||||
float t00 = src.m11 * src.m22 - src.m12* src.m21;
|
||||
float t01 = - src.m10 * src.m22 + src.m12 * src.m20;
|
||||
float t02 = src.m10 * src.m21 - src.m11 * src.m20;
|
||||
float t10 = - src.m01 * src.m22 + src.m02 * src.m21;
|
||||
float t11 = src.m00 * src.m22 - src.m02 * src.m20;
|
||||
float t12 = - src.m00 * src.m21 + src.m01 * src.m20;
|
||||
float t20 = src.m01 * src.m12 - src.m02 * src.m11;
|
||||
float t21 = -src.m00 * src.m12 + src.m02 * src.m10;
|
||||
float t22 = src.m00 * src.m11 - src.m01 * src.m10;
|
||||
|
||||
dest.m00 = t00*determinant_inv;
|
||||
dest.m11 = t11*determinant_inv;
|
||||
dest.m22 = t22*determinant_inv;
|
||||
dest.m01 = t10*determinant_inv;
|
||||
dest.m10 = t01*determinant_inv;
|
||||
dest.m20 = t02*determinant_inv;
|
||||
dest.m02 = t20*determinant_inv;
|
||||
dest.m12 = t21*determinant_inv;
|
||||
dest.m21 = t12*determinant_inv;
|
||||
return dest;
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Negate this matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix negate() {
|
||||
return negate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate this matrix and place the result in a destination matrix.
|
||||
* @param dest The destination matrix, or null if a new matrix is to be created
|
||||
* @return the negated matrix
|
||||
*/
|
||||
public Matrix3f negate(Matrix3f dest) {
|
||||
return negate(this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate the source matrix and place the result in the destination matrix.
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix, or null if a new matrix is to be created
|
||||
* @return the negated matrix
|
||||
*/
|
||||
public static Matrix3f negate(Matrix3f src, Matrix3f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix3f();
|
||||
|
||||
dest.m00 = -src.m00;
|
||||
dest.m01 = -src.m02;
|
||||
dest.m02 = -src.m01;
|
||||
dest.m10 = -src.m10;
|
||||
dest.m11 = -src.m12;
|
||||
dest.m12 = -src.m11;
|
||||
dest.m20 = -src.m20;
|
||||
dest.m21 = -src.m22;
|
||||
dest.m22 = -src.m21;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this matrix to be the identity matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Matrix setIdentity() {
|
||||
return setIdentity(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the matrix to be the identity matrix.
|
||||
* @param m The matrix to be set to the identity
|
||||
* @return m
|
||||
*/
|
||||
public static Matrix3f setIdentity(Matrix3f m) {
|
||||
m.m00 = 1.0f;
|
||||
m.m01 = 0.0f;
|
||||
m.m02 = 0.0f;
|
||||
m.m10 = 0.0f;
|
||||
m.m11 = 1.0f;
|
||||
m.m12 = 0.0f;
|
||||
m.m20 = 0.0f;
|
||||
m.m21 = 0.0f;
|
||||
m.m22 = 1.0f;
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this matrix to 0.
|
||||
* @return this
|
||||
*/
|
||||
public Matrix setZero() {
|
||||
return setZero(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the matrix matrix to 0.
|
||||
* @param m The matrix to be set to 0
|
||||
* @return m
|
||||
*/
|
||||
public static Matrix3f setZero(Matrix3f m) {
|
||||
m.m00 = 0.0f;
|
||||
m.m01 = 0.0f;
|
||||
m.m02 = 0.0f;
|
||||
m.m10 = 0.0f;
|
||||
m.m11 = 0.0f;
|
||||
m.m12 = 0.0f;
|
||||
m.m20 = 0.0f;
|
||||
m.m21 = 0.0f;
|
||||
m.m22 = 0.0f;
|
||||
return m;
|
||||
}
|
||||
|
||||
public boolean equals(Object m) {
|
||||
return (m instanceof Matrix3f) && equal(this, (Matrix3f)m);
|
||||
}
|
||||
|
||||
public static boolean equal(Matrix3f a, Matrix3f b) {
|
||||
return a.m00 == b.m00 &&
|
||||
a.m01 == b.m01 &&
|
||||
a.m02 == b.m02 &&
|
||||
a.m10 == b.m10 &&
|
||||
a.m11 == b.m11 &&
|
||||
a.m12 == b.m12 &&
|
||||
a.m20 == b.m20 &&
|
||||
a.m21 == b.m21 &&
|
||||
a.m22 == b.m22;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,892 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* Holds a 4x4 float matrix.
|
||||
*
|
||||
* @author foo
|
||||
*/
|
||||
public class Matrix4f extends Matrix implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public float m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33;
|
||||
|
||||
/**
|
||||
* Construct a new matrix, initialized to the identity.
|
||||
*/
|
||||
public Matrix4f() {
|
||||
super();
|
||||
setIdentity();
|
||||
}
|
||||
|
||||
public Matrix4f(final Matrix4f src) {
|
||||
super();
|
||||
load(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this matrix
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(m00).append(' ').append(m10).append(' ').append(m20).append(' ').append(m30).append('\n');
|
||||
buf.append(m01).append(' ').append(m11).append(' ').append(m21).append(' ').append(m31).append('\n');
|
||||
buf.append(m02).append(' ').append(m12).append(' ').append(m22).append(' ').append(m32).append('\n');
|
||||
buf.append(m03).append(' ').append(m13).append(' ').append(m23).append(' ').append(m33).append('\n');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this matrix to be the identity matrix.
|
||||
* @return this
|
||||
*/
|
||||
public Matrix setIdentity() {
|
||||
return setIdentity(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given matrix to be the identity matrix.
|
||||
* @param m The matrix to set to the identity
|
||||
* @return m
|
||||
*/
|
||||
public static Matrix4f setIdentity(Matrix4f m) {
|
||||
m.m00 = 1.0f;
|
||||
m.m01 = 0.0f;
|
||||
m.m02 = 0.0f;
|
||||
m.m03 = 0.0f;
|
||||
m.m10 = 0.0f;
|
||||
m.m11 = 1.0f;
|
||||
m.m12 = 0.0f;
|
||||
m.m13 = 0.0f;
|
||||
m.m20 = 0.0f;
|
||||
m.m21 = 0.0f;
|
||||
m.m22 = 1.0f;
|
||||
m.m23 = 0.0f;
|
||||
m.m30 = 0.0f;
|
||||
m.m31 = 0.0f;
|
||||
m.m32 = 0.0f;
|
||||
m.m33 = 1.0f;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this matrix to 0.
|
||||
* @return this
|
||||
*/
|
||||
public Matrix setZero() {
|
||||
return setZero(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given matrix to 0.
|
||||
* @param m The matrix to set to 0
|
||||
* @return m
|
||||
*/
|
||||
public static Matrix4f setZero(Matrix4f m) {
|
||||
m.m00 = 0.0f;
|
||||
m.m01 = 0.0f;
|
||||
m.m02 = 0.0f;
|
||||
m.m03 = 0.0f;
|
||||
m.m10 = 0.0f;
|
||||
m.m11 = 0.0f;
|
||||
m.m12 = 0.0f;
|
||||
m.m13 = 0.0f;
|
||||
m.m20 = 0.0f;
|
||||
m.m21 = 0.0f;
|
||||
m.m22 = 0.0f;
|
||||
m.m23 = 0.0f;
|
||||
m.m30 = 0.0f;
|
||||
m.m31 = 0.0f;
|
||||
m.m32 = 0.0f;
|
||||
m.m33 = 0.0f;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from another matrix4f
|
||||
* @param src The source matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix4f load(Matrix4f src) {
|
||||
return load(src, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the source matrix to the destination matrix
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix, or null of a new one is to be created
|
||||
* @return The copied matrix
|
||||
*/
|
||||
public static Matrix4f load(Matrix4f src, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
dest.m00 = src.m00;
|
||||
dest.m01 = src.m01;
|
||||
dest.m02 = src.m02;
|
||||
dest.m03 = src.m03;
|
||||
dest.m10 = src.m10;
|
||||
dest.m11 = src.m11;
|
||||
dest.m12 = src.m12;
|
||||
dest.m13 = src.m13;
|
||||
dest.m20 = src.m20;
|
||||
dest.m21 = src.m21;
|
||||
dest.m22 = src.m22;
|
||||
dest.m23 = src.m23;
|
||||
dest.m30 = src.m30;
|
||||
dest.m31 = src.m31;
|
||||
dest.m32 = src.m32;
|
||||
dest.m33 = src.m33;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a float buffer. The buffer stores the matrix in column major
|
||||
* (OpenGL) order.
|
||||
*
|
||||
* @param buf A float buffer to read from
|
||||
* @return this
|
||||
*/
|
||||
public Matrix load(FloatBuffer buf) {
|
||||
|
||||
m00 = buf.get();
|
||||
m01 = buf.get();
|
||||
m02 = buf.get();
|
||||
m03 = buf.get();
|
||||
m10 = buf.get();
|
||||
m11 = buf.get();
|
||||
m12 = buf.get();
|
||||
m13 = buf.get();
|
||||
m20 = buf.get();
|
||||
m21 = buf.get();
|
||||
m22 = buf.get();
|
||||
m23 = buf.get();
|
||||
m30 = buf.get();
|
||||
m31 = buf.get();
|
||||
m32 = buf.get();
|
||||
m33 = buf.get();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from a float buffer. The buffer stores the matrix in row major
|
||||
* (maths) order.
|
||||
*
|
||||
* @param buf A float buffer to read from
|
||||
* @return this
|
||||
*/
|
||||
public Matrix loadTranspose(FloatBuffer buf) {
|
||||
|
||||
m00 = buf.get();
|
||||
m10 = buf.get();
|
||||
m20 = buf.get();
|
||||
m30 = buf.get();
|
||||
m01 = buf.get();
|
||||
m11 = buf.get();
|
||||
m21 = buf.get();
|
||||
m31 = buf.get();
|
||||
m02 = buf.get();
|
||||
m12 = buf.get();
|
||||
m22 = buf.get();
|
||||
m32 = buf.get();
|
||||
m03 = buf.get();
|
||||
m13 = buf.get();
|
||||
m23 = buf.get();
|
||||
m33 = buf.get();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this matrix in a float buffer. The matrix is stored in column
|
||||
* major (openGL) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
*/
|
||||
public Matrix store(FloatBuffer buf) {
|
||||
buf.put(m00);
|
||||
buf.put(m01);
|
||||
buf.put(m02);
|
||||
buf.put(m03);
|
||||
buf.put(m10);
|
||||
buf.put(m11);
|
||||
buf.put(m12);
|
||||
buf.put(m13);
|
||||
buf.put(m20);
|
||||
buf.put(m21);
|
||||
buf.put(m22);
|
||||
buf.put(m23);
|
||||
buf.put(m30);
|
||||
buf.put(m31);
|
||||
buf.put(m32);
|
||||
buf.put(m33);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Matrix store(float[] buf) {
|
||||
buf[0] = m00;
|
||||
buf[1] = m01;
|
||||
buf[2] = m02;
|
||||
buf[3] = m03;
|
||||
buf[4] = m10;
|
||||
buf[5] = m11;
|
||||
buf[6] = m12;
|
||||
buf[7] = m13;
|
||||
buf[8] = m20;
|
||||
buf[9] = m21;
|
||||
buf[10] = m22;
|
||||
buf[11] = m23;
|
||||
buf[12] = m30;
|
||||
buf[13] = m31;
|
||||
buf[14] = m32;
|
||||
buf[15] = m33;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this matrix in a float buffer. The matrix is stored in row
|
||||
* major (maths) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
*/
|
||||
public Matrix storeTranspose(FloatBuffer buf) {
|
||||
buf.put(m00);
|
||||
buf.put(m10);
|
||||
buf.put(m20);
|
||||
buf.put(m30);
|
||||
buf.put(m01);
|
||||
buf.put(m11);
|
||||
buf.put(m21);
|
||||
buf.put(m31);
|
||||
buf.put(m02);
|
||||
buf.put(m12);
|
||||
buf.put(m22);
|
||||
buf.put(m32);
|
||||
buf.put(m03);
|
||||
buf.put(m13);
|
||||
buf.put(m23);
|
||||
buf.put(m33);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the rotation portion of this matrix in a float buffer. The matrix is stored in column
|
||||
* major (openGL) order.
|
||||
* @param buf The buffer to store this matrix in
|
||||
*/
|
||||
public Matrix store3f(FloatBuffer buf) {
|
||||
buf.put(m00);
|
||||
buf.put(m01);
|
||||
buf.put(m02);
|
||||
buf.put(m10);
|
||||
buf.put(m11);
|
||||
buf.put(m12);
|
||||
buf.put(m20);
|
||||
buf.put(m21);
|
||||
buf.put(m22);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add two matrices together and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix4f add(Matrix4f left, Matrix4f right, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
|
||||
dest.m00 = left.m00 + right.m00;
|
||||
dest.m01 = left.m01 + right.m01;
|
||||
dest.m02 = left.m02 + right.m02;
|
||||
dest.m03 = left.m03 + right.m03;
|
||||
dest.m10 = left.m10 + right.m10;
|
||||
dest.m11 = left.m11 + right.m11;
|
||||
dest.m12 = left.m12 + right.m12;
|
||||
dest.m13 = left.m13 + right.m13;
|
||||
dest.m20 = left.m20 + right.m20;
|
||||
dest.m21 = left.m21 + right.m21;
|
||||
dest.m22 = left.m22 + right.m22;
|
||||
dest.m23 = left.m23 + right.m23;
|
||||
dest.m30 = left.m30 + right.m30;
|
||||
dest.m31 = left.m31 + right.m31;
|
||||
dest.m32 = left.m32 + right.m32;
|
||||
dest.m33 = left.m33 + right.m33;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract the right matrix from the left and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix4f sub(Matrix4f left, Matrix4f right, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
|
||||
dest.m00 = left.m00 - right.m00;
|
||||
dest.m01 = left.m01 - right.m01;
|
||||
dest.m02 = left.m02 - right.m02;
|
||||
dest.m03 = left.m03 - right.m03;
|
||||
dest.m10 = left.m10 - right.m10;
|
||||
dest.m11 = left.m11 - right.m11;
|
||||
dest.m12 = left.m12 - right.m12;
|
||||
dest.m13 = left.m13 - right.m13;
|
||||
dest.m20 = left.m20 - right.m20;
|
||||
dest.m21 = left.m21 - right.m21;
|
||||
dest.m22 = left.m22 - right.m22;
|
||||
dest.m23 = left.m23 - right.m23;
|
||||
dest.m30 = left.m30 - right.m30;
|
||||
dest.m31 = left.m31 - right.m31;
|
||||
dest.m32 = left.m32 - right.m32;
|
||||
dest.m33 = left.m33 - right.m33;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiply the right matrix by the left and place the result in a third matrix.
|
||||
* @param left The left source matrix
|
||||
* @param right The right source matrix
|
||||
* @param dest The destination matrix, or null if a new one is to be created
|
||||
* @return the destination matrix
|
||||
*/
|
||||
public static Matrix4f mul(Matrix4f left, Matrix4f right, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
|
||||
float m00 = left.m00 * right.m00 + left.m10 * right.m01 + left.m20 * right.m02 + left.m30 * right.m03;
|
||||
float m01 = left.m01 * right.m00 + left.m11 * right.m01 + left.m21 * right.m02 + left.m31 * right.m03;
|
||||
float m02 = left.m02 * right.m00 + left.m12 * right.m01 + left.m22 * right.m02 + left.m32 * right.m03;
|
||||
float m03 = left.m03 * right.m00 + left.m13 * right.m01 + left.m23 * right.m02 + left.m33 * right.m03;
|
||||
float m10 = left.m00 * right.m10 + left.m10 * right.m11 + left.m20 * right.m12 + left.m30 * right.m13;
|
||||
float m11 = left.m01 * right.m10 + left.m11 * right.m11 + left.m21 * right.m12 + left.m31 * right.m13;
|
||||
float m12 = left.m02 * right.m10 + left.m12 * right.m11 + left.m22 * right.m12 + left.m32 * right.m13;
|
||||
float m13 = left.m03 * right.m10 + left.m13 * right.m11 + left.m23 * right.m12 + left.m33 * right.m13;
|
||||
float m20 = left.m00 * right.m20 + left.m10 * right.m21 + left.m20 * right.m22 + left.m30 * right.m23;
|
||||
float m21 = left.m01 * right.m20 + left.m11 * right.m21 + left.m21 * right.m22 + left.m31 * right.m23;
|
||||
float m22 = left.m02 * right.m20 + left.m12 * right.m21 + left.m22 * right.m22 + left.m32 * right.m23;
|
||||
float m23 = left.m03 * right.m20 + left.m13 * right.m21 + left.m23 * right.m22 + left.m33 * right.m23;
|
||||
float m30 = left.m00 * right.m30 + left.m10 * right.m31 + left.m20 * right.m32 + left.m30 * right.m33;
|
||||
float m31 = left.m01 * right.m30 + left.m11 * right.m31 + left.m21 * right.m32 + left.m31 * right.m33;
|
||||
float m32 = left.m02 * right.m30 + left.m12 * right.m31 + left.m22 * right.m32 + left.m32 * right.m33;
|
||||
float m33 = left.m03 * right.m30 + left.m13 * right.m31 + left.m23 * right.m32 + left.m33 * right.m33;
|
||||
|
||||
dest.m00 = m00;
|
||||
dest.m01 = m01;
|
||||
dest.m02 = m02;
|
||||
dest.m03 = m03;
|
||||
dest.m10 = m10;
|
||||
dest.m11 = m11;
|
||||
dest.m12 = m12;
|
||||
dest.m13 = m13;
|
||||
dest.m20 = m20;
|
||||
dest.m21 = m21;
|
||||
dest.m22 = m22;
|
||||
dest.m23 = m23;
|
||||
dest.m30 = m30;
|
||||
dest.m31 = m31;
|
||||
dest.m32 = m32;
|
||||
dest.m33 = m33;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a Vector by a matrix and return the result in a destination
|
||||
* vector.
|
||||
* @param left The left matrix
|
||||
* @param right The right vector
|
||||
* @param dest The destination vector, or null if a new one is to be created
|
||||
* @return the destination vector
|
||||
*/
|
||||
public static Vector4f transform(Matrix4f left, Vector4f right, Vector4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Vector4f();
|
||||
|
||||
float x = left.m00 * right.x + left.m10 * right.y + left.m20 * right.z + left.m30 * right.w;
|
||||
float y = left.m01 * right.x + left.m11 * right.y + left.m21 * right.z + left.m31 * right.w;
|
||||
float z = left.m02 * right.x + left.m12 * right.y + left.m22 * right.z + left.m32 * right.w;
|
||||
float w = left.m03 * right.x + left.m13 * right.y + left.m23 * right.z + left.m33 * right.w;
|
||||
|
||||
dest.x = x;
|
||||
dest.y = y;
|
||||
dest.z = z;
|
||||
dest.w = w;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose this matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix transpose() {
|
||||
return transpose(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate this matrix
|
||||
* @param vec The vector to translate by
|
||||
* @return this
|
||||
*/
|
||||
public Matrix4f translate(Vector2f vec) {
|
||||
return translate(vec, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate this matrix
|
||||
* @param vec The vector to translate by
|
||||
* @return this
|
||||
*/
|
||||
public Matrix4f translate(Vector3f vec) {
|
||||
return translate(vec, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales this matrix
|
||||
* @param vec The vector to scale by
|
||||
* @return this
|
||||
*/
|
||||
public Matrix4f scale(Vector3f vec) {
|
||||
return scale(vec, this, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales the source matrix and put the result in the destination matrix
|
||||
* @param vec The vector to scale by
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix, or null if a new matrix is to be created
|
||||
* @return The scaled matrix
|
||||
*/
|
||||
public static Matrix4f scale(Vector3f vec, Matrix4f src, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
dest.m00 = src.m00 * vec.x;
|
||||
dest.m01 = src.m01 * vec.x;
|
||||
dest.m02 = src.m02 * vec.x;
|
||||
dest.m03 = src.m03 * vec.x;
|
||||
dest.m10 = src.m10 * vec.y;
|
||||
dest.m11 = src.m11 * vec.y;
|
||||
dest.m12 = src.m12 * vec.y;
|
||||
dest.m13 = src.m13 * vec.y;
|
||||
dest.m20 = src.m20 * vec.z;
|
||||
dest.m21 = src.m21 * vec.z;
|
||||
dest.m22 = src.m22 * vec.z;
|
||||
dest.m23 = src.m23 * vec.z;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the matrix around the given axis the specified angle
|
||||
* @param angle the angle, in radians.
|
||||
* @param axis The vector representing the rotation axis. Must be normalized.
|
||||
* @return this
|
||||
*/
|
||||
public Matrix4f rotate(float angle, Vector3f axis) {
|
||||
return rotate(angle, axis, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the matrix around the given axis the specified angle
|
||||
* @param angle the angle, in radians.
|
||||
* @param axis The vector representing the rotation axis. Must be normalized.
|
||||
* @param dest The matrix to put the result, or null if a new matrix is to be created
|
||||
* @return The rotated matrix
|
||||
*/
|
||||
public Matrix4f rotate(float angle, Vector3f axis, Matrix4f dest) {
|
||||
return rotate(angle, axis, this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the source matrix around the given axis the specified angle and
|
||||
* put the result in the destination matrix.
|
||||
* @param angle the angle, in radians.
|
||||
* @param axis The vector representing the rotation axis. Must be normalized.
|
||||
* @param src The matrix to rotate
|
||||
* @param dest The matrix to put the result, or null if a new matrix is to be created
|
||||
* @return The rotated matrix
|
||||
*/
|
||||
public static Matrix4f rotate(float angle, Vector3f axis, Matrix4f src, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
float c = (float) Math.cos(angle);
|
||||
float s = (float) Math.sin(angle);
|
||||
float oneminusc = 1.0f - c;
|
||||
float xy = axis.x*axis.y;
|
||||
float yz = axis.y*axis.z;
|
||||
float xz = axis.x*axis.z;
|
||||
float xs = axis.x*s;
|
||||
float ys = axis.y*s;
|
||||
float zs = axis.z*s;
|
||||
|
||||
float f00 = axis.x*axis.x*oneminusc+c;
|
||||
float f01 = xy*oneminusc+zs;
|
||||
float f02 = xz*oneminusc-ys;
|
||||
// n[3] not used
|
||||
float f10 = xy*oneminusc-zs;
|
||||
float f11 = axis.y*axis.y*oneminusc+c;
|
||||
float f12 = yz*oneminusc+xs;
|
||||
// n[7] not used
|
||||
float f20 = xz*oneminusc+ys;
|
||||
float f21 = yz*oneminusc-xs;
|
||||
float f22 = axis.z*axis.z*oneminusc+c;
|
||||
|
||||
float t00 = src.m00 * f00 + src.m10 * f01 + src.m20 * f02;
|
||||
float t01 = src.m01 * f00 + src.m11 * f01 + src.m21 * f02;
|
||||
float t02 = src.m02 * f00 + src.m12 * f01 + src.m22 * f02;
|
||||
float t03 = src.m03 * f00 + src.m13 * f01 + src.m23 * f02;
|
||||
float t10 = src.m00 * f10 + src.m10 * f11 + src.m20 * f12;
|
||||
float t11 = src.m01 * f10 + src.m11 * f11 + src.m21 * f12;
|
||||
float t12 = src.m02 * f10 + src.m12 * f11 + src.m22 * f12;
|
||||
float t13 = src.m03 * f10 + src.m13 * f11 + src.m23 * f12;
|
||||
dest.m20 = src.m00 * f20 + src.m10 * f21 + src.m20 * f22;
|
||||
dest.m21 = src.m01 * f20 + src.m11 * f21 + src.m21 * f22;
|
||||
dest.m22 = src.m02 * f20 + src.m12 * f21 + src.m22 * f22;
|
||||
dest.m23 = src.m03 * f20 + src.m13 * f21 + src.m23 * f22;
|
||||
dest.m00 = t00;
|
||||
dest.m01 = t01;
|
||||
dest.m02 = t02;
|
||||
dest.m03 = t03;
|
||||
dest.m10 = t10;
|
||||
dest.m11 = t11;
|
||||
dest.m12 = t12;
|
||||
dest.m13 = t13;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate this matrix and stash the result in another matrix
|
||||
* @param vec The vector to translate by
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return the translated matrix
|
||||
*/
|
||||
public Matrix4f translate(Vector3f vec, Matrix4f dest) {
|
||||
return translate(vec, this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the source matrix and stash the result in the destination matrix
|
||||
* @param vec The vector to translate by
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return The translated matrix
|
||||
*/
|
||||
public static Matrix4f translate(Vector3f vec, Matrix4f src, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
|
||||
dest.m30 += src.m00 * vec.x + src.m10 * vec.y + src.m20 * vec.z;
|
||||
dest.m31 += src.m01 * vec.x + src.m11 * vec.y + src.m21 * vec.z;
|
||||
dest.m32 += src.m02 * vec.x + src.m12 * vec.y + src.m22 * vec.z;
|
||||
dest.m33 += src.m03 * vec.x + src.m13 * vec.y + src.m23 * vec.z;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate this matrix and stash the result in another matrix
|
||||
* @param vec The vector to translate by
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return the translated matrix
|
||||
*/
|
||||
public Matrix4f translate(Vector2f vec, Matrix4f dest) {
|
||||
return translate(vec, this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the source matrix and stash the result in the destination matrix
|
||||
* @param vec The vector to translate by
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return The translated matrix
|
||||
*/
|
||||
public static Matrix4f translate(Vector2f vec, Matrix4f src, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
|
||||
dest.m30 += src.m00 * vec.x + src.m10 * vec.y;
|
||||
dest.m31 += src.m01 * vec.x + src.m11 * vec.y;
|
||||
dest.m32 += src.m02 * vec.x + src.m12 * vec.y;
|
||||
dest.m33 += src.m03 * vec.x + src.m13 * vec.y;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose this matrix and place the result in another matrix
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return the transposed matrix
|
||||
*/
|
||||
public Matrix4f transpose(Matrix4f dest) {
|
||||
return transpose(this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transpose the source matrix and place the result in the destination matrix
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix or null if a new matrix is to be created
|
||||
* @return the transposed matrix
|
||||
*/
|
||||
public static Matrix4f transpose(Matrix4f src, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
float m00 = src.m00;
|
||||
float m01 = src.m10;
|
||||
float m02 = src.m20;
|
||||
float m03 = src.m30;
|
||||
float m10 = src.m01;
|
||||
float m11 = src.m11;
|
||||
float m12 = src.m21;
|
||||
float m13 = src.m31;
|
||||
float m20 = src.m02;
|
||||
float m21 = src.m12;
|
||||
float m22 = src.m22;
|
||||
float m23 = src.m32;
|
||||
float m30 = src.m03;
|
||||
float m31 = src.m13;
|
||||
float m32 = src.m23;
|
||||
float m33 = src.m33;
|
||||
|
||||
dest.m00 = m00;
|
||||
dest.m01 = m01;
|
||||
dest.m02 = m02;
|
||||
dest.m03 = m03;
|
||||
dest.m10 = m10;
|
||||
dest.m11 = m11;
|
||||
dest.m12 = m12;
|
||||
dest.m13 = m13;
|
||||
dest.m20 = m20;
|
||||
dest.m21 = m21;
|
||||
dest.m22 = m22;
|
||||
dest.m23 = m23;
|
||||
dest.m30 = m30;
|
||||
dest.m31 = m31;
|
||||
dest.m32 = m32;
|
||||
dest.m33 = m33;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the determinant of the matrix
|
||||
*/
|
||||
public float determinant() {
|
||||
float f =
|
||||
m00
|
||||
* ((m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32)
|
||||
- m13 * m22 * m31
|
||||
- m11 * m23 * m32
|
||||
- m12 * m21 * m33);
|
||||
f -= m01
|
||||
* ((m10 * m22 * m33 + m12 * m23 * m30 + m13 * m20 * m32)
|
||||
- m13 * m22 * m30
|
||||
- m10 * m23 * m32
|
||||
- m12 * m20 * m33);
|
||||
f += m02
|
||||
* ((m10 * m21 * m33 + m11 * m23 * m30 + m13 * m20 * m31)
|
||||
- m13 * m21 * m30
|
||||
- m10 * m23 * m31
|
||||
- m11 * m20 * m33);
|
||||
f -= m03
|
||||
* ((m10 * m21 * m32 + m11 * m22 * m30 + m12 * m20 * m31)
|
||||
- m12 * m21 * m30
|
||||
- m10 * m22 * m31
|
||||
- m11 * m20 * m32);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the determinant of a 3x3 matrix
|
||||
* @return result
|
||||
*/
|
||||
|
||||
private static float determinant3x3(float t00, float t01, float t02,
|
||||
float t10, float t11, float t12,
|
||||
float t20, float t21, float t22)
|
||||
{
|
||||
return t00 * (t11 * t22 - t12 * t21)
|
||||
+ t01 * (t12 * t20 - t10 * t22)
|
||||
+ t02 * (t10 * t21 - t11 * t20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invert this matrix
|
||||
* @return this if successful, null otherwise
|
||||
*/
|
||||
public Matrix invert() {
|
||||
return invert(this, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invert the source matrix and put the result in the destination
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix, or null if a new matrix is to be created
|
||||
* @return The inverted matrix if successful, null otherwise
|
||||
*/
|
||||
public static Matrix4f invert(Matrix4f src, Matrix4f dest) {
|
||||
float determinant = src.determinant();
|
||||
|
||||
if (determinant != 0) {
|
||||
/*
|
||||
* m00 m01 m02 m03
|
||||
* m10 m11 m12 m13
|
||||
* m20 m21 m22 m23
|
||||
* m30 m31 m32 m33
|
||||
*/
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
float determinant_inv = 1f/determinant;
|
||||
|
||||
// first row
|
||||
float t00 = determinant3x3(src.m11, src.m12, src.m13, src.m21, src.m22, src.m23, src.m31, src.m32, src.m33);
|
||||
float t01 = -determinant3x3(src.m10, src.m12, src.m13, src.m20, src.m22, src.m23, src.m30, src.m32, src.m33);
|
||||
float t02 = determinant3x3(src.m10, src.m11, src.m13, src.m20, src.m21, src.m23, src.m30, src.m31, src.m33);
|
||||
float t03 = -determinant3x3(src.m10, src.m11, src.m12, src.m20, src.m21, src.m22, src.m30, src.m31, src.m32);
|
||||
// second row
|
||||
float t10 = -determinant3x3(src.m01, src.m02, src.m03, src.m21, src.m22, src.m23, src.m31, src.m32, src.m33);
|
||||
float t11 = determinant3x3(src.m00, src.m02, src.m03, src.m20, src.m22, src.m23, src.m30, src.m32, src.m33);
|
||||
float t12 = -determinant3x3(src.m00, src.m01, src.m03, src.m20, src.m21, src.m23, src.m30, src.m31, src.m33);
|
||||
float t13 = determinant3x3(src.m00, src.m01, src.m02, src.m20, src.m21, src.m22, src.m30, src.m31, src.m32);
|
||||
// third row
|
||||
float t20 = determinant3x3(src.m01, src.m02, src.m03, src.m11, src.m12, src.m13, src.m31, src.m32, src.m33);
|
||||
float t21 = -determinant3x3(src.m00, src.m02, src.m03, src.m10, src.m12, src.m13, src.m30, src.m32, src.m33);
|
||||
float t22 = determinant3x3(src.m00, src.m01, src.m03, src.m10, src.m11, src.m13, src.m30, src.m31, src.m33);
|
||||
float t23 = -determinant3x3(src.m00, src.m01, src.m02, src.m10, src.m11, src.m12, src.m30, src.m31, src.m32);
|
||||
// fourth row
|
||||
float t30 = -determinant3x3(src.m01, src.m02, src.m03, src.m11, src.m12, src.m13, src.m21, src.m22, src.m23);
|
||||
float t31 = determinant3x3(src.m00, src.m02, src.m03, src.m10, src.m12, src.m13, src.m20, src.m22, src.m23);
|
||||
float t32 = -determinant3x3(src.m00, src.m01, src.m03, src.m10, src.m11, src.m13, src.m20, src.m21, src.m23);
|
||||
float t33 = determinant3x3(src.m00, src.m01, src.m02, src.m10, src.m11, src.m12, src.m20, src.m21, src.m22);
|
||||
|
||||
// transpose and divide by the determinant
|
||||
dest.m00 = t00*determinant_inv;
|
||||
dest.m11 = t11*determinant_inv;
|
||||
dest.m22 = t22*determinant_inv;
|
||||
dest.m33 = t33*determinant_inv;
|
||||
dest.m01 = t10*determinant_inv;
|
||||
dest.m10 = t01*determinant_inv;
|
||||
dest.m20 = t02*determinant_inv;
|
||||
dest.m02 = t20*determinant_inv;
|
||||
dest.m12 = t21*determinant_inv;
|
||||
dest.m21 = t12*determinant_inv;
|
||||
dest.m03 = t30*determinant_inv;
|
||||
dest.m30 = t03*determinant_inv;
|
||||
dest.m13 = t31*determinant_inv;
|
||||
dest.m31 = t13*determinant_inv;
|
||||
dest.m32 = t23*determinant_inv;
|
||||
dest.m23 = t32*determinant_inv;
|
||||
return dest;
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate this matrix
|
||||
* @return this
|
||||
*/
|
||||
public Matrix negate() {
|
||||
return negate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate this matrix and place the result in a destination matrix.
|
||||
* @param dest The destination matrix, or null if a new matrix is to be created
|
||||
* @return the negated matrix
|
||||
*/
|
||||
public Matrix4f negate(Matrix4f dest) {
|
||||
return negate(this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate this matrix and place the result in a destination matrix.
|
||||
* @param src The source matrix
|
||||
* @param dest The destination matrix, or null if a new matrix is to be created
|
||||
* @return The negated matrix
|
||||
*/
|
||||
public static Matrix4f negate(Matrix4f src, Matrix4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Matrix4f();
|
||||
|
||||
dest.m00 = -src.m00;
|
||||
dest.m01 = -src.m01;
|
||||
dest.m02 = -src.m02;
|
||||
dest.m03 = -src.m03;
|
||||
dest.m10 = -src.m10;
|
||||
dest.m11 = -src.m11;
|
||||
dest.m12 = -src.m12;
|
||||
dest.m13 = -src.m13;
|
||||
dest.m20 = -src.m20;
|
||||
dest.m21 = -src.m21;
|
||||
dest.m22 = -src.m22;
|
||||
dest.m23 = -src.m23;
|
||||
dest.m30 = -src.m30;
|
||||
dest.m31 = -src.m31;
|
||||
dest.m32 = -src.m32;
|
||||
dest.m33 = -src.m33;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public boolean equals(Object m) {
|
||||
return (m instanceof Matrix4f) && equal(this, (Matrix4f)m);
|
||||
}
|
||||
|
||||
public static boolean equal(Matrix4f a, Matrix4f b) {
|
||||
return a.m00 == b.m00 &&
|
||||
a.m01 == b.m01 &&
|
||||
a.m02 == b.m02 &&
|
||||
a.m03 == b.m03 &&
|
||||
a.m10 == b.m10 &&
|
||||
a.m11 == b.m11 &&
|
||||
a.m12 == b.m12 &&
|
||||
a.m13 == b.m13 &&
|
||||
a.m20 == b.m20 &&
|
||||
a.m21 == b.m21 &&
|
||||
a.m22 == b.m22 &&
|
||||
a.m23 == b.m23 &&
|
||||
a.m30 == b.m30 &&
|
||||
a.m31 == b.m31 &&
|
||||
a.m32 == b.m32 &&
|
||||
a.m33 == b.m33;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
/**
|
||||
*
|
||||
* Quaternions for LWJGL!
|
||||
*
|
||||
* @author fbi
|
||||
* @version $Revision$
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public class Quaternion extends Vector implements ReadableVector4f {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public float x, y, z, w;
|
||||
|
||||
/**
|
||||
* C'tor. The quaternion will be initialized to the identity.
|
||||
*/
|
||||
public Quaternion() {
|
||||
super();
|
||||
setIdentity();
|
||||
}
|
||||
|
||||
/**
|
||||
* C'tor
|
||||
*
|
||||
* @param src
|
||||
*/
|
||||
public Quaternion(ReadableVector4f src) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* C'tor
|
||||
*
|
||||
*/
|
||||
public Quaternion(float x, float y, float z, float w) {
|
||||
set(x, y, z, w);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.lwjgl.util.vector.WritableVector2f#set(float, float)
|
||||
*/
|
||||
public void set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float)
|
||||
*/
|
||||
public void set(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.lwjgl.util.vector.WritableVector4f#set(float, float, float,
|
||||
* float)
|
||||
*/
|
||||
public void set(float x, float y, float z, float w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from another Vector4f
|
||||
*
|
||||
* @param src
|
||||
* The source vector
|
||||
* @return this
|
||||
*/
|
||||
public Quaternion set(ReadableVector4f src) {
|
||||
x = src.getX();
|
||||
y = src.getY();
|
||||
z = src.getZ();
|
||||
w = src.getW();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this quaternion to the multiplication identity.
|
||||
* @return this
|
||||
*/
|
||||
public Quaternion setIdentity() {
|
||||
return setIdentity(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the given quaternion to the multiplication identity.
|
||||
* @param q The quaternion
|
||||
* @return q
|
||||
*/
|
||||
public static Quaternion setIdentity(Quaternion q) {
|
||||
q.x = 0;
|
||||
q.y = 0;
|
||||
q.z = 0;
|
||||
q.w = 1;
|
||||
return q;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the length squared of the quaternion
|
||||
*/
|
||||
public float lengthSquared() {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the source quaternion and place the result in another quaternion.
|
||||
*
|
||||
* @param src
|
||||
* The source quaternion
|
||||
* @param dest
|
||||
* The destination quaternion, or null if a new quaternion is to be
|
||||
* created
|
||||
* @return The normalised quaternion
|
||||
*/
|
||||
public static Quaternion normalise(Quaternion src, Quaternion dest) {
|
||||
float inv_l = 1f/src.length();
|
||||
|
||||
if (dest == null)
|
||||
dest = new Quaternion();
|
||||
|
||||
dest.set(src.x * inv_l, src.y * inv_l, src.z * inv_l, src.w * inv_l);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise this quaternion and place the result in another quaternion.
|
||||
*
|
||||
* @param dest
|
||||
* The destination quaternion, or null if a new quaternion is to be
|
||||
* created
|
||||
* @return the normalised quaternion
|
||||
*/
|
||||
public Quaternion normalise(Quaternion dest) {
|
||||
return normalise(this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* The dot product of two quaternions
|
||||
*
|
||||
* @param left
|
||||
* The LHS quat
|
||||
* @param right
|
||||
* The RHS quat
|
||||
* @return left dot right
|
||||
*/
|
||||
public static float dot(Quaternion left, Quaternion right) {
|
||||
return left.x * right.x + left.y * right.y + left.z * right.z + left.w
|
||||
* right.w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the conjugate of this quaternion and put it into the given one
|
||||
*
|
||||
* @param dest
|
||||
* The quaternion which should be set to the conjugate of this
|
||||
* quaternion
|
||||
*/
|
||||
public Quaternion negate(Quaternion dest) {
|
||||
return negate(this, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the conjugate of this quaternion and put it into the given one
|
||||
*
|
||||
* @param src
|
||||
* The source quaternion
|
||||
* @param dest
|
||||
* The quaternion which should be set to the conjugate of this
|
||||
* quaternion
|
||||
*/
|
||||
public static Quaternion negate(Quaternion src, Quaternion dest) {
|
||||
if (dest == null)
|
||||
dest = new Quaternion();
|
||||
|
||||
dest.x = -src.x;
|
||||
dest.y = -src.y;
|
||||
dest.z = -src.z;
|
||||
dest.w = src.w;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the conjugate of this quaternion
|
||||
*/
|
||||
public Vector negate() {
|
||||
return negate(this, this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.util.vector.Vector#load(java.nio.FloatBuffer)
|
||||
*/
|
||||
public Vector load(FloatBuffer buf) {
|
||||
x = buf.get();
|
||||
y = buf.get();
|
||||
z = buf.get();
|
||||
w = buf.get();
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.lwjgl.vector.Vector#scale(float)
|
||||
*/
|
||||
public Vector scale(float scale) {
|
||||
return scale(scale, this, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale the source quaternion by scale and put the result in the destination
|
||||
* @param scale The amount to scale by
|
||||
* @param src The source quaternion
|
||||
* @param dest The destination quaternion, or null if a new quaternion is to be created
|
||||
* @return The scaled quaternion
|
||||
*/
|
||||
public static Quaternion scale(float scale, Quaternion src, Quaternion dest) {
|
||||
if (dest == null)
|
||||
dest = new Quaternion();
|
||||
dest.x = src.x * scale;
|
||||
dest.y = src.y * scale;
|
||||
dest.z = src.z * scale;
|
||||
dest.w = src.w * scale;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.util.vector.ReadableVector#store(java.nio.FloatBuffer)
|
||||
*/
|
||||
public Vector store(FloatBuffer buf) {
|
||||
buf.put(x);
|
||||
buf.put(y);
|
||||
buf.put(z);
|
||||
buf.put(w);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return x
|
||||
*/
|
||||
public final float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y
|
||||
*/
|
||||
public final float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set X
|
||||
*
|
||||
* @param x
|
||||
*/
|
||||
public final void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Y
|
||||
*
|
||||
* @param y
|
||||
*/
|
||||
public final void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Z
|
||||
*
|
||||
* @param z
|
||||
*/
|
||||
public void setZ(float z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/*
|
||||
* (Overrides)
|
||||
*
|
||||
* @see org.lwjgl.vector.ReadableVector3f#getZ()
|
||||
*/
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set W
|
||||
*
|
||||
* @param w
|
||||
*/
|
||||
public void setW(float w) {
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
/*
|
||||
* (Overrides)
|
||||
*
|
||||
* @see org.lwjgl.vector.ReadableVector3f#getW()
|
||||
*/
|
||||
public float getW() {
|
||||
return w;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Quaternion: " + x + " " + y + " " + z + " " + w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this quaternion to the quaternion product of
|
||||
* quaternions left and right (this = left * right). Note that this is safe
|
||||
* for aliasing (e.g. this can be left or right).
|
||||
*
|
||||
* @param left
|
||||
* the first quaternion
|
||||
* @param right
|
||||
* the second quaternion
|
||||
*/
|
||||
public static Quaternion mul(Quaternion left, Quaternion right,
|
||||
Quaternion dest) {
|
||||
if (dest == null)
|
||||
dest = new Quaternion();
|
||||
dest.set(left.x * right.w + left.w * right.x + left.y * right.z
|
||||
- left.z * right.y, left.y * right.w + left.w * right.y
|
||||
+ left.z * right.x - left.x * right.z, left.z * right.w
|
||||
+ left.w * right.z + left.x * right.y - left.y * right.x,
|
||||
left.w * right.w - left.x * right.x - left.y * right.y
|
||||
- left.z * right.z);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Multiplies quaternion left by the inverse of quaternion right and places
|
||||
* the value into this quaternion. The value of both argument quaternions is
|
||||
* preservered (this = left * right^-1).
|
||||
*
|
||||
* @param left
|
||||
* the left quaternion
|
||||
* @param right
|
||||
* the right quaternion
|
||||
*/
|
||||
public static Quaternion mulInverse(Quaternion left, Quaternion right,
|
||||
Quaternion dest) {
|
||||
float n = right.lengthSquared();
|
||||
// zero-div may occur.
|
||||
n = (n == 0.0 ? n : 1 / n);
|
||||
// store on stack once for aliasing-safty
|
||||
if (dest == null)
|
||||
dest = new Quaternion();
|
||||
dest
|
||||
.set((left.x * right.w - left.w * right.x - left.y
|
||||
* right.z + left.z * right.y)
|
||||
* n, (left.y * right.w - left.w * right.y - left.z
|
||||
* right.x + left.x * right.z)
|
||||
* n, (left.z * right.w - left.w * right.z - left.x
|
||||
* right.y + left.y * right.x)
|
||||
* n, (left.w * right.w + left.x * right.x + left.y
|
||||
* right.y + left.z * right.z)
|
||||
* n);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this quaternion to the equivalent rotation of the
|
||||
* Axis-Angle argument.
|
||||
*
|
||||
* @param a1
|
||||
* the axis-angle: (x,y,z) is the axis and w is the angle
|
||||
*/
|
||||
public final void setFromAxisAngle(Vector4f a1) {
|
||||
x = a1.x;
|
||||
y = a1.y;
|
||||
z = a1.z;
|
||||
float n = (float) Math.sqrt(x * x + y * y + z * z);
|
||||
// zero-div may occur.
|
||||
float s = (float) (Math.sin(0.5 * a1.w) / n);
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
w = (float) Math.cos(0.5 * a1.w);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this quaternion using the rotational component of the
|
||||
* passed matrix.
|
||||
*
|
||||
* @param m
|
||||
* The matrix
|
||||
* @return this
|
||||
*/
|
||||
public final Quaternion setFromMatrix(Matrix4f m) {
|
||||
return setFromMatrix(m, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the source quaternion using the rotational component of the
|
||||
* passed matrix.
|
||||
*
|
||||
* @param m
|
||||
* The source matrix
|
||||
* @param q
|
||||
* The destination quaternion, or null if a new quaternion is to be created
|
||||
* @return q
|
||||
*/
|
||||
public static Quaternion setFromMatrix(Matrix4f m, Quaternion q) {
|
||||
return q.setFromMat(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20,
|
||||
m.m21, m.m22);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this quaternion using the rotational component of the
|
||||
* passed matrix.
|
||||
*
|
||||
* @param m
|
||||
* The source matrix
|
||||
*/
|
||||
public final Quaternion setFromMatrix(Matrix3f m) {
|
||||
return setFromMatrix(m, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the source quaternion using the rotational component of the
|
||||
* passed matrix.
|
||||
*
|
||||
* @param m
|
||||
* The source matrix
|
||||
* @param q
|
||||
* The destination quaternion, or null if a new quaternion is to be created
|
||||
* @return q
|
||||
*/
|
||||
public static Quaternion setFromMatrix(Matrix3f m, Quaternion q) {
|
||||
return q.setFromMat(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20,
|
||||
m.m21, m.m22);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to perform the matrix-to-quaternion conversion
|
||||
*/
|
||||
private Quaternion setFromMat(float m00, float m01, float m02, float m10,
|
||||
float m11, float m12, float m20, float m21, float m22) {
|
||||
|
||||
float s;
|
||||
float tr = m00 + m11 + m22;
|
||||
if (tr >= 0.0) {
|
||||
s = (float) Math.sqrt(tr + 1.0);
|
||||
w = s * 0.5f;
|
||||
s = 0.5f / s;
|
||||
x = (m21 - m12) * s;
|
||||
y = (m02 - m20) * s;
|
||||
z = (m10 - m01) * s;
|
||||
} else {
|
||||
float max = Math.max(Math.max(m00, m11), m22);
|
||||
if (max == m00) {
|
||||
s = (float) Math.sqrt(m00 - (m11 + m22) + 1.0);
|
||||
x = s * 0.5f;
|
||||
s = 0.5f / s;
|
||||
y = (m01 + m10) * s;
|
||||
z = (m20 + m02) * s;
|
||||
w = (m21 - m12) * s;
|
||||
} else if (max == m11) {
|
||||
s = (float) Math.sqrt(m11 - (m22 + m00) + 1.0);
|
||||
y = s * 0.5f;
|
||||
s = 0.5f / s;
|
||||
z = (m12 + m21) * s;
|
||||
x = (m01 + m10) * s;
|
||||
w = (m02 - m20) * s;
|
||||
} else {
|
||||
s = (float) Math.sqrt(m22 - (m00 + m11) + 1.0);
|
||||
z = s * 0.5f;
|
||||
s = 0.5f / s;
|
||||
x = (m20 + m02) * s;
|
||||
y = (m12 + m21) * s;
|
||||
w = (m10 - m01) * s;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
* @author foo
|
||||
*/
|
||||
public interface ReadableVector {
|
||||
/**
|
||||
* @return the length of the vector
|
||||
*/
|
||||
float length();
|
||||
/**
|
||||
* @return the length squared of the vector
|
||||
*/
|
||||
float lengthSquared();
|
||||
/**
|
||||
* Store this vector in a FloatBuffer
|
||||
* @param buf The buffer to store it in, at the current position
|
||||
* @return this
|
||||
*/
|
||||
Vector store(FloatBuffer buf);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
/**
|
||||
* @author foo
|
||||
*/
|
||||
public interface ReadableVector2f extends ReadableVector {
|
||||
/**
|
||||
* @return x
|
||||
*/
|
||||
float getX();
|
||||
/**
|
||||
* @return y
|
||||
*/
|
||||
float getY();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
/**
|
||||
* @author foo
|
||||
*/
|
||||
public interface ReadableVector3f extends ReadableVector2f {
|
||||
/**
|
||||
* @return z
|
||||
*/
|
||||
float getZ();
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
/**
|
||||
* @author foo
|
||||
*/
|
||||
public interface ReadableVector4f extends ReadableVector3f {
|
||||
|
||||
/**
|
||||
* @return w
|
||||
*/
|
||||
float getW();
|
||||
|
||||
}
|
||||
112
src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector.java
Normal file
112
src/main/java/net/lax1dude/eaglercraft/glemu/vector/Vector.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
* Base class for vectors.
|
||||
*
|
||||
* @author cix_foo <cix_foo@users.sourceforge.net>
|
||||
* @version $Revision$
|
||||
* $Id$
|
||||
*/
|
||||
public abstract class Vector implements Serializable, ReadableVector {
|
||||
|
||||
/**
|
||||
* Constructor for Vector.
|
||||
*/
|
||||
protected Vector() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the length of the vector
|
||||
*/
|
||||
public final float length() {
|
||||
return (float) Math.sqrt(lengthSquared());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the length squared of the vector
|
||||
*/
|
||||
public abstract float lengthSquared();
|
||||
|
||||
/**
|
||||
* Load this vector from a FloatBuffer
|
||||
* @param buf The buffer to load it from, at the current position
|
||||
* @return this
|
||||
*/
|
||||
public abstract Vector load(FloatBuffer buf);
|
||||
|
||||
/**
|
||||
* Negate a vector
|
||||
* @return this
|
||||
*/
|
||||
public abstract Vector negate();
|
||||
|
||||
|
||||
/**
|
||||
* Normalise this vector
|
||||
* @return this
|
||||
*/
|
||||
public final Vector normalise() {
|
||||
float len = length();
|
||||
if (len != 0.0f) {
|
||||
float l = 1.0f / len;
|
||||
return scale(l);
|
||||
} else
|
||||
throw new IllegalStateException("Zero length vector");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store this vector in a FloatBuffer
|
||||
* @param buf The buffer to store it in, at the current position
|
||||
* @return this
|
||||
*/
|
||||
public abstract Vector store(FloatBuffer buf);
|
||||
|
||||
|
||||
/**
|
||||
* Scale this vector
|
||||
* @param scale The scale factor
|
||||
* @return this
|
||||
*/
|
||||
public abstract Vector scale(float scale);
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
* Holds a 2-tuple vector.
|
||||
*
|
||||
* @author cix_foo <cix_foo@users.sourceforge.net>
|
||||
* @version $Revision$
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
public class Vector2f extends Vector implements Serializable, ReadableVector2f, WritableVector2f {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public float x, y;
|
||||
|
||||
/**
|
||||
* Constructor for Vector2f.
|
||||
*/
|
||||
public Vector2f() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Vector2f(ReadableVector2f src) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public Vector2f(float x, float y) {
|
||||
set(x, y);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.util.vector.WritableVector2f#set(float, float)
|
||||
*/
|
||||
public void set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from another Vector2f
|
||||
* @param src The source vector
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f set(ReadableVector2f src) {
|
||||
x = src.getX();
|
||||
y = src.getY();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the length squared of the vector
|
||||
*/
|
||||
public float lengthSquared() {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a vector
|
||||
* @param x The translation in x
|
||||
* @param y the translation in y
|
||||
* @return this
|
||||
*/
|
||||
public Vector2f translate(float x, float y) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate a vector
|
||||
* @return this
|
||||
*/
|
||||
public Vector negate() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate a vector and place the result in a destination vector.
|
||||
* @param dest The destination vector or null if a new vector is to be created
|
||||
* @return the negated vector
|
||||
*/
|
||||
public Vector2f negate(Vector2f dest) {
|
||||
if (dest == null)
|
||||
dest = new Vector2f();
|
||||
dest.x = -x;
|
||||
dest.y = -y;
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalise this vector and place the result in another vector.
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return the normalised vector
|
||||
*/
|
||||
public Vector2f normalise(Vector2f dest) {
|
||||
float l = length();
|
||||
|
||||
if (dest == null)
|
||||
dest = new Vector2f(x / l, y / l);
|
||||
else
|
||||
dest.set(x / l, y / l);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dot product of two vectors is calculated as
|
||||
* v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @return left dot right
|
||||
*/
|
||||
public static float dot(Vector2f left, Vector2f right) {
|
||||
return left.x * right.x + left.y * right.y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the angle between two vectors, in radians
|
||||
* @param a A vector
|
||||
* @param b The other vector
|
||||
* @return the angle between the two vectors, in radians
|
||||
*/
|
||||
public static float angle(Vector2f a, Vector2f b) {
|
||||
float dls = dot(a, b) / (a.length() * b.length());
|
||||
if (dls < -1f)
|
||||
dls = -1f;
|
||||
else if (dls > 1.0f)
|
||||
dls = 1.0f;
|
||||
return (float)Math.acos(dls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a vector to another vector and place the result in a destination
|
||||
* vector.
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return the sum of left and right in dest
|
||||
*/
|
||||
public static Vector2f add(Vector2f left, Vector2f right, Vector2f dest) {
|
||||
if (dest == null)
|
||||
return new Vector2f(left.x + right.x, left.y + right.y);
|
||||
else {
|
||||
dest.set(left.x + right.x, left.y + right.y);
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract a vector from another vector and place the result in a destination
|
||||
* vector.
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return left minus right in dest
|
||||
*/
|
||||
public static Vector2f sub(Vector2f left, Vector2f right, Vector2f dest) {
|
||||
if (dest == null)
|
||||
return new Vector2f(left.x - right.x, left.y - right.y);
|
||||
else {
|
||||
dest.set(left.x - right.x, left.y - right.y);
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store this vector in a FloatBuffer
|
||||
* @param buf The buffer to store it in, at the current position
|
||||
* @return this
|
||||
*/
|
||||
public Vector store(FloatBuffer buf) {
|
||||
buf.put(x);
|
||||
buf.put(y);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load this vector from a FloatBuffer
|
||||
* @param buf The buffer to load it from, at the current position
|
||||
* @return this
|
||||
*/
|
||||
public Vector load(FloatBuffer buf) {
|
||||
x = buf.get();
|
||||
y = buf.get();
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.vector.Vector#scale(float)
|
||||
*/
|
||||
public Vector scale(float scale) {
|
||||
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
|
||||
sb.append("Vector2f[");
|
||||
sb.append(x);
|
||||
sb.append(", ");
|
||||
sb.append(y);
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return x
|
||||
*/
|
||||
public final float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y
|
||||
*/
|
||||
public final float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set X
|
||||
* @param x
|
||||
*/
|
||||
public final void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Y
|
||||
* @param y
|
||||
*/
|
||||
public final void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
Vector2f other = (Vector2f)obj;
|
||||
|
||||
if (x == other.x && y == other.y) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
* Holds a 3-tuple vector.
|
||||
*
|
||||
* @author cix_foo <cix_foo@users.sourceforge.net>
|
||||
* @version $Revision$
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
public class Vector3f extends Vector implements Serializable, ReadableVector3f, WritableVector3f {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public float x, y, z;
|
||||
|
||||
/**
|
||||
* Constructor for Vector3f.
|
||||
*/
|
||||
public Vector3f() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Vector3f(ReadableVector3f src) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Vector3f(float x, float y, float z) {
|
||||
set(x, y, z);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.util.vector.WritableVector2f#set(float, float)
|
||||
*/
|
||||
public void set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float)
|
||||
*/
|
||||
public void set(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from another Vector3f
|
||||
* @param src The source vector
|
||||
* @return this
|
||||
*/
|
||||
public Vector3f set(ReadableVector3f src) {
|
||||
x = src.getX();
|
||||
y = src.getY();
|
||||
z = src.getZ();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the length squared of the vector
|
||||
*/
|
||||
public float lengthSquared() {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a vector
|
||||
* @param x The translation in x
|
||||
* @param y the translation in y
|
||||
* @return this
|
||||
*/
|
||||
public Vector3f translate(float x, float y, float z) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
this.z += z;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a vector to another vector and place the result in a destination
|
||||
* vector.
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return the sum of left and right in dest
|
||||
*/
|
||||
public static Vector3f add(Vector3f left, Vector3f right, Vector3f dest) {
|
||||
if (dest == null)
|
||||
return new Vector3f(left.x + right.x, left.y + right.y, left.z + right.z);
|
||||
else {
|
||||
dest.set(left.x + right.x, left.y + right.y, left.z + right.z);
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract a vector from another vector and place the result in a destination
|
||||
* vector.
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return left minus right in dest
|
||||
*/
|
||||
public static Vector3f sub(Vector3f left, Vector3f right, Vector3f dest) {
|
||||
if (dest == null)
|
||||
return new Vector3f(left.x - right.x, left.y - right.y, left.z - right.z);
|
||||
else {
|
||||
dest.set(left.x - right.x, left.y - right.y, left.z - right.z);
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The cross product of two vectors.
|
||||
*
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @param dest The destination result, or null if a new vector is to be created
|
||||
* @return left cross right
|
||||
*/
|
||||
public static Vector3f cross(
|
||||
Vector3f left,
|
||||
Vector3f right,
|
||||
Vector3f dest)
|
||||
{
|
||||
|
||||
if (dest == null)
|
||||
dest = new Vector3f();
|
||||
|
||||
dest.set(
|
||||
left.y * right.z - left.z * right.y,
|
||||
right.x * left.z - right.z * left.x,
|
||||
left.x * right.y - left.y * right.x
|
||||
);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Negate a vector
|
||||
* @return this
|
||||
*/
|
||||
public Vector negate() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
z = -z;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate a vector and place the result in a destination vector.
|
||||
* @param dest The destination vector or null if a new vector is to be created
|
||||
* @return the negated vector
|
||||
*/
|
||||
public Vector3f negate(Vector3f dest) {
|
||||
if (dest == null)
|
||||
dest = new Vector3f();
|
||||
dest.x = -x;
|
||||
dest.y = -y;
|
||||
dest.z = -z;
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalise this vector and place the result in another vector.
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return the normalised vector
|
||||
*/
|
||||
public Vector3f normalise(Vector3f dest) {
|
||||
float l = length();
|
||||
|
||||
if (dest == null)
|
||||
dest = new Vector3f(x / l, y / l, z / l);
|
||||
else
|
||||
dest.set(x / l, y / l, z / l);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dot product of two vectors is calculated as
|
||||
* v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @return left dot right
|
||||
*/
|
||||
public static float dot(Vector3f left, Vector3f right) {
|
||||
return left.x * right.x + left.y * right.y + left.z * right.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the angle between two vectors, in radians
|
||||
* @param a A vector
|
||||
* @param b The other vector
|
||||
* @return the angle between the two vectors, in radians
|
||||
*/
|
||||
public static float angle(Vector3f a, Vector3f b) {
|
||||
float dls = dot(a, b) / (a.length() * b.length());
|
||||
if (dls < -1f)
|
||||
dls = -1f;
|
||||
else if (dls > 1.0f)
|
||||
dls = 1.0f;
|
||||
return (float)Math.acos(dls);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.vector.Vector#load(FloatBuffer)
|
||||
*/
|
||||
public Vector load(FloatBuffer buf) {
|
||||
x = buf.get();
|
||||
y = buf.get();
|
||||
z = buf.get();
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.vector.Vector#scale(float)
|
||||
*/
|
||||
public Vector scale(float scale) {
|
||||
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
z *= scale;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.vector.Vector#store(FloatBuffer)
|
||||
*/
|
||||
public Vector store(FloatBuffer buf) {
|
||||
|
||||
buf.put(x);
|
||||
buf.put(y);
|
||||
buf.put(z);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(64);
|
||||
|
||||
sb.append("Vector3f[");
|
||||
sb.append(x);
|
||||
sb.append(", ");
|
||||
sb.append(y);
|
||||
sb.append(", ");
|
||||
sb.append(z);
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return x
|
||||
*/
|
||||
public final float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y
|
||||
*/
|
||||
public final float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set X
|
||||
* @param x
|
||||
*/
|
||||
public final void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Y
|
||||
* @param y
|
||||
*/
|
||||
public final void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Z
|
||||
* @param z
|
||||
*/
|
||||
public void setZ(float z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/* (Overrides)
|
||||
* @see org.lwjgl.vector.ReadableVector3f#getZ()
|
||||
*/
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
Vector3f other = (Vector3f)obj;
|
||||
|
||||
if (x == other.x && y == other.y && z == other.z) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
/**
|
||||
*
|
||||
* Holds a 4-tuple vector.
|
||||
*
|
||||
* @author cix_foo <cix_foo@users.sourceforge.net>
|
||||
* @version $Revision$
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
public class Vector4f extends Vector implements Serializable, ReadableVector4f, WritableVector4f {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public float x, y, z, w;
|
||||
|
||||
/**
|
||||
* Constructor for Vector4f.
|
||||
*/
|
||||
public Vector4f() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Vector4f(ReadableVector4f src) {
|
||||
set(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Vector4f(float x, float y, float z, float w) {
|
||||
set(x, y, z, w);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.util.vector.WritableVector2f#set(float, float)
|
||||
*/
|
||||
public void set(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.util.vector.WritableVector3f#set(float, float, float)
|
||||
*/
|
||||
public void set(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.util.vector.WritableVector4f#set(float, float, float, float)
|
||||
*/
|
||||
public void set(float x, float y, float z, float w) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from another Vector4f
|
||||
* @param src The source vector
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f set(ReadableVector4f src) {
|
||||
x = src.getX();
|
||||
y = src.getY();
|
||||
z = src.getZ();
|
||||
w = src.getW();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the length squared of the vector
|
||||
*/
|
||||
public float lengthSquared() {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate a vector
|
||||
* @param x The translation in x
|
||||
* @param y the translation in y
|
||||
* @return this
|
||||
*/
|
||||
public Vector4f translate(float x, float y, float z, float w) {
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
this.z += z;
|
||||
this.w += w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a vector to another vector and place the result in a destination
|
||||
* vector.
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return the sum of left and right in dest
|
||||
*/
|
||||
public static Vector4f add(Vector4f left, Vector4f right, Vector4f dest) {
|
||||
if (dest == null)
|
||||
return new Vector4f(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
|
||||
else {
|
||||
dest.set(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w);
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract a vector from another vector and place the result in a destination
|
||||
* vector.
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return left minus right in dest
|
||||
*/
|
||||
public static Vector4f sub(Vector4f left, Vector4f right, Vector4f dest) {
|
||||
if (dest == null)
|
||||
return new Vector4f(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
|
||||
else {
|
||||
dest.set(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w);
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Negate a vector
|
||||
* @return this
|
||||
*/
|
||||
public Vector negate() {
|
||||
x = -x;
|
||||
y = -y;
|
||||
z = -z;
|
||||
w = -w;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Negate a vector and place the result in a destination vector.
|
||||
* @param dest The destination vector or null if a new vector is to be created
|
||||
* @return the negated vector
|
||||
*/
|
||||
public Vector4f negate(Vector4f dest) {
|
||||
if (dest == null)
|
||||
dest = new Vector4f();
|
||||
dest.x = -x;
|
||||
dest.y = -y;
|
||||
dest.z = -z;
|
||||
dest.w = -w;
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalise this vector and place the result in another vector.
|
||||
* @param dest The destination vector, or null if a new vector is to be created
|
||||
* @return the normalised vector
|
||||
*/
|
||||
public Vector4f normalise(Vector4f dest) {
|
||||
float l = length();
|
||||
|
||||
if (dest == null)
|
||||
dest = new Vector4f(x / l, y / l, z / l, w / l);
|
||||
else
|
||||
dest.set(x / l, y / l, z / l, w / l);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* The dot product of two vectors is calculated as
|
||||
* v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w
|
||||
* @param left The LHS vector
|
||||
* @param right The RHS vector
|
||||
* @return left dot right
|
||||
*/
|
||||
public static float dot(Vector4f left, Vector4f right) {
|
||||
return left.x * right.x + left.y * right.y + left.z * right.z + left.w * right.w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the angle between two vectors, in radians
|
||||
* @param a A vector
|
||||
* @param b The other vector
|
||||
* @return the angle between the two vectors, in radians
|
||||
*/
|
||||
public static float angle(Vector4f a, Vector4f b) {
|
||||
float dls = dot(a, b) / (a.length() * b.length());
|
||||
if (dls < -1f)
|
||||
dls = -1f;
|
||||
else if (dls > 1.0f)
|
||||
dls = 1.0f;
|
||||
return (float)Math.acos(dls);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.vector.Vector#load(FloatBuffer)
|
||||
*/
|
||||
public Vector load(FloatBuffer buf) {
|
||||
x = buf.get();
|
||||
y = buf.get();
|
||||
z = buf.get();
|
||||
w = buf.get();
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.vector.Vector#scale(float)
|
||||
*/
|
||||
public Vector scale(float scale) {
|
||||
x *= scale;
|
||||
y *= scale;
|
||||
z *= scale;
|
||||
w *= scale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.lwjgl.vector.Vector#store(FloatBuffer)
|
||||
*/
|
||||
public Vector store(FloatBuffer buf) {
|
||||
|
||||
buf.put(x);
|
||||
buf.put(y);
|
||||
buf.put(z);
|
||||
buf.put(w);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Vector4f: " + x + " " + y + " " + z + " " + w;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return x
|
||||
*/
|
||||
public final float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return y
|
||||
*/
|
||||
public final float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set X
|
||||
* @param x
|
||||
*/
|
||||
public final void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Y
|
||||
* @param y
|
||||
*/
|
||||
public final void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Z
|
||||
* @param z
|
||||
*/
|
||||
public void setZ(float z) {
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
|
||||
/* (Overrides)
|
||||
* @see org.lwjgl.vector.ReadableVector3f#getZ()
|
||||
*/
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set W
|
||||
* @param w
|
||||
*/
|
||||
public void setW(float w) {
|
||||
this.w = w;
|
||||
}
|
||||
|
||||
/* (Overrides)
|
||||
* @see org.lwjgl.vector.ReadableVector3f#getZ()
|
||||
*/
|
||||
public float getW() {
|
||||
return w;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
Vector4f other = (Vector4f)obj;
|
||||
|
||||
if (x == other.x && y == other.y && z == other.z && w == other.w) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
/**
|
||||
* Writable interface to Vector2fs
|
||||
* @author $author$
|
||||
* @version $revision$
|
||||
* $Id$
|
||||
*/
|
||||
public interface WritableVector2f {
|
||||
|
||||
/**
|
||||
* Set the X value
|
||||
* @param x
|
||||
*/
|
||||
void setX(float x);
|
||||
|
||||
/**
|
||||
* Set the Y value
|
||||
* @param y
|
||||
*/
|
||||
void setY(float y);
|
||||
|
||||
/**
|
||||
* Set the X,Y values
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
void set(float x, float y);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
/**
|
||||
* Writable interface to Vector3fs
|
||||
* @author $author$
|
||||
* @version $revision$
|
||||
* $Id$
|
||||
*/
|
||||
public interface WritableVector3f extends WritableVector2f {
|
||||
|
||||
/**
|
||||
* Set the Z value
|
||||
* @param z
|
||||
*/
|
||||
void setZ(float z);
|
||||
|
||||
/**
|
||||
* Set the X,Y,Z values
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
void set(float x, float y, float z);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2002-2008 LWJGL Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'LWJGL' nor the names of
|
||||
* its contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.lax1dude.eaglercraft.glemu.vector;
|
||||
|
||||
/**
|
||||
* Writable interface to Vector4fs
|
||||
* @author $author$
|
||||
* @version $revision$
|
||||
* $Id$
|
||||
*/
|
||||
public interface WritableVector4f extends WritableVector3f {
|
||||
|
||||
/**
|
||||
* Set the W value
|
||||
* @param w
|
||||
*/
|
||||
void setW(float w);
|
||||
|
||||
/**
|
||||
* Set the X,Y,Z,W values
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @param w
|
||||
*/
|
||||
void set(float x, float y, float z, float w);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
public class ICEServerSet {
|
||||
|
||||
public static enum RelayType {
|
||||
STUN, TURN;
|
||||
}
|
||||
|
||||
public static class RelayServer {
|
||||
|
||||
public final RelayType type;
|
||||
public final String address;
|
||||
public final String username;
|
||||
public final String password;
|
||||
|
||||
protected RelayServer(RelayType type, String address, String username, String password) {
|
||||
this.type = type;
|
||||
this.address = address;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
protected RelayServer(RelayType type, String address) {
|
||||
this.type = type;
|
||||
this.address = address;
|
||||
this.username = null;
|
||||
this.password = null;
|
||||
}
|
||||
|
||||
public String getICEString() {
|
||||
if(username == null) {
|
||||
return address;
|
||||
}else {
|
||||
return address + ";" + username + ";" + password;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
144
src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket.java
Normal file
144
src/main/java/net/lax1dude/eaglercraft/sp/relay/pkt/IPacket.java
Normal file
@@ -0,0 +1,144 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class IPacket {
|
||||
|
||||
private static final Map<Integer,Class<? extends IPacket>> definedPacketClasses = new HashMap<>();
|
||||
private static final Map<Class<? extends IPacket>,Integer> definedPacketIds = new HashMap<>();
|
||||
|
||||
private static void register(int id, Class<? extends IPacket> clazz) {
|
||||
definedPacketClasses.put(id, clazz);
|
||||
definedPacketIds.put(clazz, id);
|
||||
}
|
||||
|
||||
static {
|
||||
register(0x00, IPacket00Handshake.class);
|
||||
register(0x01, IPacket01ICEServers.class);
|
||||
register(0x02, IPacket02NewClient.class);
|
||||
register(0x03, IPacket03ICECandidate.class);
|
||||
register(0x04, IPacket04Description.class);
|
||||
register(0x05, IPacket05ClientSuccess.class);
|
||||
register(0x06, IPacket06ClientFailure.class);
|
||||
register(0x07, IPacket07LocalWorlds.class);
|
||||
register(0x69, IPacket69Pong.class);
|
||||
register(0xFE, IPacketFEDisconnectClient.class);
|
||||
register(0xFF, IPacketFFErrorCode.class);
|
||||
}
|
||||
|
||||
public static IPacket readPacket(DataInputStream input) throws IOException {
|
||||
int i = input.read();
|
||||
try {
|
||||
Class<? extends IPacket> clazz = definedPacketClasses.get(i);
|
||||
if(clazz == null) {
|
||||
throw new IOException("Unknown packet type: " + i);
|
||||
}
|
||||
IPacket pkt = clazz.newInstance();
|
||||
pkt.read(input);
|
||||
return pkt;
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new IOException("Unknown packet type: " + i);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] writePacket(IPacket packet) throws IOException {
|
||||
Integer i = definedPacketIds.get(packet.getClass());
|
||||
if(i != null) {
|
||||
int len = packet.packetLength();
|
||||
ByteArrayOutputStream bao = len == -1 ? new ByteArrayOutputStream() :
|
||||
new ByteArrayOutputStream(len + 1);
|
||||
bao.write(i);
|
||||
packet.write(new DataOutputStream(bao));
|
||||
byte[] ret = bao.toByteArray();
|
||||
if(len != -1 && ret.length != len + 1) {
|
||||
System.err.println("writePacket buffer for packet " + packet.getClass().getSimpleName() + " " +
|
||||
(len + 1 < ret.length ? "overflowed" : "underflowed") + " by " + (len + 1 < ret.length ?
|
||||
ret.length - len - 1 : len + 1 - ret.length) + " bytes");
|
||||
}
|
||||
return ret;
|
||||
}else {
|
||||
throw new IOException("Unknown packet type: " + packet.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
}
|
||||
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
}
|
||||
|
||||
public int packetLength() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static String readASCII(InputStream is, int len) throws IOException {
|
||||
char[] ret = new char[len];
|
||||
for(int i = 0; i < len; ++i) {
|
||||
int j = is.read();
|
||||
if(j < 0) {
|
||||
return null;
|
||||
}
|
||||
ret[i] = (char)j;
|
||||
}
|
||||
return new String(ret);
|
||||
}
|
||||
|
||||
public static void writeASCII(OutputStream is, String txt) throws IOException {
|
||||
for(int i = 0, l = txt.length(); i < l; ++i) {
|
||||
is.write((int)txt.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static String readASCII8(InputStream is) throws IOException {
|
||||
int i = is.read();
|
||||
if(i < 0) {
|
||||
return null;
|
||||
}else {
|
||||
return readASCII(is, i);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeASCII8(OutputStream is, String txt) throws IOException {
|
||||
if(txt == null) {
|
||||
is.write(0);
|
||||
}else {
|
||||
int l = txt.length();
|
||||
is.write(l);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
is.write((int)txt.charAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String readASCII16(InputStream is) throws IOException {
|
||||
int hi = is.read();
|
||||
int lo = is.read();
|
||||
if(hi < 0 || lo < 0) {
|
||||
return null;
|
||||
}else {
|
||||
return readASCII(is, (hi << 8) | lo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeASCII16(OutputStream is, String txt) throws IOException {
|
||||
if(txt == null) {
|
||||
is.write(0);
|
||||
is.write(0);
|
||||
}else {
|
||||
int l = txt.length();
|
||||
is.write((l >> 8) & 0xFF);
|
||||
is.write(l & 0xFF);
|
||||
for(int i = 0; i < l; ++i) {
|
||||
is.write((int)txt.charAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class IPacket00Handshake extends IPacket {
|
||||
|
||||
public int connectionType = 0;
|
||||
public int connectionVersion = 1;
|
||||
public String connectionCode = null;
|
||||
|
||||
public IPacket00Handshake() {
|
||||
}
|
||||
|
||||
public IPacket00Handshake(int connectionType, int connectionVersion,
|
||||
String connectionCode) {
|
||||
this.connectionType = connectionType;
|
||||
this.connectionVersion = connectionVersion;
|
||||
this.connectionCode = connectionCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
connectionType = input.read();
|
||||
connectionVersion = input.read();
|
||||
connectionCode = IPacket.readASCII8(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
output.write(connectionType);
|
||||
output.write(connectionVersion);
|
||||
IPacket.writeASCII8(output, connectionCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int packetLength() {
|
||||
return 1 + 1 + (connectionCode != null ? 1 + connectionCode.length() : 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class IPacket01ICEServers extends IPacket {
|
||||
|
||||
public final Collection<ICEServerSet.RelayServer> servers;
|
||||
|
||||
public IPacket01ICEServers() {
|
||||
servers = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
servers.clear();
|
||||
int l = input.readUnsignedShort();
|
||||
for(int i = 0; i < l; ++i) {
|
||||
char type = (char)input.read();
|
||||
ICEServerSet.RelayType typeEnum;
|
||||
if(type == 'S') {
|
||||
typeEnum = ICEServerSet.RelayType.STUN;
|
||||
}else if(type == 'T') {
|
||||
typeEnum = ICEServerSet.RelayType.TURN;
|
||||
}else {
|
||||
throw new IOException("Unknown/Unsupported Relay Type: '" + type + "'");
|
||||
}
|
||||
servers.add(new ICEServerSet.RelayServer(
|
||||
typeEnum,
|
||||
readASCII16(input),
|
||||
readASCII8(input),
|
||||
readASCII8(input)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class IPacket02NewClient extends IPacket {
|
||||
|
||||
public String clientId;
|
||||
|
||||
public IPacket02NewClient(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public IPacket02NewClient() {
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
clientId = readASCII8(input);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class IPacket03ICECandidate extends IPacket {
|
||||
|
||||
public String peerId;
|
||||
public String candidate;
|
||||
|
||||
public IPacket03ICECandidate(String peerId, String desc) {
|
||||
this.peerId = peerId;
|
||||
this.candidate = desc;
|
||||
}
|
||||
|
||||
public IPacket03ICECandidate() {
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
peerId = readASCII8(input);
|
||||
candidate = readASCII16(input);
|
||||
}
|
||||
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
writeASCII8(output, peerId);
|
||||
writeASCII16(output, candidate);
|
||||
}
|
||||
|
||||
public int packetLength() {
|
||||
return 1 + peerId.length() + 2 + candidate.length();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class IPacket04Description extends IPacket {
|
||||
|
||||
public String peerId;
|
||||
public String description;
|
||||
|
||||
public IPacket04Description(String peerId, String desc) {
|
||||
this.peerId = peerId;
|
||||
this.description = desc;
|
||||
}
|
||||
|
||||
public IPacket04Description() {
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
peerId = readASCII8(input);
|
||||
description = readASCII16(input);
|
||||
}
|
||||
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
writeASCII8(output, peerId);
|
||||
writeASCII16(output, description);
|
||||
}
|
||||
|
||||
public int packetLength() {
|
||||
return 1 + peerId.length() + 2 + description.length();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class IPacket05ClientSuccess extends IPacket {
|
||||
|
||||
public String clientId;
|
||||
|
||||
public IPacket05ClientSuccess() {
|
||||
}
|
||||
|
||||
public IPacket05ClientSuccess(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
clientId = readASCII8(input);
|
||||
}
|
||||
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
writeASCII8(output, clientId);
|
||||
}
|
||||
|
||||
public int packetLength() {
|
||||
return 1 + clientId.length();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class IPacket06ClientFailure extends IPacket {
|
||||
|
||||
public String clientId;
|
||||
|
||||
public IPacket06ClientFailure() {
|
||||
}
|
||||
|
||||
public IPacket06ClientFailure(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
clientId = readASCII8(input);
|
||||
}
|
||||
|
||||
public void write(DataOutputStream output) throws IOException {
|
||||
writeASCII8(output, clientId);
|
||||
}
|
||||
|
||||
public int packetLength() {
|
||||
return 1 + clientId.length();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class IPacket07LocalWorlds extends IPacket {
|
||||
|
||||
public static class LocalWorld {
|
||||
|
||||
public final String worldName;
|
||||
public final String worldCode;
|
||||
|
||||
public LocalWorld(String worldName, String worldCode) {
|
||||
this.worldName = worldName;
|
||||
this.worldCode = worldCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final List<LocalWorld> worldsList;
|
||||
|
||||
public IPacket07LocalWorlds() {
|
||||
this.worldsList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void read(DataInputStream input) throws IOException {
|
||||
int l = input.read();
|
||||
for(int i = 0; i < l; ++i) {
|
||||
worldsList.add(new LocalWorld(readASCII8(input), readASCII8(input)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class IPacket69Pong extends IPacket {
|
||||
|
||||
public int protcolVersion;
|
||||
public String comment;
|
||||
public String brand;
|
||||
|
||||
public IPacket69Pong(int protcolVersion, String comment, String brand) {
|
||||
if(comment.length() > 255) {
|
||||
comment = comment.substring(0, 256);
|
||||
}
|
||||
this.protcolVersion = protcolVersion;
|
||||
this.comment = comment;
|
||||
this.brand = brand;
|
||||
}
|
||||
|
||||
public IPacket69Pong() {
|
||||
}
|
||||
|
||||
public void read(DataInputStream output) throws IOException {
|
||||
protcolVersion = output.read();
|
||||
comment = readASCII8(output);
|
||||
brand = readASCII8(output);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user