250 errors

This commit is contained in:
catfoolyou
2025-01-28 16:56:34 -05:00
parent 6ee3b454e1
commit 84ba94f919
1798 changed files with 65010 additions and 483 deletions

View File

@@ -0,0 +1,5 @@
package net.lax1dude.eaglercraft;
public class AbortedException extends RuntimeException {
}

View 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));
}
}

View 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 &gt; 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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.");
}
}
}

View 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 &gt; 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} &gt; 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 &gt; 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 &gt; 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 &gt; 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 &gt; 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;
}
}

View 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;
}

View 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;
}
}

View 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;
}
}
}

View 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));
}
}

View 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);
}
}

View File

@@ -0,0 +1,11 @@
package net.lax1dude.eaglercraft;
import net.lax1dude.eaglercraft.glemu.EaglerAdapterGL30;
public class EaglerAdapter extends EaglerAdapterGL30 {
/*
* YOU EAGLR!
*/
}

View 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);
}
}

View 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;
}
}

View 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]");
}
}
}

View 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;
}
}
}

View File

@@ -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;
}
}
}

View 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);
}
}

View 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;
}
}

View 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);
}
}

View 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();
}

View File

@@ -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);
}
}
}

View 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);
}
}

View 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View 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;
}
}
}
}
}
}
}
}

View 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));
}
}
}
}
}

View File

@@ -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()));
}
}
}

View File

@@ -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;
}
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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));
}
}
}

View 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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View 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);
}
}
}
}
}

View 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;
}
}

View 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));
}
}

View 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;
}
}
}
}

View 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);
}
}
}

View File

@@ -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 + "]";
}
}

View 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;
}
}
}

View 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;
}
}
}

View File

@@ -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;
}
}
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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();
}

View 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);
}
}

View File

@@ -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();
}

View 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();
}

View 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;
}
}
}

View 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;
}
}

View 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<>();
}

View 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;
}
}

View File

@@ -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;
}
}

View 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]";
}
}

File diff suppressed because it is too large Load Diff

View 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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View 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);
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}
}
}

View 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();
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();
}

View 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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}
}
}
}

View 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));
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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)
));
}
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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)));
}
}
}

View File

@@ -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