Update #0 - First Release

This commit is contained in:
LAX1DUDE 2022-12-25 01:12:28 -08:00
commit e7179fad45
2154 changed files with 256324 additions and 0 deletions

7
.gitattributes vendored Normal file
View File

@ -0,0 +1,7 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
*.bat text eol=crlf
*.sh text eol=lf
gradlew text eol=lf

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
buildtools_config.json
MinecraftSrc.zip
/MinecraftSrc/*
/pullrequest_merged_*
/patches.*
/mcp918/*
!/mcp918/readme.txt
!/mcp918/assetsIndexTransformer.json
/rundir/*
/##TEAVM.TMP##/*

553
CREDITS Normal file
View File

@ -0,0 +1,553 @@
EaglercraftX Developers
~~~~~~~~~~~~~~~~~~~~~~~
lax1dude:
- Creator of Eaglercraft
- Wrote HW accelerated OpenGL 1.3 emulator
- Wrote all desktop emulation code
- Ported the Minecraft 1.8 client src to TeaVM
- Wrote EaglercraftXBungee
- Wrote the patch and build system
ayunami2000:
- Many bug fixes
- Added resource packs
- Added screen recording
- Created the replit
Code used within EaglercraftX
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: TeaVM
Project Author: Alexey Andreev
Project URL: https://teavm.org/
Used For: Compiling Java to JS, JRE implementation
* Copyright 2014 Alexey Andreev.
*
* Licensed 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: LWJGL 3
Project Author: Spasi
Project URL: https://www.lwjgl.org
Used For: OpenGL, OpenAL, and GLFW bindings in desktop debug runtime
* Copyright (c) 2012-present Lightweight Java Game Library
* 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 Lightweight Java Game Library 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: java-diff-utils
Project Author: Google, forked by wumpz
Project URL: https://java-diff-utils.github.io/java-diff-utils/
Used For: generating and applying patch files in build system
* Copyright 2009-2017 java-diff-utils.
*
* Licensed 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Google Guava
Project Author: Google
Project URL: https://github.com/google/guava
Used For: It's a dependency for Minecraft 1.8
* Copyright (C) 2011 The Guava Authors
*
* Licensed 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: javax.annotation
Project Author: Oracle Inc.
Project URL: ??
Used For: Dependency for Google Guava
* Copyright (c) 2005-2018 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://oss.oracle.com/licenses/CDDL+GPL-1.1
* or LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Apache Commons Lang
Project Author: Apache Software Foundation
Project URL: https://commons.apache.org/proper/commons-lang/
Used For: It's a dependency for Minecraft 1.8
* 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Apache Commons IO
Project Author: Apache Software Foundation
Project URL: https://commons.apache.org/proper/commons-io/
Used For: simplifying file IO in build system
* 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Apache Commons CSV
Project Author: Apache Software Foundation
Project URL: https://commons.apache.org/proper/commons-csv/
Used For: loading mod coder pack config files in build system
* 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: JSON-java
Project Author: Sean Leary (stleary)
Project URL: https://github.com/stleary/JSON-java
Used For: JSON serialization and parsing in client and build system
* Public domain.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Eclipse IDE Java Formatter
Project Author: Eclipse Foundation
Project URL: https://www.eclipse.org/
Used For: Formatting source code in build system before making diffs
* License is here: https://www.eclipse.org/legal/epl-2.0/
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: ObjectWeb ASM
Project Author: OW2
Project URL: https://asm.ow2.io/
Used For: parsing method signatures in build system
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the copyright holders 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Bouncy Castle Crypto
Project Author: The Legion of the Bouncy Castle
Project URL: https://www.bouncycastle.org/java.html
Used For: MD5, SHA-1, SHA-256 implementations
* Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Apache Harmony JRE
Project Author: Apache Software Foundation
Project URL: https://harmony.apache.org/
Used For: TeaVM compatible String.format implementation
* 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Apache Commons Codec
Project Author: Apache Software Foundation
Project URL: https://commons.apache.org/proper/commons-codec/
Used For: Base64 encoder/decoder implementation
* 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: JZlib
Project Author: ymnk, JCraft Inc.
Project URL: http://www.jcraft.com/jzlib/
Used For: Deflate and GZIP implementations in client
* Copyright (c) 2011 ymnk, JCraft,Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 3. The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT,
* INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Java-WebSocket
Project Author: Nathan Rajlich (TooTallNate)
Project URL: http://tootallnate.github.io/Java-WebSocket
Used For: WebSockets in desktop runtime
* Copyright (c) 2010-2020 Nathan Rajlich
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: Netty
Project Author: Netty Project
Project URL: https://netty.io/
Used For: 'ByteBuf' classes implementations for Minecraft 1.8's networking engine
* Copyright 2015 The Netty Project
*
* The Netty Project 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:
*
* https://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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: 3D Sound System
Project Author: Paul Lamb
Project URL: http://www.paulscode.com/forum/index.php?topic=4.0
Used For: Audio in desktop runtime
* SoundSystem License:
*
* You are free to use this library for any purpose, commercial or
* otherwise. You may modify this library or source code, and distribute it any
* way you like, provided the following conditions are met:
*
* 1) You must abide by the conditions of the aforementioned LWJGL License.
*
* 2) You may not falsely claim to be the author of this library or any
* unmodified portion of it.
*
* 3) You may not copyright this library or a modified version of it and then
* sue me for copyright infringement.
*
* 4) If you modify the source code, you must clearly document the changes made
* before redistributing the modified source code, so other users know it is not
* the original code.
*
* 5) You are not required to give me credit for this library in any derived
* work, but if you do, you must also mention my website:
* http://www.paulscode.com
*
* 6) I the author will not be responsible for any damages (physical, financial,
* or otherwise) caused by the use if this library or any part of it.
*
* 7) I the author do not guarantee, warrant, or make any representations,
* either expressed or implied, regarding the use of this library or any part of
* it.
*
* Author: Paul Lamb
* http://www.paulscode.com
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: JOrbis
Project Author: ymnk, JCraft Inc.
Project URL: http://www.jcraft.com/jorbis/
Used For: Audio in desktop runtime
* JOrbis
* Copyright (C) 2000 ymnk, JCraft,Inc.
*
* Written by: 2000 ymnk<ymnk@jcraft.com>
*
* Many thanks to
* Monty <monty@xiph.org> and
* The XIPHOPHORUS Company http://www.xiph.org/ .
* JOrbis has been based on their awesome works, Vorbis codec.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: sqlite-jdbc
Project Author: Taro L. Saito (xerial)
Project URL: https://github.com/xerial/sqlite-jdbc
Used For: Default skin cache and authentication JDBC driver in EaglerXBungee
* Licensed 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Make sure you also update the copy of this file in "sources/resources/assets/eagler/CREDITS"
The content of both files should match, but not include this notice in the resources one

6
CompileLatestClient.bat Normal file
View File

@ -0,0 +1,6 @@
@echo off
title CompileLatestClient
java -cp "buildtools/BuildTools.jar" net.lax1dude.eaglercraft.v1_8.buildtools.gui.CompileLatestClientGUI
del /S /Q "##TEAVM.TMP##\*"
rmdir /S /Q "##TEAVM.TMP##"
pause

3
CompileLatestClient.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/sh
java -cp "buildtools/BuildTools.jar" net.lax1dude.eaglercraft.v1_8.buildtools.gui.CompileLatestClientGUI
rm -rf "##TEAVM.TMP##"

64
LICENSE Normal file
View File

@ -0,0 +1,64 @@
Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES NORMALLY
FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED TO SHARE,
DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE SOFTWARE IN THIS
REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
NOT FOR COMMERCIAL OR MALICIOUS USE
Prohibited sharing, distribution, and repurposing these files includes but is not
limited to: Publicly sharing or distributing any significant portion, modified or
unmodified, of any source code files produced by the buildtools commands without
minification or obfuscation, with the exception of patch files. Publicly
repurposing, without permission, the source code for any file which is a part of
the Eaglercraft runtime, as in any additional source files required for output of
buildtools commands to run on a specific platform. Publicly repurposing, without
permission, any resource file found in the project's default resource pack that
does not exist in vanilla Minecraft resource packs. And, additionally, publicly
repurposing, without permission, any data produced by the act of compiling or
converting the files described in these previous three cases, besides the compiled
or minified application (the 'game') itself.
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 HOLDER 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.
Prohibited commercial use includes selling access to any files or data (including
the game itself) contained or produced by this repository, requiring the direct
forced viewing of advertisement presented when a user attempts to load a compiled
version of this project (or follow a hyperlink to the project's source or files
derived from it, examples include using adfoc.us or adf.ly on your site), and
selling content in any form that can only be accessed through the use of this
project or files produced by or derived from it. Making a pay-to-win multiplayer
server, for example, would be prohibited under these terms.
Malicious use includes creating and/or distributing modified versions of the
game's 1.8 client (often referred to as "hacked clients") which give you an unfair
advantage on multiplayer servers, creating and/or distributing modified clients
which allow you to exploit bugs in EaglercraftXBungee or Eagler-compatible server
software, creating and/or distributing modified clients which allow you to exploit
bugs in Minecraft servers or Minecraft-compatible server software, or creating
and/or distributing modified clients which allow you to exploit bugs in portions of
any other software used in companion with EaglerXBungee or on an Eagler-compatible
server (e.g. VIAaaS, NGINX, Caddy)
Distribution of any file or a product of compilation or conversion covered by this
document must retain all existing copyright notices found within the file and
folders before any modifications were made.
BY VIOLATING THESE TERMS YOU AGREE TO A BLOCK/BAN FROM ALL SOURCES OF DOCUMENTATION
AND SUPPORT FOR THIS PROJECT, PERMISSION TO USE THESE FILES WAS GIVEN TO YOU IN
GOOD FAITH THAT THE WORK WILL NOT BE ABUSED, AND VIOLATING THIS AGREEMENT IS A
DEMONSTRATION OF A LACK OF RESPECT AND GOOD INTENTIONS ON BEHALF OF YOUR EFFORTS TO
LEARN HOW TO USE THESE TOOLS CORRECTLY AND IS JUSTIFICATION FOR YOUR EXCLUSION FROM
ANY AND ALL SOURCES OF DOCUMENTATION OR SUPPORT THAT WILL ASSIST YOU TO CONTINUE TO
VIOLATE THESE TERMS

67
README.md Normal file
View File

@ -0,0 +1,67 @@
# EaglercraftX 1.8
### Play real Minecraft 1.8 in your browser, currently only supports multiplayer
![EaglercraftX 1.8 Screenshot Main Menu](https://g.deev.is/eaglercraft/eaglerx-480p.png)
## ATTENTION MOJANG/MICROSOFT EMPLOYEE ASSIGNED TO STALK ME:
### THIS REPOSITORY DOES NOT CONTAIN YOUR INTELLECTUAL PROPERTY
### FILING A FALSE DMCA IS ILLEGAL AND IMMORAL
### This repository contains:
- **Utilities to decompile Minecraft 1.8 and apply patch files to it**
- **Source code to provide the LWJGL keyboard, mouse, and OpenGL APIs in a browser**
- **Source code for an OpenGL 1.3 emulator built on top of WebGL 2.0**
- **Patch files to mod the Minecraft 1.8 source code to make it browser compatible**
- **Browser-modified portions of Minecraft 1.8's open-source dependencies**
- **Plugins for Minecraft servers to allow the eagler client to connect to them**
### This repository does NOT contain:
- **Any portion of the decompiled Minecraft 1.8 source code or resources**
- **Any portion of Mod Coder Pack and it's config files**
- **Data that can be used alone to reconstruct portions of the game's source code**
- **Code configured by default to allow users to play without owning a copy of Minecraft**
## Getting Started:
### To compile the latest version of the client, on Windows:
1. Make sure you have at least Java 11 installed and added to your PATH
2. Download (clone) this repository to your computer
3. Double click `CompileLatestClient.bat`, a GUI resembling a classic windows installer should open
4. Follow the steps shown to you in the new window to finish compiling
### To compile the latest version of the client, on Linux/macOS:
1. Make sure you have at least Java 11 installed
2. Download (clone) this repository to your computer
3. Open a terminal in the folder the repository was cloned to
4. Type `chmod +x CompileLatestClient.sh` and hit enter
5. Type `./CompileLatestClient.sh` and hit enter, a GUI resembling a classic windows installer should open
6. Follow the steps shown to you in the new window to finish compiling
## Making a Server:
**EaglercraftX 1.8's server is a BungeeCord/Waterfall PLUGIN, not an entire "fork" of bungeecord like the 1.5 Eaglerbungee was, and I can't believe I have to clarify this too but the EaglerXBungee 1.8 plugin is not compatible with the old 1.5 bungee, you must migrate to the latest version of official BungeeCord/Waterfall to use it**
Simply set up the latest version of BungeeCord or Waterfall and download [EaglerXBungee-Latest.jar](https://gitlab.com/lax1dude/eaglercraftx-1.8/-/raw/main/gateway/EaglercraftXBungee/EaglerXBungee-Latest.jar) and place it in the plugins directory.
Then to actually log in to the server with Eaglercraft, first join your server using vanilla Minecraft Java Edition 1.8 and run the new `/eagler` command to set a password. Then leave the server and switch to your EaglercraftX client.
Set your EaglercraftX username to the same username as the vanilla minecraft account you set the password with, then when you try to join your server it will present you with a login screen where you can enter the password you set. If the password is correct it will let you join the server.
**NOTE: If you set `online_mode` to `false` on BungeeCord/Waterfall's config.yml, the password system will be disabled and you will be able to join with any username without setting a password like Eaglercraft 1.5. This should only ever be used for testing.**
A config guide will be added here too eventually
## Contributing:
This part of the guide is incomplete
## Developing a Client:
There is currently no system in place to make forks of 1.8 and merge commits made to the patch files in this repository with the patch files or workspace of the fork, you're on your own if you try to keep a fork of this repo for reasons other than to contribute to it

4
build_clean_tmp.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: clean
java -jar buildtools/BuildTools.jar clean
pause

2
build_clean_tmp.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar clean

4
build_help.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: help
java -jar buildtools/BuildTools.jar help
pause

2
build_help.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar help

4
build_init.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: init
java -jar buildtools/BuildTools.jar init
pause

2
build_init.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar init

View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: pullrequest
java -jar buildtools/BuildTools.jar pullrequest
pause

View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar pullrequest

4
build_make_unpatched.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: unpatched
java -jar buildtools/BuildTools.jar unpatched
pause

2
build_make_unpatched.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar unpatched

4
build_make_workspace.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: workspace
java -jar buildtools/BuildTools.jar workspace
pause

2
build_make_workspace.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar workspace

4
build_merge_direct.bat Normal file
View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: merge_direct
java -jar buildtools/BuildTools.jar merge_direct
pause

2
build_merge_direct.sh Normal file
View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar merge_direct

View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: merge
java -jar buildtools/BuildTools.jar merge
pause

View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar merge

View File

@ -0,0 +1,4 @@
@echo off
title BuildTools: pullrequest_test
java -jar buildtools/BuildTools.jar pullrequest_test
pause

View File

@ -0,0 +1,2 @@
#!/bin/sh
java -jar buildtools/BuildTools.jar pullrequest_test

BIN
buildtools/BuildTools.jar Normal file

Binary file not shown.

BIN
buildtools/Java11Check.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,4 @@
when you export the BuildTools source as a jar you must copy the "MANIFEST.MF" file in this directory into the "META-INF" directory inside the JAR!!
reasons: limitations in eclipse/intellij, lazyness

4
buildtools/MANIFEST.MF Normal file
View File

@ -0,0 +1,4 @@
Manifest-Version: 1.0
Main-Class: net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools
Class-Path: Java11Check.jar deps/asm-signature.jar deps/commons-csv-1.9.0.jar deps/commons-io-2.11.0.jar deps/eclipse-formatter.jar deps/java-diff-utils-4.11.jar deps/json-20220320.jar

BIN
buildtools/TeaVMBridge.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Play minecraft 1.8 in your browser" />
<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
<title>EaglercraftX 1.8</title>
<meta property="og:locale" content="en-US" />
<meta property="og:type" content="website" />
<meta property="og:title" content="EaglercraftX 1.8" />
<meta property="og:description" content="Play minecraft 1.8 in your browser" />
<meta property="og:image" content="favicon.png" />
<link type="image/png" rel="shortcut icon" href="favicon.png" />
<script type="text/javascript" src="classes.js"></script>
<script type="text/javascript" src="fix-webm-duration.js"></script>
<script type="text/javascript">
"use strict";
window.addEventListener("load", () => {
if(document.location.href.startsWith("file:")) {
alert("HTTP please, do not open this file locally, run a local HTTP server and load it via HTTP");
}else {
var opts = window.eaglercraftXOpts;
if(typeof opts === "function") window.eaglercraftXOpts = opts = opts();
if(typeof opts === "undefined") window.eaglercraftXOpts = opts = {};
if(!opts.container) opts.container = "game_frame";
if(!opts.assetsURI) opts.assetsURI = "assets.epk";
if(!opts.localesURI) opts.localesURI = "lang/";
if(!opts.joinServer) {
var q = window.location.search;
if(typeof q === "string" && q.startsWith("?")) {
q = new URLSearchParams(q);
var s = q.get("server");
if(s) opts.joinServer = s;
}
}
main();
}
});
</script>
</head>
<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
</body>
</html>

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Play minecraft 1.8 in your browser" />
<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
<title>EaglercraftX 1.8</title>
<meta property="og:locale" content="en-US" />
<meta property="og:type" content="website" />
<meta property="og:title" content="EaglercraftX 1.8" />
<meta property="og:description" content="Play minecraft 1.8 in your browser" />
<meta property="og:image" content="favicon.png" />
<link type="image/png" rel="shortcut icon" href="favicon.png" />
<script type="text/javascript" src="classes.js"></script>
<script type="text/javascript" src="fix-webm-duration.js"></script>
<script type="text/javascript">
"use strict";
window.addEventListener("load", () => {
if(document.location.href.startsWith("file:")) {
alert("HTTP please, do not open this file locally, run a local HTTP server and load it via HTTP");
}else {
// %%%%%%%%% launch options %%%%%%%%%%%%
window.eaglercraftXOpts = {
container: "game_frame",
assetsURI: "assets.epk",
localesURI: "lang/",
servers: [
/* example: { addr: "ws://localhost:8081/", name: "Local test server" } */
]
};
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
var q = window.location.search;
if(typeof q === "string" && q.startsWith("?")) {
q = new URLSearchParams(q);
var s = q.get("server");
if(s) window.eaglercraftXOpts.joinServer = s;
}
main();
}
});
</script>
</head>
<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
</body>
</html>

View File

@ -0,0 +1,167 @@
package net.lax1dude.eaglercraft.v1_8.buildtools;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.MergePullRequest;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.PullRequestTask;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CreateUnpatched;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InitTask;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.SetupWorkspace;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.TaskClean;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EaglerBuildTools {
public static File repositoryRoot = new File(".");
public static void main(String[] args) {
System.out.println("Eaglercraft 1.8 Build Tools");
System.out.println("Copyright (c) 2022 LAX1DUDE");
System.out.println();
if(!System.getProperty("eaglercraft.isJava11", "false").equalsIgnoreCase("true")) {
try {
if (!(boolean) Class
.forName("net.lax1dude.eaglercraft.v1_8.buildtools.Java11Check", true,
new URLClassLoader(new URL[] { (new File("buildtools/Java11Check.jar")).toURI().toURL() }))
.getMethod("classLoadCheck").invoke(null)) {
throw new RuntimeException("wtf?");
}
}catch(Throwable t) {
System.err.println("ERROR: A minimum of Java 11 is required to run this tool!");
System.err.println();
System.err.println("You are using Java " + System.getProperty("java.version"));
System.err.println();
return;
}
}
if(args.length == 0 || (args.length == 1 && args[0].equalsIgnoreCase("help"))) {
System.out.println("Options:");
System.out.println(" help - displays this message");
System.out.println(" init - decompiles 1.8.8 and applies the main repo's patch files");
System.out.println(" workspace - creates a dev workspace with a gradle project to compile the source");
System.out.println(" pullrequest - scans changes in the dev workspace and creates patch files for pull requests");
System.out.println(" pullrequest_test - makes new workspace and re-applies the patches in 'pullrequest'");
System.out.println(" unpatched - creates a zip file with the vanilla minecraft source without patches");
System.out.println(" merge - merges the patch files in the pullrequest folder with the repo's main patch files");
System.out.println(" merge_direct - merges changes in the dev workspace with the repo's main patch files");
System.out.println(" clean - delete init and pullrequest directories, keeps dev workspace");
System.out.println();
}else if(args.length == 1 && args[0].equalsIgnoreCase("init")) {
LicensePrompt.display();
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(InitTask.initTask()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("workspace")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(SetupWorkspace.setupWorkspace()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("pullrequest")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(PullRequestTask.pullRequest()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("pullrequest_test")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(SetupWorkspace.pullRequestTest()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("unpatched")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(CreateUnpatched.createUnpatched()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("merge")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(MergePullRequest.mergeTask()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("merge_direct")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(MergePullRequest.mergeDirect()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else if(args.length == 1 && args[0].equalsIgnoreCase("clean")) {
System.out.println("Running task '" + args[0] + "':");
System.out.println();
if(TaskClean.taskClean()) {
System.out.println();
System.out.println("Task Complete.");
System.out.println();
}else {
System.err.println();
System.err.println("Task Failed!");
System.err.println();
}
}else {
System.err.println("Invalid arguments!");
}
}
}

View File

@ -0,0 +1,183 @@
package net.lax1dude.eaglercraft.v1_8.buildtools;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import org.json.JSONObject;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EaglerBuildToolsConfig {
public static File temporary_directory = new File(System.getProperty("user.home"), ".eaglercraft_1.8_buildtools");
private static boolean temporary_directory_isInit = false;
private static boolean temporary_directory_mentioned = false;
public static File workspace_directory = new File("../eaglercraft_1.8_workspace");
private static boolean workspace_directory_isInit = false;
private static boolean workspace_directory_mentioned = false;
private static boolean config_file_loaded = false;
public static final File configFile = new File("./buildtools_config.json");
public static void load() {
if(configFile.exists()) {
try(FileInputStream is = new FileInputStream(configFile)) {
byte[] r = new byte[(int)configFile.length()];
is.read(r);
is.close();
String jsonTxt = new String(r, StandardCharsets.UTF_8);
JSONObject obj = new JSONObject(jsonTxt);
String path = obj.optString("temporary_directory", null);
if(path != null) {
temporary_directory = new File(path);
temporary_directory_isInit = true;
}
path = obj.optString("workspace_directory", null);
if(path != null) {
workspace_directory = new File(path);
workspace_directory_isInit = true;
}
}catch(Throwable ex) {
System.err.println("Failed to read config!");
ex.printStackTrace();
}
}
}
public static void save() {
JSONObject obj = new JSONObject();
if(temporary_directory_isInit) obj.put("temporary_directory", temporary_directory.getAbsolutePath());
if(workspace_directory_isInit) obj.put("workspace_directory", workspace_directory.getAbsoluteFile());
try(FileOutputStream os = new FileOutputStream(configFile)) {
os.write(obj.toString(4).getBytes(StandardCharsets.UTF_8));
os.close();
}catch(IOException e) {
System.err.println("Failed to write config!");
e.printStackTrace();
}
}
private static void mentionConfigPath() {
System.out.println("Edit '" + configFile.getName() + "' to change");
}
public static File getTemporaryDirectory() {
if(!config_file_loaded) {
load();
config_file_loaded = true;
}
if(!temporary_directory_isInit) {
File f = temporary_directory;
System.out.println();
System.out.println("Using temporary directory: " + f.getAbsolutePath());
temporary_directory_mentioned = true;
f = askIfChangeIsWanted(f);
temporary_directory = f;
temporary_directory_isInit = true;
while(!temporary_directory.isDirectory() && !temporary_directory.mkdirs()) {
System.err.println("Failed to create: " + f.getAbsolutePath());
temporary_directory = askIfChangeIsWanted(f);
}
save();
System.out.println();
return temporary_directory;
}else {
if(!temporary_directory_mentioned) {
System.out.println("Using temporary directory: " + temporary_directory.getAbsolutePath());
temporary_directory_mentioned = true;
while(!temporary_directory.isDirectory() && !temporary_directory.mkdirs()) {
System.err.println("Failed to create: " + temporary_directory.getAbsolutePath());
temporary_directory = askIfChangeIsWanted(temporary_directory);
}
mentionConfigPath();
}
return temporary_directory;
}
}
public static File getWorkspaceDirectory() {
if(!config_file_loaded) {
load();
config_file_loaded = true;
}
if(!workspace_directory_isInit) {
File f = workspace_directory;
System.out.println();
System.out.println("Using workspace directory: " + f.getAbsolutePath());
workspace_directory_mentioned = true;
f = askIfChangeIsWanted(f);
workspace_directory = f;
workspace_directory_isInit = true;
while(!workspace_directory.isDirectory() && !workspace_directory.mkdirs()) {
System.err.println("Failed to create: " + f.getAbsolutePath());
workspace_directory = askIfChangeIsWanted(f);
}
save();
System.out.println();
return workspace_directory;
}else {
if(!workspace_directory_mentioned) {
System.out.println("Using workspace directory: " + workspace_directory.getAbsolutePath());
workspace_directory_mentioned = true;
while(!workspace_directory.isDirectory() && !workspace_directory.mkdirs()) {
System.err.println("Failed to create: " + workspace_directory.getAbsolutePath());
workspace_directory = askIfChangeIsWanted(workspace_directory);
}
mentionConfigPath();
}
return workspace_directory;
}
}
public static File askIfChangeIsWanted(File in) {
System.out.println("Would you like to change this directory?");
System.out.println("Enter 'Y' for yes or 'N' for no: ");
String l = "N";
try {
l = (new BufferedReader(new InputStreamReader(System.in))).readLine();
} catch (IOException e) {
}
if(l != null && ((l = l.trim()).equalsIgnoreCase("y") || l.equalsIgnoreCase("yes"))) {
System.out.println();
System.out.println("Type a new filename or hit 'Enter' to browse: ");
try {
l = (new BufferedReader(new InputStreamReader(System.in))).readLine();
} catch (IOException e) {
}
if(l != null && (l = l.trim()).length() > 0) {
in = new File(l);
}else {
File f = FileChooserTool.load(true);
if(f == null) {
System.out.println("You hit cancel on the file chooser, the directory '" + in.getAbsolutePath() + "' will be used.");
in = askIfChangeIsWanted(in);
}else {
in = f;
}
}
}
return in;
}
}

View File

@ -0,0 +1,46 @@
package net.lax1dude.eaglercraft.v1_8.buildtools;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class FileChooserTool {
public static final JFileChooser fc = new JFileChooser();
public static File load(boolean directory) {
fc.setFileSelectionMode(directory ? JFileChooser.DIRECTORIES_ONLY : JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.setFileHidingEnabled(false);
fc.setDialogTitle("Eaglercraft Buildtools");
JFrame parent = new JFrame();
parent.setBounds(0, 0, 50, 50);
parent.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
parent.setAlwaysOnTop(true);
parent.setTitle("File Chooser");
parent.setLocationRelativeTo(null);
parent.setVisible(true);
if(fc.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
parent.dispose();
return fc.getSelectedFile();
}else {
parent.dispose();
return null;
}
}
}

View File

@ -0,0 +1,64 @@
package net.lax1dude.eaglercraft.v1_8.buildtools;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class LicensePrompt {
public static void main(String[] args) {
System.out.println();
display();
}
public static void display() {
System.out.println("WARNING: You must agree to the LICENSE before running this command");
System.out.println();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(LicensePrompt.class.getResourceAsStream("/lang/LICENSE_console_wrapped.txt"), StandardCharsets.UTF_8))) {
String line;
while((line = reader.readLine()) != null) {
if(line.equals("<press enter>")) {
pressEnter();
}else {
System.out.println(line);
}
}
}catch(IOException ex) {
System.err.println();
System.err.println("ERROR: could not display license text");
System.err.println("Please read the \"LICENSE\" file before using this software");
System.err.println();
pressEnter();
}
}
private static void pressEnter() {
System.out.println();
System.out.println("(press ENTER to continue)");
while(true) {
try {
if(System.in.read() == '\n') {
break;
}
}catch(IOException ex) {
throw new RuntimeException("Unexpected IOException reading STDIN", ex);
}
}
}
}

View File

@ -0,0 +1,447 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.decompiler;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class LocalVariableGenerator extends SignatureVisitor {
public static final Map<Character,String> primitiveNames = new HashMap();
public static final Set<String> illegalVariableNames = new HashSet();
static {
primitiveNames.put('Z', "Flag");
primitiveNames.put('C', "Char");
primitiveNames.put('B', "Byte");
primitiveNames.put('S', "Short");
primitiveNames.put('I', "Int");
primitiveNames.put('F', "Float");
primitiveNames.put('J', "Long");
primitiveNames.put('D', "Double");
primitiveNames.put('V', "Void");
illegalVariableNames.addAll(Arrays.asList(
"abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
"continue", "const", "default", "do", "double", "else", "enum", "exports", "extends",
"final", "finally", "float", "for", "goto", "if", "implements", "import",
"instanceof", "int", "interface", "long", "native", "new", "package", "private",
"protected", "public", "return", "short", "static", "strictfp", "super", "switch",
"synchronized", "this", "throw", "throws", "transient", "try", "var", "void",
"volatile", "while", "string"
));
}
private String baseClass = null;
private boolean isArray = false;
private String typeParam1 = null;
private boolean typeParam1IsArray = false;
private String typeParam2 = null;
private boolean typeParam2IsArray = false;
public static final SignatureVisitor nopVisitor = new SignatureVisitor(Opcodes.ASM5) {};
LocalVariableGenerator() {
super(Opcodes.ASM5);
}
public static String createName(String sig) {
SignatureReader rd = new SignatureReader(sig);
LocalVariableGenerator gen = new LocalVariableGenerator();
rd.acceptType(gen);
return gen.getResult();
}
private String removePath(String in) {
int idx = in.lastIndexOf('/');
int idx2 = in.lastIndexOf('$');
if(idx2 > idx && idx2 != in.length() - 1) {
idx = idx2;
}
if(idx != -1) {
in = in.substring(idx + 1);
}
if(in.length() == 0 || Character.isDigit(in.charAt(0))) {
in = "obj" + in;
}
return in;
}
String getResult() {
String rt;
if(baseClass == null) {
rt = "Object";
}else {
rt = removePath(baseClass);
}
if(typeParam1 == null && typeParam2 == null) {
if(isArray) {
rt = "ArrayOf" + rt;
}
}else {
if(isArray) {
rt = rt + "Array";
}
}
if(typeParam1 != null && typeParam2 == null) {
if(typeParam1IsArray) {
typeParam1 = typeParam1 + "Array";
}
rt = rt + "Of" + removePath(typeParam1);
}else if(typeParam1 != null && typeParam2 != null) {
if(typeParam1IsArray) {
typeParam1 = typeParam1 + "Array";
}
if(typeParam2IsArray) {
typeParam2 = typeParam2 + "Array";
}
rt = rt + "Of" + removePath(typeParam1) + "And" + removePath(typeParam2);
}
return rt;
}
@Override
public SignatureVisitor visitArrayType() {
if(baseClass == null) {
isArray = true;
return new ArrayTypeVisitor();
}else {
return nopVisitor;
}
}
private class ArrayTypeVisitor extends SignatureVisitor {
protected ArrayTypeVisitor() {
super(Opcodes.ASM5);
}
@Override
public void visitBaseType(char descriptor) {
if(baseClass == null) {
baseClass = primitiveNames.get(descriptor);
}
}
@Override
public void visitClassType(String name) {
if(baseClass == null) {
baseClass = name;
}
}
@Override
public SignatureVisitor visitArrayType() {
if(baseClass == null) {
baseClass = "array";
}
return nopVisitor;
}
@Override public SignatureVisitor visitClassBound() { return nopVisitor; }
@Override public SignatureVisitor visitExceptionType() { return nopVisitor; }
@Override public SignatureVisitor visitInterface() { return nopVisitor; }
@Override public SignatureVisitor visitInterfaceBound() { return nopVisitor; }
@Override public SignatureVisitor visitParameterType() { return nopVisitor; }
@Override public SignatureVisitor visitTypeArgument(char wildcard) { return nopVisitor; }
@Override public SignatureVisitor visitReturnType() { return nopVisitor; }
}
@Override
public void visitBaseType(char descriptor) {
if(baseClass == null) {
baseClass = primitiveNames.get(descriptor);
}
}
@Override
public SignatureVisitor visitClassBound() {
//System.out.println("class: " + this);
return nopVisitor;
}
@Override
public void visitClassType(String name) {
//System.out.println("classType: " + name);
if(baseClass == null) {
baseClass = name;
}
}
@Override
public void visitEnd() {
}
@Override
public SignatureVisitor visitExceptionType() {
return nopVisitor;
}
@Override
public void visitFormalTypeParameter(String name) {
//System.out.println("formalTypeParam: " + name);
}
@Override
public void visitInnerClassType(String name) {
//System.out.println("innerClassType: " + name);
}
@Override
public SignatureVisitor visitInterface() {
return nopVisitor;
}
@Override
public SignatureVisitor visitInterfaceBound() {
return nopVisitor;
}
@Override
public SignatureVisitor visitParameterType() {
return nopVisitor;
}
private class TypeParamVisitor extends SignatureVisitor {
private boolean hasVisited = false;
private final int firstOrSecond;
protected TypeParamVisitor(int firstOrSecond) {
super(Opcodes.ASM5);
this.firstOrSecond = firstOrSecond;
}
@Override
public void visitBaseType(char descriptor) {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = primitiveNames.get(descriptor);
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = primitiveNames.get(descriptor);
}
}
hasVisited = true;
}
}
@Override
public void visitClassType(String name) {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = name;
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = name;
}
}
hasVisited = true;
}
}
@Override
public SignatureVisitor visitArrayType() {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1IsArray = true;
return new TypeParamArrayVisitor();
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2IsArray = true;
return new TypeParamArrayVisitor();
}
}
}
return nopVisitor;
}
private class TypeParamArrayVisitor extends SignatureVisitor {
protected TypeParamArrayVisitor() {
super(Opcodes.ASM5);
}
@Override
public void visitBaseType(char descriptor) {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = primitiveNames.get(descriptor);
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = primitiveNames.get(descriptor);
}
}
hasVisited = true;
}
}
@Override
public void visitClassType(String name) {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = name;
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = name;
}
}
hasVisited = true;
}
}
@Override
public SignatureVisitor visitArrayType() {
if(!hasVisited) {
if(firstOrSecond == 1) {
if(typeParam1 == null) {
typeParam1 = "array";
}
}else if(firstOrSecond == 2) {
if(typeParam2 == null) {
typeParam2 = "array";
}
}
hasVisited = true;
}
return nopVisitor;
}
@Override public SignatureVisitor visitClassBound() { return nopVisitor; }
@Override public SignatureVisitor visitExceptionType() { return nopVisitor; }
@Override public SignatureVisitor visitInterface() { return nopVisitor; }
@Override public SignatureVisitor visitInterfaceBound() { return nopVisitor; }
@Override public SignatureVisitor visitParameterType() { return nopVisitor; }
@Override public SignatureVisitor visitTypeArgument(char wildcard) { return nopVisitor; }
@Override public SignatureVisitor visitReturnType() { return nopVisitor; }
}
}
@Override
public SignatureVisitor visitReturnType() {
return nopVisitor;
}
@Override
public SignatureVisitor visitSuperclass() {
return nopVisitor;
}
@Override
public void visitTypeArgument() {
}
@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
if(typeParam1 == null) {
return new TypeParamVisitor(1);
}else if(typeParam2 == null) {
return new TypeParamVisitor(2);
}else {
return nopVisitor;
}
}
@Override
public void visitTypeVariable(String name) {
}
public static String nextLocalVariableNameFromString(Map<String,Integer> tmpLocalsMap, String signature, String pfx) {
String str = signature.length() == 1 ? primitiveNames.get(signature.charAt(0)) : null;
if(str == null) {
str = LocalVariableGenerator.createName(signature);
}
String ls = str.toLowerCase();
Integer i = tmpLocalsMap.get(ls);
if(i == null) {
tmpLocalsMap.put(ls, 1);
if(Character.isDigit(str.charAt(str.length() - 1))) {
str = str + "_1";
}else {
str = illegalVariableNames.contains(str.toLowerCase()) ? str + "1" : str;
}
}else {
int ii = i.intValue() + 1;
tmpLocalsMap.put(ls, ii);
if(Character.isDigit(str.charAt(str.length() - 1)) || str.contains("And") || str.length() > 16) {
str = str + "_" + ii;
}else {
str = str + ii;
}
}
return pfx == null ? camelCase(str) : pfx + str;
}
public static String nextLocalVariableName(Map<String,Integer> tmpLocalsMap, LocalVariableGenerator signature, String pfx) {
String str = signature.getResult();
String ls = str.toLowerCase();
Integer i = tmpLocalsMap.get(ls);
if(i == null) {
tmpLocalsMap.put(ls, 1);
if(Character.isDigit(str.charAt(str.length() - 1))) {
str = str + "_1";
}else {
str = illegalVariableNames.contains(str.toLowerCase()) ? str + "1" : str;
}
}else {
int ii = i.intValue() + 1;
tmpLocalsMap.put(ls, ii);
if(Character.isDigit(str.charAt(str.length() - 1)) || str.contains("And") || str.length() > 16) {
str = str + "_" + ii;
}else {
str = str + ii;
}
}
return pfx == null ? camelCase(str) : pfx + str;
}
public static String camelCase(String in) {
if(in == null || in.length() <= 0) {
return "name";
}else {
if(in.length() > 1 && Character.isUpperCase(in.charAt(0)) && Character.isUpperCase(in.charAt(1))) {
return "var" + in;
}else {
return in.substring(0, 1).toLowerCase() + in.substring(1);
}
}
}
}

View File

@ -0,0 +1,88 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.decompiler;
import java.util.ArrayList;
import java.util.HashMap;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class ParameterSplitter extends SignatureVisitor {
protected ParameterSplitter() {
super(Opcodes.ASM5);
}
protected static final ArrayList<LocalVariableGenerator> ret = new ArrayList();
protected static final HashMap<String,Integer> usedLocals = new HashMap();
public static int getParameterArray(String sig, String[] input) {
SignatureReader rd = new SignatureReader(sig);
ParameterSplitter pms = new ParameterSplitter();
ret.clear();
usedLocals.clear();
rd.accept(pms);
int l = ret.size();
if(l > input.length) {
l = input.length;
}
int c = 0;
for(int i = 0; i < l; ++i) {
if(input[i] == null) {
input[i] = LocalVariableGenerator.nextLocalVariableName(usedLocals, ret.get(i), "par");
++c;
}
}
return c;
}
public static String[] getParameterSigArray(String sig, String pfx) {
SignatureReader rd = new SignatureReader(sig);
ParameterSplitter pms = new ParameterSplitter();
ret.clear();
usedLocals.clear();
rd.accept(pms);
String[] r = new String[ret.size()];
for(int i = 0; i < r.length; ++i) {
r[i] = LocalVariableGenerator.nextLocalVariableName(usedLocals, ret.get(i), pfx);
}
return r;
}
@Override
public SignatureVisitor visitParameterType() {
LocalVariableGenerator lv = new LocalVariableGenerator();
ret.add(lv);
return lv;
}
@Override public SignatureVisitor visitClassBound() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitExceptionType() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitInterface() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitInterfaceBound() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitTypeArgument(char wildcard) { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitReturnType() { return LocalVariableGenerator.nopVisitor; }
@Override public SignatureVisitor visitArrayType() { return LocalVariableGenerator.nopVisitor; }
@Override public void visitBaseType(char descriptor) { }
@Override public void visitClassType(String name) { }
@Override public void visitEnd() { }
@Override public void visitFormalTypeParameter(String name) { }
@Override public void visitInnerClassType(String name) { }
@Override public SignatureVisitor visitSuperclass() { return LocalVariableGenerator.nopVisitor; }
@Override public void visitTypeArgument() { }
@Override public void visitTypeVariable(String name) { }
}

View File

@ -0,0 +1,416 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.awt.Desktop;
import java.awt.EventQueue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.apache.commons.io.FileUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries.MissingJARsException;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.DecompileMinecraft;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.FFMPEG;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InitMCP;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge.TeaVMClassLoadException;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge.TeaVMRuntimeException;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class CompileLatestClientGUI {
public static CompileLatestClientFrame frame = null;
public static void main(String[] args) {
System.out.println();
System.out.println("Launching client compiler wizard...");
System.out.println("Copyright (c) 2022 lax1dude");
System.out.println();
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException e) {
System.err.println("Could not set system look and feel: " + e.toString());
}
if(!System.getProperty("eaglercraft.isJava11", "false").equalsIgnoreCase("true")) {
try {
if (!(boolean) Class
.forName("net.lax1dude.eaglercraft.v1_8.buildtools.Java11Check", true,
new URLClassLoader(new URL[] { (new File("buildtools/Java11Check.jar")).toURI().toURL() }))
.getMethod("classLoadCheck").invoke(null)) {
throw new RuntimeException("wtf?");
}
}catch(Throwable t) {
JOptionPane.showMessageDialog(null, "Error: Java 11 is required to run this program", "Unsupported JRE", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
return;
}
}
frame = new CompileLatestClientFrame();
frame.frmCompileLatestClient.setLocationRelativeTo(null);
frame.frmCompileLatestClient.setVisible(true);
System.out.println("you eagler");
System.out.println();
frame.launchLogUpdateThread();
System.setOut(new PrintStream(new ConsoleRedirector(false)));
System.setErr(new PrintStream(new ConsoleRedirector(true)));
if(JavaC.jdkHome == null) {
if(JOptionPane.showConfirmDialog(frame.frmCompileLatestClient, "Error: A JDK is required to run this program!\nYou are currently running on a JRE\nDo you have a JDK installed that you would like to use instead?", "Unsupported JRE", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "You need at least JDK 8 to compile EaglercraftX 1.8!\nSelect the path to the installation you want to use", "Unsupported JRE", JOptionPane.INFORMATION_MESSAGE);
JFileChooser fileChooser = new JFileChooser((new File(System.getProperty("java.home"))).getParentFile());
fileChooser.setMultiSelectionEnabled(false);
fileChooser.setFileHidingEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
while(true) {
if(fileChooser.showOpenDialog(frame.frmCompileLatestClient) == JFileChooser.APPROVE_OPTION) {
File f = fileChooser.getSelectedFile();
if(JavaC.windows ? (new File(f, "bin/javac.exe")).exists() : (new File(f, "bin/javac")).canExecute()) {
break;
}else {
if(JOptionPane.showConfirmDialog(frame.frmCompileLatestClient, "Could not find a java compiler in this directory!\nWould you like to try again?", "Unsupported JRE", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
continue;
}
}
}
JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "Please install JDK 8 or newer to continue", "Unsupported JRE", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
return;
}
JavaC.jdkHome = fileChooser.getSelectedFile();
JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "The JDK \"" + JavaC.jdkHome.getAbsolutePath() + "\" will be used to compile EaglercraftX", "Unsupported JRE", JOptionPane.INFORMATION_MESSAGE);
}else {
JOptionPane.showMessageDialog(frame.frmCompileLatestClient, "Please install a JDK and re-launch this program", "Unsupported JRE", JOptionPane.ERROR_MESSAGE);
System.exit(-1);
}
}
EventQueue.invokeLater(new Runnable() {
public void run() {
frame.scrollPane_LicenseText.getVerticalScrollBar().setValue(0);
}
});
}
});
}
public static class CompileFailureException extends RuntimeException {
public CompileFailureException(String msg) {
super(msg);
}
public CompileFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}
public static void runCompiler() {
try {
runCompiler0();
}catch(CompileFailureException t) {
System.out.println();
System.err.println("Error: " + t.getMessage());
t.printStackTrace();
frame.finishCompiling(true, t.getMessage());
return;
}catch(Throwable t) {
System.out.println();
System.err.println("Error: unhandled exception caught while compiling!");
t.printStackTrace();
frame.finishCompiling(true, t.toString());
return;
}
if(!frame.finished) {
System.out.println();
System.err.println("Error: compilation finished with unknown status!");
frame.finishCompiling(true, "Compilation finished with unknown status");
}
}
private static void runCompiler0() throws Throwable {
File repositoryFolder = new File(frame.textField_RepositoryPath.getText().trim());
EaglerBuildTools.repositoryRoot = repositoryFolder;
File modCoderPack = new File(frame.textField_ModCoderPack.getText().trim());
File minecraftJar = new File(frame.textField_JarFilePath.getText().trim());
File assetsIndex = new File(frame.textField_AssetsIndexJSON.getText().trim());
File outputDirectory = new File(frame.textField_OutputDirectory.getText().trim());
File temporaryDirectory = new File(outputDirectory, "build");
File[] existingOutput = outputDirectory.listFiles();
if(existingOutput.length > 0) {
System.out.println("Deleting existing files from the output directory...");
try {
for(int i = 0; i < existingOutput.length; ++i) {
File f = existingOutput[i];
if(f.isDirectory()) {
FileUtils.deleteDirectory(f);
}else {
if(!f.delete()) {
throw new IOException("Could not delete: " + f.getAbsolutePath());
}
}
}
}catch(IOException t) {
throw new CompileFailureException("Could not delete old output directory: " + t.getMessage());
}
}
File mcpDataTMP = new File(temporaryDirectory, "ModCoderPack");
File minecraftSrcTmp = new File(temporaryDirectory, "MinecraftSrc");
String ffmpeg = frame.chckbxUsePathFFmpeg.isSelected() ? "" : frame.textField_pathToFFmpeg.getText().trim();
if(ffmpeg.length() == 0) {
FFMPEG.foundFFMPEG = "ffmpeg";
}else {
FFMPEG.foundFFMPEG = ffmpeg;
}
String mavenRepositoryURL = frame.getRepositoryURL();
File mavenRepositoryFolder = null;
if(mavenRepositoryURL == null) {
mavenRepositoryFolder = new File(frame.textField_MavenRepoLocal.getText().trim());
}
boolean generateOfflineDownload = frame.chckbxOutputOfflineDownload.isSelected();
boolean keepTemporaryFiles = frame.chckbxKeepTemporaryFiles.isSelected();
if(!mcpDataTMP.isDirectory() && !mcpDataTMP.mkdirs()) {
throw new CompileFailureException("Error: failed to create \"" + mcpDataTMP.getAbsolutePath() + "\"!");
}
if(!InitMCP.initTask(modCoderPack, mcpDataTMP)) {
throw new CompileFailureException("Error: could not initialize MCP from \"" + modCoderPack.getAbsolutePath() + "\"!");
}
if(!minecraftSrcTmp.isDirectory() && !minecraftSrcTmp.mkdirs()) {
throw new CompileFailureException("Error: failed to create \"" + minecraftSrcTmp.getAbsolutePath() + "\"!");
}
if(!DecompileMinecraft.decompileMinecraft(mcpDataTMP, minecraftJar, minecraftSrcTmp, assetsIndex, false)) {
throw new CompileFailureException("Error: could not decompile and patch 1.8.8.jar from \"" + minecraftJar.getAbsolutePath() + "\"!");
}
try {
FileUtils.copyFile(new File(repositoryFolder, "patches/minecraft/output_license.txt"), new File(temporaryDirectory, "MinecraftSrc/LICENSE"));
}catch(IOException ex) {
System.err.println("Error: failed to write LICENSE in temporary directory!");
ex.printStackTrace();
}
System.out.println();
if(frame.rdbtnMavenRepoLocal.isSelected()) {
System.out.println("TeaVM JARs will be loaded from: " + frame.textField_MavenRepoLocal.getText());
}else {
String url = frame.getRepositoryURL();
System.out.println("TeaVM JARs will be downloaded from repository: " + url);
System.out.println();
try {
TeaVMBinaries.downloadFromMaven(url, new File("##TEAVM.TMP##"));
}catch(MissingJARsException ex) {
throw new CompileFailureException(ex.getMessage());
}
}
System.out.println();
int compileResultCode;
File compiledResultClasses = new File(temporaryDirectory, "classes");
try {
try {
compileResultCode = JavaC.runJavaC(new File(minecraftSrcTmp, "minecraft_src_javadoc.jar"),
compiledResultClasses, temporaryDirectory, TeaVMBinaries.getTeaVMRuntimeClasspath(),
new File(repositoryFolder, "sources/main/java"), new File(repositoryFolder, "sources/teavm/java"));
}catch(IOException ex) {
throw new CompileFailureException("failed to run javac compiler! " + ex.toString(), ex);
}
System.out.println();
if(compileResultCode == 0) {
System.out.println("Java compiler completed successfully");
}else {
throw new CompileFailureException("failed to run javac compiler! exit code " + compileResultCode + ", check log");
}
}finally {
File extractedSrcTmp = new File(temporaryDirectory, "MinecraftSrc/src_javadoc_tmp");
if(extractedSrcTmp.exists()) {
System.out.println();
System.out.println("Deleting temporary directory: " + extractedSrcTmp.getAbsolutePath());
try {
FileUtils.deleteDirectory(extractedSrcTmp);
}catch(IOException ex) {
System.err.println("Failed to delete temporary directory!");
ex.printStackTrace();
}
}
}
System.out.println();
System.out.println("Preparing arguments for TeaVM...");
if(!TeaVMBinaries.tryLoadTeaVMBridge()) {
System.err.println("Failed to locate TeaVMBridge.jar, you can specify it's path manually by adding the JVM argument \"-Deaglercraft.TeaVMBridge=<path>\"");
throw new CompileFailureException("Failed to locate TeaVMBridge.jar!");
}
Map<String, Object> teavmArgs = new HashMap();
List<String> teavmClassPath = new ArrayList();
teavmClassPath.add(compiledResultClasses.getAbsolutePath());
teavmClassPath.addAll(Arrays.asList(TeaVMBinaries.getTeaVMRuntimeClasspath()));
teavmArgs.put("classPathEntries", teavmClassPath);
teavmArgs.put("entryPointName", "main");
teavmArgs.put("mainClass", "net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass");
teavmArgs.put("minifying", true);
teavmArgs.put("optimizationLevel", "ADVANCED");
teavmArgs.put("targetDirectory", outputDirectory.getAbsolutePath());
teavmArgs.put("generateSourceMaps", true);
teavmArgs.put("targetFileName", "classes.js");
System.out.println();
boolean teavmStatus;
try {
teavmStatus = TeaVMBridge.compileTeaVM(teavmArgs);
}catch(TeaVMClassLoadException ex) {
throw new CompileFailureException("Failed to link TeaVM jar files! Did you select the wrong jar?", ex);
}catch(TeaVMRuntimeException ex) {
throw new CompileFailureException("Failed to run TeaVM! Check log", ex);
}
if(!teavmStatus) {
frame.finishCompiling(true, "TeaVM reported problems, check the log");
return;
}
File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/CompileEPK.jar");
if(!epkCompiler.exists()) {
throw new CompileFailureException("EPKCompiler JAR file is missing: " + epkCompiler.getAbsolutePath());
}
System.out.println();
System.out.println("Writing default index.html...");
FileUtils.copyFile(new File(repositoryFolder, "buildtools/production-index.html"), new File(outputDirectory, "index.html"));
FileUtils.copyFile(new File(repositoryFolder, "buildtools/production-favicon.png"), new File(outputDirectory, "favicon.png"));
FileUtils.copyFile(new File(repositoryFolder, "sources/setup/workspace_template/javascript/fix-webm-duration.js"), new File(outputDirectory, "fix-webm-duration.js"));
System.out.println();
System.out.println("Running EPKCompiler on assets...");
EPKCompiler.compilerMain(epkCompiler, new String[] {
((new File(minecraftSrcTmp, "minecraft_res_patch.jar")).getAbsolutePath() + System.getProperty("path.separator") +
(new File(repositoryFolder, "sources/resources")).getAbsolutePath()), (new File(outputDirectory, "assets.epk")).getAbsolutePath() });
System.out.println();
System.out.println("Running EPKCompiler on languages.zip...");
EPKCompiler.compilerMain(epkCompiler, new String[] {
(new File(minecraftSrcTmp, "minecraft_languages.zip")).getAbsolutePath(),
(new File(temporaryDirectory, "languages.epk")).getAbsolutePath() });
System.out.println();
System.out.println("Creating languages directory...");
File langDirectory = new File(outputDirectory, "lang");
byte[] copyBuffer = new byte[16384];
int i;
try(ZipInputStream zis = new ZipInputStream(new FileInputStream(new File(minecraftSrcTmp, "minecraft_languages.zip")))) {
ZipEntry etr;
while((etr = zis.getNextEntry()) != null) {
if(!etr.isDirectory()) {
File phile = new File(langDirectory, etr.getName());
File parent = phile.getParentFile();
if(!parent.exists() && !parent.mkdirs()) {
throw new IOException("Could not create directory: " + parent.getAbsolutePath());
}
try(FileOutputStream os = new FileOutputStream(phile)) {
while((i = zis.read(copyBuffer)) != -1) {
os.write(copyBuffer, 0, i);
}
}
}
}
}
System.out.println();
if(generateOfflineDownload) {
System.out.println("Running offline download generator...");
System.out.println();
File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/MakeOfflineDownload.jar");
MakeOfflineDownload.compilerMain(offlineDownloadGenerator, new String[] {
(new File(repositoryFolder, "sources/setup/workspace_template/javascript/OfflineDownloadTemplate.txt")).getAbsolutePath(),
(new File(outputDirectory, "classes.js")).getAbsolutePath() + System.getProperty("path.separator")
+ (new File(outputDirectory, "fix-webm-duration.js")).getAbsolutePath(),
(new File(outputDirectory, "assets.epk")).getAbsolutePath(),
(new File(outputDirectory, "EaglercraftX_1.8_Offline_en_US.html")).getAbsolutePath(),
(new File(outputDirectory, "EaglercraftX_1.8_Offline_International.html")).getAbsolutePath(),
(new File(outputDirectory, "build/languages.epk")).getAbsolutePath()
});
}
System.out.println("Releasing external ClassLoader(s)...");
System.out.println();
TeaVMBridge.free();
EPKCompiler.free();
if(generateOfflineDownload) {
MakeOfflineDownload.free();
}
if(!keepTemporaryFiles) {
System.out.println("Cleaning up temporary files...");
try {
FileUtils.deleteDirectory(temporaryDirectory);
}catch(IOException ex) {
System.err.println("Failed to delete temporary directory: " + temporaryDirectory.getAbsolutePath());
ex.printStackTrace();
}
}
System.out.println();
System.out.println("Client build successful! Check the output directory for your files");
try {
Desktop.getDesktop().open(outputDirectory);
}catch(Throwable t) {
}
frame.finishCompiling(false, "");
}
}

View File

@ -0,0 +1,58 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class ConsoleRedirector extends OutputStream {
private final OutputStream stdout;
private final boolean err;
public ConsoleRedirector(boolean err) {
stdout = err ? System.err : System.out;
this.err = err;
}
@Override
public void write(byte[] b, int o, int l) throws IOException {
stdout.write(b, o, l);
String append = new String(b, o, l, StandardCharsets.US_ASCII);
if(err) {
CompileLatestClientGUI.frame.logError(append);
}else {
CompileLatestClientGUI.frame.logInfo(append);
}
}
@Override
public void write(int b) throws IOException {
stdout.write(b);
write0(b);
}
private void write0(int b) throws IOException {
char c = (char)b;
if(c != '\r') {
if(err && c != '\n') {
CompileLatestClientGUI.frame.logError(new String(new char[] { c }));
}else {
CompileLatestClientGUI.frame.logInfo(new String(new char[] { c }));
}
}
}
}

View File

@ -0,0 +1,67 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EPKCompiler {
private static File currentJarFile = null;
private static URLClassLoader classLoader = null;
private static Method mainMethod = null;
public static void compilerMain(File jarFile, String[] args) throws InvocationTargetException {
if(currentJarFile != null && !currentJarFile.equals(jarFile)) {
throw new IllegalArgumentException("Cannot load two different EPKCompiler versions into the same runtime");
}
if(mainMethod == null) {
currentJarFile = jarFile;
try {
if(classLoader == null) {
classLoader = new URLClassLoader(new URL[] { jarFile.toURI().toURL() }, ClassLoader.getSystemClassLoader());
}
Class epkCompilerMain = classLoader.loadClass("CompilePackage");
mainMethod = epkCompilerMain.getDeclaredMethod("main", String[].class);
} catch (MalformedURLException | SecurityException e) {
throw new IllegalArgumentException("Illegal EPKCompiler JAR path!", e);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new IllegalArgumentException("EPKCompiler JAR does not contain main class: 'CompilePackage'", e);
}
}
try {
mainMethod.invoke(null, new Object[] { args });
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new IllegalArgumentException("EPKCompiler JAR does not contain valid 'main' method", e);
}
}
public static void free() {
if(classLoader != null) {
try {
classLoader.close();
classLoader = null;
} catch (IOException e) {
System.err.println("Memory leak, failed to release EPKCompiler ClassLoader!");
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,223 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class JavaC {
public static final boolean windows;
public static File jdkHome;
public static final List<String> compilerFlags = Arrays.asList(
"-Xlint:-unchecked", "-Xlint:-options", "-Xlint:-deprecation",
"-source", "1.8", "-target", "1.8"
);
private static int debugSourceFileCount = 0;
public static int runJavaC(File mcSourceJar, File outputDirectory, File tmpDirectory, String[] teavmClasspath,
File... eaglerSourceDirs) throws IOException {
if(!outputDirectory.exists() && !outputDirectory.mkdirs()) {
throw new IOException("Could not create output directory: " + outputDirectory.getAbsolutePath());
}
if(!tmpDirectory.exists() && !tmpDirectory.mkdirs()) {
throw new IOException("Could not create temporary directory: " + outputDirectory.getAbsolutePath());
}
File minecraftSrcTmp = new File(tmpDirectory, "MinecraftSrc/src_javadoc_tmp");
if(!minecraftSrcTmp.exists() && !minecraftSrcTmp.mkdirs()) {
throw new IOException("Could not create temporary directory: " + minecraftSrcTmp.getAbsolutePath());
}
debugSourceFileCount = 0;
File argFile = new File(tmpDirectory, "sourceFiles.txt");
try(PrintWriter writer = new PrintWriter(new FileWriter(argFile))) {
System.out.println("Extracting decompiled source...");
byte[] copyBuffer = new byte[16384];
int copyBufferLen;
try(ZipInputStream zis = new ZipInputStream(new FileInputStream(mcSourceJar))) {
ZipEntry etr;
while((etr = zis.getNextEntry()) != null && !etr.isDirectory()) {
String n = etr.getName();
if(n.endsWith(".java")) {
File writeTo = new File(minecraftSrcTmp, n);
File parent = writeTo.getParentFile();
if(!parent.exists() && !parent.mkdirs()) {
throw new IOException("Could not create temporary directory: " + parent.getAbsolutePath());
}
try(OutputStream os = new FileOutputStream(writeTo)) {
while((copyBufferLen = zis.read(copyBuffer)) != -1) {
os.write(copyBuffer, 0, copyBufferLen);
}
}
writer.println("\"" + writeTo.getAbsolutePath().replace('\\', '/') + "\"");
++debugSourceFileCount;
}
}
}
System.out.println("Scanning source folder paths...");
for(int i = 0; i < eaglerSourceDirs.length; ++i) {
discoverSourceFiles(eaglerSourceDirs[i], writer);
}
}
List<String> commandBuilder = new ArrayList();
if(windows) {
commandBuilder.add((new File(jdkHome, "bin/javac.exe")).getAbsolutePath());
}else {
commandBuilder.add((new File(jdkHome, "bin/javac")).getAbsolutePath());
}
commandBuilder.addAll(compilerFlags);
String pathSeparator = System.getProperty("path.separator");
commandBuilder.add("-classpath");
commandBuilder.add(String.join(pathSeparator, teavmClasspath));
commandBuilder.add("-sourcepath");
StringBuilder sourcePathBuilder = new StringBuilder();
sourcePathBuilder.append(mcSourceJar.getAbsolutePath());
for(int i = 0; i < eaglerSourceDirs.length; ++i) {
sourcePathBuilder.append(pathSeparator).append(eaglerSourceDirs[i].getAbsolutePath());
}
commandBuilder.add(sourcePathBuilder.toString());
commandBuilder.add("-d");
commandBuilder.add(outputDirectory.getAbsolutePath());
commandBuilder.add("@" + argFile.getAbsolutePath());
System.out.println();
for(int i = 0, l = commandBuilder.size(); i < l; ++i) {
String e = commandBuilder.get(i);
if(e.indexOf(' ') != -1) {
System.out.print("\"" + e + "\"");
}else {
System.out.print(e);
}
System.out.print(' ');
}
System.out.println();
System.out.println();
System.out.println("Compiling " + debugSourceFileCount + " source files...");
ProcessBuilder procBuilder = new ProcessBuilder(commandBuilder);
procBuilder.directory(tmpDirectory);
Process javacProcess = procBuilder.start();
InputStream stdout = javacProcess.getInputStream();
InputStream stderr = javacProcess.getErrorStream();
byte[] readBuffer = new byte[128];
int j;
boolean tick;
do {
tick = false;
j = stdout.available();
if(j > 0) {
if(j > 128) {
j = 128;
}
stdout.read(readBuffer, 0, j);
System.out.write(readBuffer, 0, j);
tick = true;
}
j = stderr.available();
if(j > 0) {
if(j > 128) {
j = 128;
}
stderr.read(readBuffer, 0, j);
System.err.write(readBuffer, 0, j);
tick = true;
}
if(!tick) {
try {
Thread.sleep(10l);
} catch (InterruptedException e) {
}
}
}while(javacProcess.isAlive());
while(true) {
try {
return javacProcess.waitFor();
} catch (InterruptedException e) {
}
}
}
private static void discoverSourceFiles(File folder, PrintWriter printWriter) throws IOException {
File[] files = folder.listFiles();
for(int i = 0; i < files.length; ++i) {
File f = files[i];
String name = f.getAbsolutePath();
if(f.isDirectory()) {
discoverSourceFiles(f, printWriter);
}else {
if(name.endsWith(".java")) {
printWriter.println("\"" + name.replace('\\', '/') + "\"");
++debugSourceFileCount;
}
}
}
}
static {
windows = System.getProperty("os.name").toLowerCase().contains("windows");
String javac = windows ? "javac.exe" : "javac";
File jdkHomeProp = new File(System.getProperty("java.home"));
if((new File(jdkHomeProp, "bin/" + javac)).isFile()) {
jdkHome = jdkHomeProp;
}else if((new File(jdkHomeProp, "../bin/" + javac)).isFile()) {
jdkHome = jdkHomeProp.getParentFile();
}else {
jdkHome = null;
}
}
}

View File

@ -0,0 +1,67 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class MakeOfflineDownload {
private static File currentJarFile = null;
private static URLClassLoader classLoader = null;
private static Method mainMethod = null;
public static void compilerMain(File jarFile, String[] args) throws InvocationTargetException {
if(currentJarFile != null && !currentJarFile.equals(jarFile)) {
throw new IllegalArgumentException("Cannot load two different MakeOfflineDownload versions into the same runtime");
}
if(mainMethod == null) {
currentJarFile = jarFile;
try {
if(classLoader == null) {
classLoader = new URLClassLoader(new URL[] { jarFile.toURI().toURL() }, ClassLoader.getSystemClassLoader());
}
Class epkCompilerMain = classLoader.loadClass("net.lax1dude.eaglercraft.v1_8.buildtools.workspace.MakeOfflineDownload");
mainMethod = epkCompilerMain.getDeclaredMethod("main", String[].class);
} catch (MalformedURLException | SecurityException e) {
throw new IllegalArgumentException("Illegal MakeOfflineDownload JAR path!", e);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new IllegalArgumentException("MakeOfflineDownload JAR does not contain main class: 'net.lax1dude.eaglercraft.v1_8.buildtools.workspace.MakeOfflineDownload'", e);
}
}
try {
mainMethod.invoke(null, new Object[] { args });
} catch (IllegalAccessException | IllegalArgumentException e) {
throw new IllegalArgumentException("MakeOfflineDownload JAR does not contain valid 'main' method", e);
}
}
public static void free() {
if(classLoader != null) {
try {
classLoader.close();
classLoader = null;
} catch (IOException e) {
System.err.println("Memory leak, failed to release MakeOfflineDownload ClassLoader!");
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,422 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.FileUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class TeaVMBinaries {
public static final String teavmCoreJar = "teavm-core-0.6.1.jar";
public static final String teavmCoreMaven = "org/teavm/teavm-core/0.6.1/teavm-core-0.6.1.jar";
public static File teavmCore = null;
public static final String teavmCliJar = "teavm-cli-0.6.1.jar";
public static final String teavmCliMaven = "org/teavm/teavm-cli/0.6.1/teavm-cli-0.6.1.jar";
public static File teavmCli = null;
public static final String teavmToolingJar = "teavm-tooling-0.6.1.jar";
public static final String teavmToolingMaven = "org/teavm/teavm-tooling/0.6.1/teavm-tooling-0.6.1.jar";
public static File teavmTooling = null;
public static final String teavmPlatformJar = "teavm-platform-0.6.1.jar";
public static final String teavmPlatformMaven = "org/teavm/teavm-platform/0.6.1/teavm-platform-0.6.1.jar";
public static File teavmPlatform = null;
public static final String teavmClasslibJar = "teavm-classlib-0.6.1.jar";
public static final String teavmClasslibMaven = "org/teavm/teavm-classlib/0.6.1/teavm-classlib-0.6.1.jar";
public static File teavmClasslib = null;
public static final String teavmInteropJar = "teavm-interop-0.6.1.jar";
public static final String teavmInteropMaven = "org/teavm/teavm-interop/0.6.1/teavm-interop-0.6.1.jar";
public static File teavmInterop = null;
public static final String teavmJSOJar = "teavm-jso-0.6.1.jar";
public static final String teavmJSOMaven = "org/teavm/teavm-jso/0.6.1/teavm-jso-0.6.1.jar";
public static File teavmJSO = null;
public static final String teavmJSOApisJar = "teavm-jso-apis-0.6.1.jar";
public static final String teavmJSOApisMaven = "org/teavm/teavm-jso-apis/0.6.1/teavm-jso-apis-0.6.1.jar";
public static File teavmJSOApis = null;
public static final String teavmJSOImplJar = "teavm-jso-impl-0.6.1.jar";
public static final String teavmJSOImplMaven = "org/teavm/teavm-jso-impl/0.6.1/teavm-jso-impl-0.6.1.jar";
public static File teavmJSOImpl = null;
public static final String teavmMetaprogrammingAPIJar = "teavm-metaprogramming-api-0.6.1.jar";
public static final String teavmMetaprogrammingAPIMaven = "org/teavm/teavm-metaprogramming-api/0.6.1/teavm-metaprogramming-api-0.6.1.jar";
public static File teavmMetaprogrammingAPI = null;
public static final String teavmMetaprogrammingImplJar = "teavm-metaprogramming-impl-0.6.1.jar";
public static final String teavmMetaprogrammingImplMaven = "org/teavm/teavm-metaprogramming-impl/0.6.1/teavm-metaprogramming-impl-0.6.1.jar";
public static File teavmMetaprogrammingImpl = null;
public static final String teavmJodaTimeJar = "joda-time-2.7.jar";
public static final String teavmJodaTimeMaven = "joda-time/joda-time/2.7/joda-time-2.7.jar";
public static File teavmJodaTime = null;
public static final String teavmJZLIBJar = "jzlib-1.1.3.jar";
public static final String teavmJZLIBMaven = "com/jcraft/jzlib/1.1.3/jzlib-1.1.3.jar";
public static File teavmJZLIB = null;
public static File teavmBridge = null;
public static class MissingJARsException extends RuntimeException {
public final List<String> jars;
public MissingJARsException(String msg, List<String> jars) {
super(msg);
this.jars = jars;
}
public MissingJARsException(List<String> jars) {
this("The following JAR files were not found: " + String.join(", ", jars), jars);
}
}
public static void downloadFromMaven(String url, File outputDir) throws MissingJARsException {
teavmCore = teavmPlatform = teavmClasslib = teavmInterop = teavmJSO =
teavmJSOApis = teavmJSOImpl = teavmMetaprogrammingAPI = teavmMetaprogrammingImpl =
teavmJodaTime = teavmJZLIB = teavmTooling = teavmCli = null;
if(url.lastIndexOf('/') != url.length() - 1) {
url += "/";
}
String urlConc = url + teavmCoreMaven;
try {
File f = new File(outputDir, teavmCoreJar);
copyURLToFileCheck404(urlConc, f);
teavmCore = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmCliMaven;
try {
File f = new File(outputDir, teavmCliJar);
copyURLToFileCheck404(urlConc, f);
teavmCli = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmToolingMaven;
try {
File f = new File(outputDir, teavmToolingJar);
copyURLToFileCheck404(urlConc, f);
teavmTooling = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmPlatformMaven;
try {
File f = new File(outputDir, teavmPlatformJar);
copyURLToFileCheck404(urlConc, f);
teavmPlatform = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmClasslibMaven;
try {
File f = new File(outputDir, teavmClasslibJar);
copyURLToFileCheck404(urlConc, f);
teavmClasslib = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmInteropMaven;
try {
File f = new File(outputDir, teavmInteropJar);
copyURLToFileCheck404(urlConc, f);
teavmInterop = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJSOMaven;
try {
File f = new File(outputDir, teavmJSOJar);
copyURLToFileCheck404(urlConc, f);
teavmJSO = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJSOApisMaven;
try {
File f = new File(outputDir, teavmJSOApisJar);
copyURLToFileCheck404(urlConc, f);
teavmJSOApis = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJSOImplMaven;
try {
File f = new File(outputDir, teavmJSOImplJar);
copyURLToFileCheck404(urlConc, f);
teavmJSOImpl = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmMetaprogrammingAPIMaven;
try {
File f = new File(outputDir, teavmMetaprogrammingAPIJar);
copyURLToFileCheck404(urlConc, f);
teavmMetaprogrammingAPI = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmMetaprogrammingImplMaven;
try {
File f = new File(outputDir, teavmMetaprogrammingImplJar);
copyURLToFileCheck404(urlConc, f);
teavmMetaprogrammingImpl = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJodaTimeMaven;
try {
File f = new File(outputDir, teavmJodaTimeJar);
copyURLToFileCheck404(urlConc, f);
teavmJodaTime = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
urlConc = url + teavmJZLIBMaven;
try {
File f = new File(outputDir, teavmJZLIBJar);
copyURLToFileCheck404(urlConc, f);
teavmJZLIB = f;
}catch(IOException ex) {
System.err.println("Could not download JAR: " + urlConc);
ex.printStackTrace();
throw new MissingJARsException("The following JAR file could not be downloaded: " + urlConc, Arrays.asList(urlConc));
}
}
public static void loadFromDirectory(File directory) throws MissingJARsException {
teavmCore = teavmPlatform = teavmClasslib = teavmInterop = teavmJSO =
teavmJSOApis = teavmJSOImpl = teavmMetaprogrammingAPI = teavmMetaprogrammingImpl =
teavmJodaTime = teavmJZLIB = teavmTooling = teavmCli = null;
discoverJars(directory);
List<String> missingJars = new ArrayList();
if(teavmCore == null) {
missingJars.add(teavmCoreJar);
}
if(teavmCli == null) {
missingJars.add(teavmCliJar);
}
if(teavmTooling == null) {
missingJars.add(teavmToolingJar);
}
if(teavmPlatform == null) {
missingJars.add(teavmPlatformJar);
}
if(teavmClasslib == null) {
missingJars.add(teavmClasslibJar);
}
if(teavmInterop == null) {
missingJars.add(teavmInteropJar);
}
if(teavmJSO == null) {
missingJars.add(teavmJSOJar);
}
if(teavmJSOApis == null) {
missingJars.add(teavmJSOApisJar);
}
if(teavmJSOImpl == null) {
missingJars.add(teavmJSOImplJar);
}
if(teavmMetaprogrammingAPI == null) {
missingJars.add(teavmMetaprogrammingAPIJar);
}
if(teavmMetaprogrammingImpl == null) {
missingJars.add(teavmMetaprogrammingImplJar);
}
if(teavmJodaTime == null) {
missingJars.add(teavmJodaTimeJar);
}
if(teavmJZLIB == null) {
missingJars.add(teavmJZLIBJar);
}
if(missingJars.size() > 0) {
throw new MissingJARsException(missingJars);
}
}
private static void discoverJars(File dir) {
File[] files = dir.listFiles();
for(int i = 0; i < files.length; ++i) {
File f = files[i];
if(f.isDirectory()) {
discoverJars(f);
}else {
String n = f.getName();
switch(n) {
case teavmCoreJar:
teavmCore = f;
break;
case teavmCliJar:
teavmCli = f;
break;
case teavmToolingJar:
teavmTooling = f;
break;
case teavmPlatformJar:
teavmPlatform = f;
break;
case teavmClasslibJar:
teavmClasslib = f;
break;
case teavmInteropJar:
teavmInterop = f;
break;
case teavmJSOJar:
teavmJSO = f;
break;
case teavmJSOApisJar:
teavmJSOApis = f;
break;
case teavmJSOImplJar:
teavmJSOImpl = f;
break;
case teavmMetaprogrammingAPIJar:
teavmMetaprogrammingAPI = f;
break;
case teavmMetaprogrammingImplJar:
teavmMetaprogrammingImpl = f;
break;
case teavmJodaTimeJar:
teavmJodaTime = f;
break;
case teavmJZLIBJar:
teavmJZLIB = f;
break;
default:
break;
}
}
}
}
private static void copyURLToFileCheck404(String urlIn, File fileOut) throws IOException {
System.out.println("downloading: " + urlIn);
URL url;
try {
url = new URL(urlIn);
}catch(MalformedURLException ex) {
throw new IOException("Invalid URL: " + urlIn, ex);
}
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
int respCode = connection.getResponseCode();
if(respCode != 200) {
connection.disconnect();
throw new IOException("Recieved response code: " + respCode);
}
try (InputStream stream = connection.getInputStream()) {
FileUtils.copyInputStreamToFile(stream, fileOut);
}finally {
connection.disconnect(); // is this required?
}
}
public static boolean tryLoadTeaVMBridge() {
String override = System.getProperty("eaglercraft.TeaVMBridge");
File teavmBridgeCheck;
if(override != null) {
teavmBridgeCheck = new File(override);
}else {
try {
teavmBridgeCheck = new File(new File(URLDecoder.decode(
TeaVMBinaries.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath(),
"UTF-8")).getParent(), "TeaVMBridge.jar");
} catch (URISyntaxException | UnsupportedEncodingException e) {
System.err.println("Failed to locate TeaVMBridge.jar relative to BuildTools jar!");
e.printStackTrace();
return false;
}
}
if(teavmBridgeCheck.exists()) {
teavmBridge = teavmBridgeCheck;
return true;
}else {
System.err.println("File does not exist: " + teavmBridgeCheck.getAbsolutePath());
return false;
}
}
public static File[] getTeaVMCompilerClasspath() {
return new File[] { teavmCore, teavmCli, teavmTooling, teavmInterop, teavmMetaprogrammingAPI, teavmBridge };
}
public static String[] getTeaVMRuntimeClasspath() {
return new String[] {
teavmJodaTime.getAbsolutePath(), teavmJZLIB.getAbsolutePath(), teavmClasslib.getAbsolutePath(),
teavmInterop.getAbsolutePath(), teavmJSO.getAbsolutePath(), teavmJSOApis.getAbsolutePath(),
teavmJSOImpl.getAbsolutePath(), teavmMetaprogrammingAPI.getAbsolutePath(),
teavmMetaprogrammingImpl.getAbsolutePath(), teavmPlatform.getAbsolutePath()
};
}
}

View File

@ -0,0 +1,612 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui.headless;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.LicensePrompt;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.EPKCompiler;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.JavaC;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.MakeOfflineDownload;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.CompileLatestClientGUI.CompileFailureException;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries.MissingJARsException;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.DecompileMinecraft;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.FFMPEG;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InitMCP;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge.TeaVMClassLoadException;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridge.TeaVMRuntimeException;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileReaderUTF;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileWriterUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class CompileLatestClientHeadless {
public static void main(String[] args) throws Throwable {
System.out.println();
System.out.println("Launching client compiler...");
System.out.println("Copyright (c) 2022 lax1dude");
System.out.println();
boolean yes = false;
String configPath = null;
if(args.length == 1) {
configPath = args[0];
}else if(args.length == 2 && (yes = args[0].equalsIgnoreCase("-y"))) {
configPath = args[1];
}else {
System.err.println("Usage: java -jar BuildTools.jar [-y] <config file>");
System.err.println();
System.exit(-1);
return;
}
System.out.println("Loading config file: " + configPath);
System.out.println();
File configFile = new File(configPath);
String configSrc;
try {
configSrc = FileUtils.readFileToString(configFile, StandardCharsets.UTF_8);
}catch(FileNotFoundException ex) {
ex.printStackTrace();
System.err.println();
System.err.println("ERROR: File '" + configFile.getAbsolutePath() + "' does not exist!");
System.err.println();
System.exit(-1);
return;
}
JSONObject configJSON;
try {
configJSON = new JSONObject(configSrc);
}catch(JSONException ex) {
System.err.println("ERROR: Could not parse '" + configFile.getName() + "' as JSON!");
System.err.println();
System.err.println(ex.toString());
System.err.println();
System.exit(-1);
return;
}
File repositoryFolder;
File modCoderPack;
File minecraftJar;
File assetsIndex;
File outputDirectory;
File temporaryDirectory;
String ffmpeg = "ffmpeg";
String mavenURL = null;
File mavenLocal = null;
File productionIndex = null;
File productionFavicon = null;
List<String> addScripts = null;
List<String> removeScripts = null;
List<String> injectInOfflineScripts = null;
boolean generateOffline;
File offlineTemplate = null;
boolean keepTemporaryFiles;
boolean writeSourceMap = false;
boolean minifying = true;
try {
repositoryFolder = new File(configJSON.optString("repositoryFolder", "."));
modCoderPack = new File(configJSON.getString("modCoderPack"));
minecraftJar = new File(configJSON.getString("minecraftJar"));
assetsIndex = new File(configJSON.getString("assetsIndex"));
outputDirectory = new File(configJSON.getString("outputDirectory"));
String tmpDir = configJSON.optString("temporaryDirectory");
temporaryDirectory = tmpDir == null ? new File(outputDirectory, "build") : new File(tmpDir);
ffmpeg = configJSON.optString("ffmpeg", ffmpeg);
if(ffmpeg.length() == 0) {
ffmpeg = "ffmpeg";
}
String prodIndex = configJSON.optString("productionIndex");
if(prodIndex != null) {
productionIndex = new File(prodIndex);
String prodFavicon = configJSON.optString("productionFavicon");
if(prodFavicon != null) {
productionFavicon = new File(prodFavicon);
}
JSONArray scripts = configJSON.optJSONArray("addScripts");
if(scripts != null) {
int l = scripts.length();
if(l > 0) {
addScripts = new ArrayList(l);
for(int i = 0; i < l; ++i) {
addScripts.add(scripts.getString(i));
}
}
}
scripts = configJSON.optJSONArray("removeScripts");
if(scripts != null) {
int l = scripts.length();
if(l > 0) {
removeScripts = new ArrayList(l);
for(int i = 0; i < l; ++i) {
removeScripts.add(scripts.getString(i));
}
}
}
scripts = configJSON.optJSONArray("injectInOffline");
if(scripts != null) {
int l = scripts.length();
if(l > 0) {
injectInOfflineScripts = new ArrayList(l);
for(int i = 0; i < l; ++i) {
injectInOfflineScripts.add(scripts.getString(i));
}
}
}
}
mavenURL = configJSON.optString("mavenURL");
mavenLocal = new File(configJSON.getString("mavenLocal"));
generateOffline = configJSON.optBoolean("generateOfflineDownload", false);
if(generateOffline) {
offlineTemplate = new File(configJSON.getString("offlineDownloadTemplate"));
}
keepTemporaryFiles = configJSON.optBoolean("keepTemporaryFiles", false);
writeSourceMap = configJSON.optBoolean("writeSourceMap", false);
minifying = configJSON.optBoolean("minifying", true);
}catch(JSONException ex) {
System.err.println("CONFIG ERROR: " + ex.toString());
System.err.println();
System.exit(-1);
return;
}
System.out.println("Loaded config successfully:");
System.out.println();
System.out.println(" - Repository Folder: " + repositoryFolder.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Mod Coder Pack: " + modCoderPack.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Minecraft 1.8.8: " + minecraftJar.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Assets Index 1.8: " + assetsIndex.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Temporary Directory: " + temporaryDirectory.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Output Directory: " + outputDirectory.getAbsolutePath().replace('\\', '/'));
System.out.println(" - FFmpeg Executable: " + ffmpeg.replace('\\', '/'));
System.out.println(" - Maven Repo URL: " + mavenURL);
System.out.println(" - Maven Local Dir: " + mavenLocal.getAbsolutePath().replace('\\', '/'));
System.out.println(" - Production Index: " + (productionIndex == null ? "null" : productionIndex.getAbsolutePath().replace('\\', '/')));
System.out.println(" - Production Favicon: " + (productionFavicon == null ? "null" : productionFavicon.getAbsolutePath().replace('\\', '/')));
System.out.println(" - Generate Offline: " + generateOffline);
System.out.println(" - Offline Template: " + (offlineTemplate == null ? "null" : offlineTemplate.getAbsolutePath().replace('\\', '/')));
System.out.println(" - Inject in Offline: " + (injectInOfflineScripts == null ? "[ ]" : "[ " + String.join(", ", injectInOfflineScripts).replace('\\', '/') + " ]"));
System.out.println(" - Minifying: " + minifying);
System.out.println(" - Write Source Map: " + writeSourceMap);
System.out.println(" - Keep Temp Files: " + keepTemporaryFiles);
System.out.println(" - Add Scripts: " + (addScripts == null ? "[ ]" : "[ " + String.join(", ", addScripts).replace('\\', '/') + " ]"));
System.out.println(" - Remove Scripts: " + (removeScripts == null ? "[ ]" : "[ " + String.join(", ", removeScripts).replace('\\', '/') + " ]"));
System.out.println();
if(!yes) {
System.out.println();
LicensePrompt.display();
System.out.println();
}
EaglerBuildTools.repositoryRoot = repositoryFolder;
try {
if(!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) {
throw new CompileFailureException("Could not create output directory!");
}
File[] existingOutput = outputDirectory.listFiles();
if(existingOutput.length > 0) {
if(!yes) {
System.out.print("Output directory has existing files, would you like to delete them? [y/n] ");
String str = (new BufferedReader(new InputStreamReader(System.in))).readLine();
System.out.println();
if(!str.equalsIgnoreCase("y") && !str.equalsIgnoreCase("yes")) {
System.out.println("Build cancelled.");
System.out.println();
System.exit(-1);
return;
}
}
System.out.println("Deleting existing files from the output directory...");
try {
for(int i = 0; i < existingOutput.length; ++i) {
File f = existingOutput[i];
if(f.isDirectory()) {
FileUtils.deleteDirectory(f);
}else {
if(!f.delete()) {
throw new IOException("Could not delete: " + f.getAbsolutePath());
}
}
}
}catch(IOException t) {
throw new CompileFailureException("Could not delete old output directory: " + t.getMessage());
}
}
File mcpDataTMP = new File(temporaryDirectory, "ModCoderPack");
File minecraftSrcTmp = new File(temporaryDirectory, "MinecraftSrc");
if(ffmpeg.length() == 0) {
FFMPEG.foundFFMPEG = "ffmpeg";
}else {
FFMPEG.foundFFMPEG = ffmpeg;
}
if(!mcpDataTMP.isDirectory() && !mcpDataTMP.mkdirs()) {
throw new CompileFailureException("Error: failed to create \"" + mcpDataTMP.getAbsolutePath() + "\"!");
}
if(!InitMCP.initTask(modCoderPack, mcpDataTMP)) {
throw new CompileFailureException("Error: could not initialize MCP from \"" + modCoderPack.getAbsolutePath() + "\"!");
}
if(!minecraftSrcTmp.isDirectory() && !minecraftSrcTmp.mkdirs()) {
throw new CompileFailureException("Error: failed to create \"" + minecraftSrcTmp.getAbsolutePath() + "\"!");
}
if(!DecompileMinecraft.decompileMinecraft(mcpDataTMP, minecraftJar, minecraftSrcTmp, assetsIndex, false)) {
throw new CompileFailureException("Error: could not decompile and patch 1.8.8.jar from \"" + minecraftJar.getAbsolutePath() + "\"!");
}
try {
FileUtils.copyFile(new File(repositoryFolder, "patches/minecraft/output_license.txt"), new File(temporaryDirectory, "MinecraftSrc/LICENSE"));
}catch(IOException ex) {
System.err.println("Error: failed to write LICENSE in temporary directory!");
ex.printStackTrace();
}
System.out.println();
if(mavenURL == null) {
System.out.println("TeaVM JARs will be loaded from: " + mavenLocal.getAbsolutePath());
System.out.println();
try {
TeaVMBinaries.loadFromDirectory(mavenLocal);
}catch(MissingJARsException ex) {
throw new CompileFailureException(ex.getMessage());
}
}else {
System.out.println("TeaVM JARs will be downloaded from repository: " + mavenURL);
System.out.println();
try {
TeaVMBinaries.downloadFromMaven(mavenURL, mavenLocal);
}catch(MissingJARsException ex) {
throw new CompileFailureException(ex.getMessage());
}
System.out.println();
System.out.println("Notice: make sure to delete \"" + mavenLocal.getAbsolutePath() + "\" when the compiler is finished, it will not be deleted automatically");
System.out.println();
}
int compileResultCode;
File compiledResultClasses = new File(temporaryDirectory, "classes");
try {
try {
compileResultCode = JavaC.runJavaC(new File(minecraftSrcTmp, "minecraft_src_javadoc.jar"),
compiledResultClasses, temporaryDirectory, TeaVMBinaries.getTeaVMRuntimeClasspath(),
new File(repositoryFolder, "sources/main/java"), new File(repositoryFolder, "sources/teavm/java"));
}catch(IOException ex) {
throw new CompileFailureException("failed to run javac compiler! " + ex.toString(), ex);
}
System.out.println();
if(compileResultCode == 0) {
System.out.println("Java compiler completed successfully");
}else {
throw new CompileFailureException("failed to run javac compiler! exit code " + compileResultCode + ", check log");
}
}finally {
File extractedSrcTmp = new File(temporaryDirectory, "MinecraftSrc/src_javadoc_tmp");
if(extractedSrcTmp.exists()) {
System.out.println();
System.out.println("Deleting temporary directory: " + extractedSrcTmp.getAbsolutePath());
try {
FileUtils.deleteDirectory(extractedSrcTmp);
}catch(IOException ex) {
System.err.println("Failed to delete temporary directory!");
ex.printStackTrace();
}
}
}
System.out.println();
System.out.println("Preparing arguments for TeaVM...");
if(!TeaVMBinaries.tryLoadTeaVMBridge()) {
System.err.println("Failed to locate TeaVMBridge.jar, you can specify it's path manually by adding the JVM argument \"-Deaglercraft.TeaVMBridge=<path>\"");
throw new CompileFailureException("Failed to locate TeaVMBridge.jar!");
}
Map<String, Object> teavmArgs = new HashMap();
List<String> teavmClassPath = new ArrayList();
teavmClassPath.add(compiledResultClasses.getAbsolutePath());
teavmClassPath.addAll(Arrays.asList(TeaVMBinaries.getTeaVMRuntimeClasspath()));
teavmArgs.put("classPathEntries", teavmClassPath);
teavmArgs.put("entryPointName", "main");
teavmArgs.put("mainClass", "net.lax1dude.eaglercraft.v1_8.internal.teavm.MainClass");
teavmArgs.put("minifying", minifying);
teavmArgs.put("optimizationLevel", "ADVANCED");
teavmArgs.put("targetDirectory", outputDirectory.getAbsolutePath());
teavmArgs.put("generateSourceMaps", writeSourceMap);
teavmArgs.put("targetFileName", "classes.js");
System.out.println();
boolean teavmStatus;
try {
teavmStatus = TeaVMBridge.compileTeaVM(teavmArgs);
}catch(TeaVMClassLoadException ex) {
throw new CompileFailureException("Failed to link TeaVM jar files! Did you select the wrong jar?", ex);
}catch(TeaVMRuntimeException ex) {
throw new CompileFailureException("Failed to run TeaVM! Check log", ex);
}
if(!teavmStatus) {
System.out.println("TeaVM reported problems, check the log");
System.out.println();
System.exit(-1);
return;
}
File epkCompiler = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/CompileEPK.jar");
if(!epkCompiler.exists()) {
throw new CompileFailureException("EPKCompiler JAR file is missing: " + epkCompiler.getAbsolutePath());
}
System.out.println();
System.out.println("Writing index.html...");
System.out.println();
String faviconExt = null;
if(productionFavicon != null) {
faviconExt = productionFavicon.getName();
int i = faviconExt.lastIndexOf('.');
if(i != -1) {
faviconExt = faviconExt.substring(i + 1);
}
}
try(BufferedReader indexReader = new BufferedReader(new FileReaderUTF(productionIndex));
PrintWriter indexWriter = new PrintWriter(new FileWriterUTF(new File(outputDirectory, "index.html")))) {
String line;
while((line = indexReader.readLine()) != null) {
String trim = line.trim();
if(trim.startsWith("<link")) {
if(trim.contains("rel=\"shortcut icon\"")) {
if(faviconExt != null) {
String contentType = "image/png";
switch(faviconExt) {
case "png":
break;
case "jpg":
case "jpeg":
contentType = "image/jpeg";
break;
case "ico":
contentType = "image/x-icon";
break;
case "gif":
contentType = "image/gif";
break;
case "bmp":
contentType = "image/bmp";
break;
case "webp":
contentType = "image/webp";
break;
default:
System.err.println();
System.err.println("WARNING: favicon extension '" + faviconExt + "' is unknown, defaulting to image/png MIME type");
System.err.println();
break;
}
indexWriter.println(line.replace("favicon.png", "favicon." + faviconExt).replace("image/png", contentType));
System.out.println("Setting favicon <link> href to \"favicon." + faviconExt + "\", MIME type \"" + contentType + "\" in index.html");
}else {
System.out.println("Removed favicon <link> from index.html, no favicon configured");
}
continue;
}
}
if(trim.startsWith("<meta")) {
if(trim.contains("property=\"og:image\"")) {
if(faviconExt != null) {
indexWriter.println(line.replace("favicon.png", "favicon." + faviconExt));
System.out.println("Setting og:image <link> href to \"favicon." + faviconExt + "\"");
}else {
System.out.println("Removed og:image <meta> tag in index.html, no favicon configured");
}
continue;
}
}
if(trim.startsWith("<script")) {
int idx = line.indexOf("src=\"");
int idx2 = line.indexOf('"', idx + 5);
String srcSubStr = line.substring(idx + 5, idx2);
if(addScripts != null && srcSubStr.equals("classes.js")) {
for(int i = 0, l = addScripts.size(); i < l; ++i) {
String addSrc = addScripts.get(i);
indexWriter.println(line.replace("classes.js", addSrc));
System.out.println("Added <script> tag with src \"" + addSrc + "\" to index.html");
}
}
if(removeScripts != null && removeScripts.contains(srcSubStr)) {
System.out.println("Removed <script> tag with src \"" + srcSubStr + "\" from index.html");
continue;
}
}
indexWriter.println(line);
}
}
System.out.println();
if(productionFavicon != null) {
FileUtils.copyFile(productionFavicon, new File(outputDirectory, "favicon." + faviconExt));
}
FileUtils.copyFile(new File(repositoryFolder, "sources/setup/workspace_template/javascript/fix-webm-duration.js"), new File(outputDirectory, "fix-webm-duration.js"));
System.out.println();
System.out.println("Running EPKCompiler on assets...");
EPKCompiler.compilerMain(epkCompiler, new String[] {
((new File(minecraftSrcTmp, "minecraft_res_patch.jar")).getAbsolutePath() + System.getProperty("path.separator") +
(new File(repositoryFolder, "sources/resources")).getAbsolutePath()), (new File(outputDirectory, "assets.epk")).getAbsolutePath() });
System.out.println();
System.out.println("Running EPKCompiler on languages.zip...");
EPKCompiler.compilerMain(epkCompiler, new String[] {
(new File(minecraftSrcTmp, "minecraft_languages.zip")).getAbsolutePath(),
(new File(temporaryDirectory, "languages.epk")).getAbsolutePath() });
System.out.println();
System.out.println("Creating languages directory...");
File langDirectory = new File(outputDirectory, "lang");
byte[] copyBuffer = new byte[16384];
int i;
try(ZipInputStream zis = new ZipInputStream(new FileInputStream(new File(minecraftSrcTmp, "minecraft_languages.zip")))) {
ZipEntry etr;
while((etr = zis.getNextEntry()) != null) {
if(!etr.isDirectory()) {
File phile = new File(langDirectory, etr.getName());
File parent = phile.getParentFile();
if(!parent.exists() && !parent.mkdirs()) {
throw new IOException("Could not create directory: " + parent.getAbsolutePath());
}
try(FileOutputStream os = new FileOutputStream(phile)) {
while((i = zis.read(copyBuffer)) != -1) {
os.write(copyBuffer, 0, i);
}
}
}
}
}
System.out.println();
if(generateOffline) {
System.out.println("Running offline download generator...");
System.out.println();
File offlineTemplateArg = offlineTemplate;
if(injectInOfflineScripts != null) {
offlineTemplateArg = new File(temporaryDirectory, "offline_download_template.txt");
try(BufferedReader indexReader = new BufferedReader(new FileReaderUTF(offlineTemplate));
PrintWriter indexWriter = new PrintWriter(new FileWriterUTF(offlineTemplateArg))) {
String line;
while((line = indexReader.readLine()) != null) {
if(line.contains("${classes_js}")) {
for(int j = 0, l = injectInOfflineScripts.size(); j < l; ++j) {
File injectFile = new File(injectInOfflineScripts.get(j));
String injectName = injectFile.getAbsolutePath();
String injectNameName = injectFile.getName();
System.out.println("Adding file to offline download template: " + injectName);
indexWriter.println("// %%%%%%%%% " + injectNameName + " %%%%%%%%%");
indexWriter.println();
try(BufferedReader insertReader = new BufferedReader(new FileReaderUTF(injectFile))) {
String line2;
while((line2 = insertReader.readLine()) != null) {
indexWriter.println(line2);
}
}
indexWriter.println();
char[] percents = new char[20 + injectNameName.length()];
for(int k = 0; k < percents.length; ++k) {
percents[k] = '%';
}
indexWriter.print("// ");
indexWriter.println(percents);
indexWriter.println();
indexWriter.println();
}
System.out.println();
}
indexWriter.println(line);
}
}
}
File offlineDownloadGenerator = new File(repositoryFolder, "sources/setup/workspace_template/desktopRuntime/MakeOfflineDownload.jar");
MakeOfflineDownload.compilerMain(offlineDownloadGenerator, new String[] {
offlineTemplateArg.getAbsolutePath(),
(new File(outputDirectory, "classes.js")).getAbsolutePath() + System.getProperty("path.separator")
+ (new File(outputDirectory, "fix-webm-duration.js")).getAbsolutePath(),
(new File(outputDirectory, "assets.epk")).getAbsolutePath(),
(new File(outputDirectory, "EaglercraftX_1.8_Offline_en_US.html")).getAbsolutePath(),
(new File(outputDirectory, "EaglercraftX_1.8_Offline_International.html")).getAbsolutePath(),
(new File(temporaryDirectory, "languages.epk")).getAbsolutePath()
});
}
System.out.println("Releasing external ClassLoader(s)...");
System.out.println();
TeaVMBridge.free();
EPKCompiler.free();
if(generateOffline) {
MakeOfflineDownload.free();
}
if(!keepTemporaryFiles) {
System.out.println("Cleaning up temporary files...");
try {
FileUtils.deleteDirectory(temporaryDirectory);
}catch(IOException ex) {
System.err.println("Failed to delete temporary directory: " + temporaryDirectory.getAbsolutePath());
ex.printStackTrace();
}
}
System.out.println();
System.out.println("Client build successful! Check the output directory for your files");
}catch(CompileFailureException ex) {
System.out.println();
System.err.println("COMPILATION FAILED: " + ex.getMessage());
System.out.println();
System.exit(-1);
}
}
}

View File

@ -0,0 +1,153 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.WeakHashMap;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import com.github.difflib.patch.Patch;
import com.github.difflib.patch.PatchFailedException;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class ApplyPatchesToZip {
public static final int patchContextLength = 3;
public static void applyPatches(File zipIn, File unpatchedZipIn, File patchesIn, File zipOut, boolean compress, boolean useECR) throws Throwable {
if(!patchesIn.isDirectory()) {
FileUtils.copyFile(zipIn, zipOut);
return;
}
Map<String,byte[]> jarEntriesUnpatched;
if(unpatchedZipIn != null) {
System.out.println("Loading files from '" + unpatchedZipIn.getName() + "'...");
try(FileInputStream is = new FileInputStream(unpatchedZipIn)) {
jarEntriesUnpatched = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesUnpatched = new WeakHashMap();
}
Map<String,byte[]> jarEntriesPatched;
if(zipIn != null) {
System.out.println("Loading files from '" + zipIn.getName() + "'...");
try(FileInputStream is = new FileInputStream(zipIn)) {
jarEntriesPatched = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesPatched = new WeakHashMap();
}
System.out.println("Patching files in '" + zipIn.getName() + "'...");
final Map<String,byte[]> jarEntries = new HashMap();
jarEntries.putAll(jarEntriesUnpatched);
jarEntries.putAll(jarEntriesPatched);
DiffSet diffs = new DiffSet();
int totalLoad = diffs.loadFolder(patchesIn, useECR, useECR ? new DiffSet.SourceProvider() {
@Override
public List<String> getSource(String filename) throws IOException {
byte[] etr = jarEntries.get(filename);
if(etr == null) {
throw new FileNotFoundException("Could not find source for: " + filename);
}
return Lines.linesList(new String(etr, StandardCharsets.UTF_8));
}
} : null);
System.out.println(" loaded " + totalLoad + " patch files from the repo");
System.out.println(" patching files...");
System.out.print(" ");
int cnt = 0;
int crtCnt = 0;
int delCnt = 0;
int repCnt = 0;
int pthCnt = 0;
try(ZipOutputStream jarOut = new ZipOutputStream(new FileOutputStream(zipOut))) {
jarOut.setLevel(compress ? 5 : 0);
jarOut.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
jarOut.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
String nm;
for(Entry<String,byte[]> et : jarEntries.entrySet()) {
nm = et.getKey();
if(!nm.startsWith("META-INF")) {
Object op = diffs.diffs.get(nm);
if(op != null) {
if(op instanceof DiffSet.DeleteFunction) {
++delCnt;
continue;
}else if(op instanceof DiffSet.ReplaceFunction) {
jarOut.putNextEntry(new ZipEntry(nm));
IOUtils.write(((DiffSet.ReplaceFunction)op).file, jarOut);
++repCnt;
}else if(op instanceof Patch<?>) {
jarOut.putNextEntry(new ZipEntry(nm));
List<String> lines = Lines.linesList(new String(et.getValue(), "UTF-8"));
try {
lines = ((Patch<String>)op).applyTo(lines);
}catch(PatchFailedException ptch) {
throw new IOException("Could not patch file \"" + nm + "\"!", ptch);
}
IOUtils.writeLines(lines, null, jarOut, "UTF-8");
++pthCnt;
}else {
// ?
}
++cnt;
if(cnt % 75 == 74) {
System.out.print(".");
}
}else {
if(jarEntriesPatched.containsKey(nm)) {
jarOut.putNextEntry(new ZipEntry(nm));
IOUtils.write(et.getValue(), jarOut);
++cnt;
if(cnt % 75 == 74) {
System.out.print(".");
}
}
}
}
}
for(Entry<String,byte[]> etr : diffs.recreate.entrySet()) {
jarOut.putNextEntry(new ZipEntry(etr.getKey()));
IOUtils.write(etr.getValue(), jarOut);
++crtCnt;
++cnt;
if(cnt % 75 == 74) {
System.out.print(".");
}
}
}
System.out.println();
System.out.println("Patched " + pthCnt + " files");
System.out.println("Restored " + crtCnt + " files");
System.out.println("Replaced " + repCnt + " files");
System.out.println("Deleted " + delCnt + " files");
System.out.println();
}
}

View File

@ -0,0 +1,148 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class DiffSet {
public static class DeleteFunction {
private DeleteFunction() {
}
}
public static class ReplaceFunction {
public final byte[] file;
private ReplaceFunction(byte[] file) {
this.file = file;
}
}
public static final DeleteFunction deleteFunction = new DeleteFunction();
public final Map<String,Object> diffs;
public final Map<String,byte[]> recreate;
public DiffSet() {
diffs = new HashMap();
recreate = new HashMap();
}
private static final Pattern editPattern = Pattern.compile(".*\\.edit(\\.[^\\.\\/\\\\]+)?$");
private static final Pattern replacePattern = Pattern.compile(".*\\.replace(\\.[^\\.\\/\\\\]+)?$");
private static final Pattern deletePattern = Pattern.compile(".*\\.delete(\\.[^\\.\\/\\\\]+)?$");
private static final Pattern recreatePattern = Pattern.compile(".*\\.recreate(\\.[^\\.\\/\\\\]+)?$");
public int loadFolder(File pathIn, boolean useECR, SourceProvider ecrContextProvider) throws IOException {
String baseAbsolutePath = pathIn.getAbsolutePath();
int total = 0;
File del = new File(pathIn, "delete.txt");
if(del.isFile()) {
Collection<String> cl = FileUtils.readLines(del, "UTF-8");
for(String s : cl) {
s = s.trim();
s = s.replace('\\', '/');
if(!s.startsWith("#")) {
if(s.startsWith("/")) {
s = s.substring(1);
}
diffs.put(s, deleteFunction);
}
}
}
Collection<File> fl = FileUtils.listFiles(pathIn, null, true);
Iterator<File> fi = fl.iterator();
while(fi.hasNext()) {
File f = fi.next();
String fName = f.getAbsolutePath().replace(baseAbsolutePath, "").replace('\\', '/');
if(fName.startsWith("/")) {
fName = fName.substring(1);
}
if(editPattern.matcher(fName).matches()) {
try {
String nm = removeExt(fName, "edit");
Patch<String> pth;
if(useECR) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8))) {
pth = EaglerContextRedacted.readContextRestricted(ecrContextProvider.getSource(nm), reader);
}
}else {
List<String> phile = FileUtils.readLines(f, "UTF-8");
pth = UnifiedDiffUtils.parseUnifiedDiff(phile);
}
if(pth == null) {
throw new IOException("Invalid DIFF file!");
}
diffs.put(nm, pth);
++total;
}catch(Throwable ex) {
System.err.println("ERROR: could not read '" + fName + "'!");
}
}else if(replacePattern.matcher(fName).matches()) {
try {
diffs.put(removeExt(fName, "replace"), new ReplaceFunction(FileUtils.readFileToByteArray(f)));
++total;
}catch(Throwable ex) {
System.err.println("ERROR: could not read '" + fName + "'!");
}
}else if(deletePattern.matcher(fName).matches()) {
diffs.put(removeExt(fName, "delete"), deleteFunction);
++total;
}else if(recreatePattern.matcher(fName).matches()) {
try {
String str = removeExt(fName, "recreate");
recreate.put(str, FileUtils.readFileToByteArray(f));
diffs.remove(str);
++total;
}catch(Throwable ex) {
System.err.println("ERROR: could not read '" + fName + "'!");
}
}
}
return total;
}
private static String removeExt(String fn, String ext) {
int end = fn.lastIndexOf("." + ext);
if(end != -1) {
return fn.substring(0, end) + fn.substring(end + ext.length() + 1, fn.length());
}else {
return fn;
}
}
public static interface SourceProvider {
List<String> getSource(String filename) throws IOException;
}
}

View File

@ -0,0 +1,256 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.ChangeDelta;
import com.github.difflib.patch.Chunk;
import com.github.difflib.patch.DeleteDelta;
import com.github.difflib.patch.DeltaType;
import com.github.difflib.patch.InsertDelta;
import com.github.difflib.patch.Patch;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EaglerContextRedacted {
public static void writeContextRedacted(Patch<String> patch, PrintWriter output) {
Date theDate = new Date();
output.println();
output.println("# Eagler Context Redacted Diff");
output.println("# Copyright (c) " + (new SimpleDateFormat("yyyy")).format(theDate) + " lax1dude. All rights reserved.");
output.println();
output.println("# Version: 1.0");
output.println("# Author: lax1dude");
output.println();
List<AbstractDelta<String>> deltas = patch.getDeltas();
delta_itr: for(int i = 0, l = deltas.size(); i < l; ++i) {
AbstractDelta<String> delta = deltas.get(i);
DeltaType type = delta.getType();
String blockType;
String blockPrefix;
switch(type) {
case CHANGE:
blockType = "> CHANGE";
blockPrefix = "~ ";
break;
case DELETE:
blockType = "> DELETE";
blockPrefix = "- ";
break;
case EQUAL:
continue delta_itr;
case INSERT:
blockType = "> INSERT";
blockPrefix = "+ ";
break;
default:
throw new IllegalArgumentException("Invalid type " + type + " for delta " + i);
}
Chunk<String> source = delta.getSource();
int sourcePos = source.getPosition();
int sourceLen = source.getLines().size();
Chunk<String> target = delta.getTarget();
int targetPos = target.getPosition();
List<String> linesToWrite = target.getLines();
int targetLen = linesToWrite.size();
output.println(blockType + " " + targetPos + (targetLen > 0 ? " : " + (targetPos + targetLen) : "") + " @ "
+ sourcePos + (sourceLen > 0 ? " : " + (sourcePos + sourceLen) : ""));
output.println();
if(targetLen > 0) {
for(int j = 0, ll = linesToWrite.size(); j < ll; ++j) {
output.println(blockPrefix + linesToWrite.get(j));
}
output.println();
}
}
output.println("> EOF");
}
public static Patch<String> readContextRestricted(List<String> context, BufferedReader reader) throws IOException {
Patch<String> newPatch = new Patch();
DeltaType currentDeltaType = null;
int sourceStart = 0;
int sourceLen = 0;
int targetStart = 0;
int targetLen = 0;
List<String> targetLines = null;
String line;
readLinesLoop: while((line = reader.readLine()) != null) {
if(line.length() < 2) {
continue;
}
if(line.charAt(1) != ' ') {
throw new IOException("Unknown line type: " + line.substring(0, 2));
}
char lineType = line.charAt(0);
String value = line.substring(2);
switch(lineType) {
case '#':
int idx = value.indexOf(':');
if(idx > 0) {
String k = value.substring(0, idx).trim().toLowerCase();
if(k.equals("version")) {
String v = value.substring(idx + 1).trim();
if(!v.equals("1.0")) {
throw new IOException("Unsupported format version: " + v);
}
}
}
break;
case '>':
String[] split = value.trim().split("[\\s]+");
if(split.length == 1 && split[0].equals("EOF")) {
break readLinesLoop;
}
if(split.length < 4 ||
!((split[2].equals("@") && (split.length == 4 || (split.length == 6 && split[4].equals(":")))) ||
(split[2].equals(":") && ((split.length == 6 && split[4].equals("@")) || (split.length == 8 && split[4].equals("@") && split[6].equals(":")))))) {
throw new IOException("Invalid block: [ " + String.join(" ", split) + " ]");
}
if(currentDeltaType != null) {
newPatch.addDelta(makeDelta(currentDeltaType, sourceStart, sourceLen, targetStart, targetLen, context, targetLines));
}
switch(split[0]) {
case "CHANGE":
currentDeltaType = DeltaType.CHANGE;
break;
case "DELETE":
currentDeltaType = DeltaType.DELETE;
break;
case "INSERT":
currentDeltaType = DeltaType.INSERT;
break;
default:
throw new IOException("Unknown line block: " + split[0]);
}
targetLines = null;
targetStart = parseInt(split[1]);
if(split[2].equals(":")) {
targetLen = parseInt(split[3]) - targetStart;
sourceStart = parseInt(split[5]);
if(split.length == 8) {
sourceLen = parseInt(split[7]) - sourceStart;
}else {
sourceLen = 0;
}
}else {
targetLen = 0;
sourceStart = parseInt(split[3]);
if(split.length == 6) {
sourceLen = parseInt(split[5]) - sourceStart;
}else {
sourceLen = 0;
}
}
break;
case '~':
if(currentDeltaType != DeltaType.CHANGE) {
throw new IOException("Read an unexpected CHANGE line in a " + currentDeltaType + " block: " + line);
}else {
if(targetLines == null) targetLines = new ArrayList();
targetLines.add(value);
}
break;
case '-':
if(currentDeltaType != DeltaType.DELETE) {
throw new IOException("Read an unexpected DELETE line in a " + currentDeltaType + " block: " + line);
}else {
if(targetLines == null) targetLines = new ArrayList();
targetLines.add(value);
}
break;
case '+':
if(currentDeltaType != DeltaType.INSERT) {
throw new IOException("Read an unexpected INSERT line in a " + currentDeltaType + " block: " + line);
}else {
if(targetLines == null) targetLines = new ArrayList();
targetLines.add(value);
}
break;
default:
throw new IOException("Unknown line type: " + lineType);
}
}
if(currentDeltaType != null) {
newPatch.addDelta(makeDelta(currentDeltaType, sourceStart, sourceLen, targetStart, targetLen, context, targetLines));
}
return newPatch;
}
private static int parseInt(String str) throws IOException {
try {
return Integer.parseInt(str);
}catch(NumberFormatException ex) {
throw new IOException("Value is not a valid integer: \"" + str + "\"");
}
}
private static AbstractDelta<String> makeDelta(DeltaType deltaType, int sourceStart, int sourceLen,
int targetStart, int targetLen, List<String> context, List<String> targetLines) throws IOException {
List<String> sourceLines = new ArrayList(sourceLen);
for(int i = 0; i < sourceLen; ++i) {
sourceLines.add(context.get(sourceStart + i));
}
if(targetLines == null) {
targetLines = new ArrayList(0);
}
if(targetLen != targetLines.size()) {
throw new IOException("" + deltaType + " block at sourceStart " + sourceStart + " is " + targetLen
+ " lines long but only " + targetLines.size() + " lines were read!");
}
switch(deltaType) {
case CHANGE:
return new ChangeDelta(new Chunk(sourceStart, sourceLines), new Chunk(targetStart, targetLines));
case DELETE:
return new DeleteDelta(new Chunk(sourceStart, sourceLines), new Chunk(targetStart, targetLines));
case INSERT:
return new InsertDelta(new Chunk(sourceStart, sourceLines), new Chunk(targetStart, targetLines));
default:
throw new IllegalArgumentException("Invalid delta type: " + deltaType);
}
}
}

View File

@ -0,0 +1,47 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.IOUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class JARMemoryCache {
public static Map<String,byte[]> loadJAR(InputStream is) throws IOException {
Map<String,byte[]> ret = new HashMap();
ZipInputStream isz = new ZipInputStream(is);
ZipEntry et;
while((et = isz.getNextEntry()) != null) {
if(!et.isDirectory()) {
String n = et.getName();
if(n.startsWith("/")) {
n = n.substring(1);
}
if(!n.startsWith("META-INF")) {
byte[] data = IOUtils.toByteArray(isz);
ret.put(n, data);
}
}
}
return ret;
}
}

View File

@ -0,0 +1,32 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class Lines {
public static final Pattern splitPattern = Pattern.compile("(\\r\\n|\\n|\\r)");
public static String[] linesArray(String input) {
return splitPattern.split(input);
}
public static List<String> linesList(String input) {
return Arrays.asList(splitPattern.split(input));
}
}

View File

@ -0,0 +1,529 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import com.github.difflib.DiffUtils;
import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InsertJavaDoc;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.SetupWorkspace;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class MergePullRequest {
public static boolean mergeTask() {
try {
return mergeTask0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'merge'!");
t.printStackTrace();
return false;
}
}
private static boolean mergeTask0() throws Throwable {
File pullRequestDir = new File("pullrequest");
if(!pullRequestDir.isDirectory() || FileUtils.isEmptyDirectory(pullRequestDir)) {
System.err.println("ERROR: the 'pullrequest' directory does not exist or is empty, aborting merge because there's nothing to merge");
return false;
}
if((new File(pullRequestDir, "merged.txt")).exists()) {
System.err.println("ERROR: the 'pullrequest' directory has already been merged, aborting merge because there's nothing to merge");
System.err.println("To override, delete 'merged.txt' from the folder.");
return false;
}
System.out.println();
System.out.println("Warning: running 'merge' is a command only intended to be used");
System.out.println("by the repository's owner, it will perminantly incorporate all");
System.out.println("changes in the 'pullrequest' directory into this repository's");
System.out.println("patch file directory!");
System.out.println();
System.out.println("Doing so will make it impossible to reliably create any future");
System.out.println("pull requests back to this project's main repository, unless the");
System.out.println("main repository has merged the same pull request into it's patch");
System.out.println("file directory too.");
System.out.println();
System.out.println("Back up the current state of the patch file directory in a local");
System.out.println("commit or branch to allow you to undo any unintentional changes");
System.out.println("made to the directory as a result of running this command.");
System.out.println();
System.out.print("Do you really want to do this? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("OKAY THANK GOD, crisis averted!");
System.out.println();
System.out.println("Thank the author of this tool kindly for providing this check.");
return true;
}
System.out.println();
System.out.println("Warning: close all programs that may have files or folders open");
System.out.println("in the repository or the merge could fail catastrophically");
System.out.println();
System.out.println("This folder: " + (new File(".")).getAbsolutePath());
System.out.println();
System.out.println("Check for any file explorer windows displaying the contents of a");
System.out.println("file or folder in this directory.");
System.out.println();
System.out.println("Close any programs with files open someplace in this folder.");
System.out.println();
System.out.println("If merging fails, revert all changes in this directory with git");
System.out.println("or a backup, re-run 'init', then run 'pullrequest' and 'merge'");
System.out.println();
System.out.print("Did you close everything? [Y/n]: ");
ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("OKAY THANK GOD, crisis averted!");
System.out.println();
System.out.println("Thank the author of this tool kindly for providing this check.");
return true;
}
System.out.println();
File temporaryDirectory = EaglerBuildToolsConfig.getTemporaryDirectory();
System.out.println();
File pullRequestToSrc = new File(pullRequestDir, "source");
File pullRequestToRes = new File(pullRequestDir, "resources");
boolean prSrcExist = pullRequestToSrc.isDirectory() && !FileUtils.isEmptyDirectory(pullRequestToSrc);
boolean prResExist = pullRequestToRes.isDirectory() && !FileUtils.isEmptyDirectory(pullRequestToRes);
if(!prSrcExist && !prResExist) {
System.err.println("ERROR: the 'pullrequest' directory does not exist or is empty, aborting merge because there's nothing to merge");
return false;
}
if(prSrcExist) {
File tmpOriginalUnpatched = new File(temporaryDirectory, "MinecraftSrc/minecraft_src.jar");
if(!tmpOriginalUnpatched.isFile()) {
System.err.println("ERROR: file '" + tmpOriginalUnpatched.getName() + "' was not found!");
System.err.println("Run the 'init' task again to re-generate it");
return false;
}
File tmpOriginal = new File(temporaryDirectory, "MinecraftSrc/minecraft_src_patch.jar");
if(!tmpOriginal.isFile()) {
System.err.println("ERROR: file '" + tmpOriginal.getName() + "' was not found!");
System.err.println("Run the 'init' task again to re-generate it");
return false;
}
File tmpMerged = new File(temporaryDirectory, "MinecraftSrc/minecraft_src_merge.jar");
File tmpMergedDiffs = new File(temporaryDirectory, "MinecraftSrc/minecraft_src_merge_diffs.zip");
System.out.println("Applying pull request to '" + tmpOriginal.getName() + "'...");
System.out.println();
ApplyPatchesToZip.applyPatches(tmpOriginal, tmpOriginalUnpatched, pullRequestToSrc, tmpMerged, true, false);
try {
createMergeDiffs(tmpMerged, tmpOriginalUnpatched, tmpMergedDiffs);
}catch(Throwable t) {
tmpMerged.delete();
throw t;
}
System.out.println();
File patchOut = new File("./patches/minecraft");
File patchTmpOut = new File("./patches.bak/minecraft");
if(patchOut.exists()) {
System.out.println("Backing up '" + patchOut.getAbsolutePath() + "'...");
try {
FileUtils.deleteDirectory(patchTmpOut);
FileUtils.moveDirectory(patchOut, patchTmpOut);
}catch(Throwable t) {
tmpMerged.delete();
throw t;
}
}
FileUtils.copyFile(new File(patchTmpOut, "output_license.txt"), new File(patchOut, "output_license.txt"));
System.out.println("Extracting '" + tmpMergedDiffs + "' to 'patches/minecraft'...");
int cnt = SetupWorkspace.extractJarTo(tmpMergedDiffs, patchOut);
if(!tmpMergedDiffs.delete()) {
System.err.println("ERROR: could not delete '" + tmpMergedDiffs.getName() + "'!");
}
System.out.println("Wrote " + cnt + " files.");
System.out.println("Copying '" + tmpMerged.getName() + "' to '" + tmpOriginal.getName() + "'...");
if((tmpOriginal.exists() && !tmpOriginal.delete()) || !tmpMerged.renameTo(tmpOriginal)) {
System.err.println("ERROR: could not copy '" + tmpMerged.getName() + "' to '" + tmpOriginal.getName() + "'!");
System.err.println("Run the 'init' task again before proceeding");
tmpOriginal.delete();
}else {
File javadocOut = new File(temporaryDirectory, "MinecraftSrc/minecraft_src_javadoc.jar");
CSVMappings comments = new CSVMappings();
if(!InsertJavaDoc.processSource(tmpOriginal, javadocOut, new File(temporaryDirectory, "ModCoderPack"), comments)) {
System.err.println();
System.err.println("ERROR: Could not create javadoc!");
return false;
}
}
if(tmpMerged.exists()) {
tmpMerged.delete();
}
System.out.println("Deleting backup folder...");
try {
FileUtils.deleteDirectory(patchTmpOut);
}catch(Throwable t) {
System.err.println("ERROR: could not delete 'patches.bak/minecraft'!");
System.err.println(t.toString());
}
System.out.println();
}
if(prResExist) {
File tmpOriginalUnpatched = new File(temporaryDirectory, "MinecraftSrc/minecraft_res.jar");
if(!tmpOriginalUnpatched.isFile()) {
System.err.println("ERROR: file '" + tmpOriginalUnpatched.getName() + "' was not found!");
System.err.println("Run the 'init' task again to re-generate it");
return false;
}
File tmpOriginal = new File(temporaryDirectory, "MinecraftSrc/minecraft_res_patch.jar");
if(!tmpOriginal.isFile()) {
System.err.println("ERROR: file '" + tmpOriginal.getName() + "' was not found!");
System.err.println("Run the 'init' task again to re-generate it");
return false;
}
File tmpMerged = new File(temporaryDirectory, "MinecraftSrc/minecraft_res_merge.jar");
File tmpMergedDiffs = new File(temporaryDirectory, "MinecraftSrc/minecraft_res_merge_diffs.zip");
System.out.println("Applying pull request to '" + tmpOriginal.getName() + "'...");
System.out.println();
ApplyPatchesToZip.applyPatches(tmpOriginal, tmpOriginalUnpatched, pullRequestToRes, tmpMerged, true, false);
try {
createMergeDiffs(tmpMerged, tmpOriginalUnpatched, tmpMergedDiffs);
}catch(Throwable t) {
tmpMerged.delete();
throw t;
}
System.out.println();
File patchOut = new File("./patches/resources");
File patchTmpOut = new File("./patches.bak/resources");
if(patchOut.exists()) {
System.out.println("Backing up '" + patchOut.getAbsolutePath() + "'...");
try {
FileUtils.deleteDirectory(patchTmpOut);
FileUtils.moveDirectory(patchOut, patchTmpOut);
}catch(Throwable t) {
tmpMerged.delete();
throw t;
}
}
System.out.println("Extracting '" + tmpMergedDiffs + "' to 'patches/resources'...");
int cnt = SetupWorkspace.extractJarTo(tmpMergedDiffs, patchOut);
if(!tmpMergedDiffs.delete()) {
System.err.println("ERROR: could not delete '" + tmpMergedDiffs.getName() + "'!");
}
System.out.println("Wrote " + cnt + " files.");
System.out.println("Copying '" + tmpMerged.getName() + "' to '" + tmpOriginal.getName() + "'...");
if((tmpOriginal.exists() && !tmpOriginal.delete()) || !tmpMerged.renameTo(tmpOriginal)) {
System.err.println("ERROR: could not copy '" + tmpMerged.getName() + "' to '" + tmpOriginal.getName() + "'!");
System.err.println("Run the 'init' task again before proceeding");
tmpOriginal.delete();
}
if(tmpMerged.exists()) {
tmpMerged.delete();
}
System.out.println("Deleting backup folder...");
try {
FileUtils.deleteDirectory(patchTmpOut);
}catch(Throwable t) {
System.err.println("ERROR: could not delete 'patches.bak/resources'!");
System.err.println(t.getMessage());
}
System.out.println();
}
(new File("./patches.bak")).delete();
System.out.println("Successfully merged pullrequest directory!");
try {
SimpleDateFormat fmt1 = new SimpleDateFormat("MM-dd-yy");
SimpleDateFormat fmt2 = new SimpleDateFormat("kk:mm:ss");
Date dt = new Date();
FileUtils.writeStringToFile(new File(pullRequestDir, "merged.txt"), "This pullrequest was merged on " +
fmt1.format(new Date()) + " at " + fmt2.format(dt) + ".", "UTF-8");
}catch(IOException ex) {
System.err.println("ERROR: could not write 'merged.txt' in pullrequest directory!");
System.err.println("Creating a file called 'merged.txt' is important to tell buildtools that the");
System.err.println("existing pullrequest has already been merged! Do not try to merge it again!");
}
System.out.println("Backing up to 'pullrequest_merged_backup'...");
String pth = pullRequestDir.getAbsolutePath();
if(pth.endsWith("/") || pth.endsWith("\\")) {
pth = pth.substring(0, pth.length() - 1);
}
File m0 = new File(pth + "_merged_backup");
if(m0.exists() && !FileUtils.deleteQuietly(m0)) {
System.err.println("Could not delete old backup!");
m0 = new File(pth + "_merged_backup1");
if(m0.exists() && !FileUtils.deleteQuietly(m0)) {
System.err.println("Could not delete 2nd old backup!");
return true;
}
}
try {
FileUtils.moveDirectory(pullRequestDir, m0);
}catch(IOException ex) {
System.err.println("Could not create backup!");
}
return true;
}
private static void createMergeDiffs(File tmpMerged, File tmpOriginalUnpatched, File tmpMergedDiffs) throws Throwable {
System.out.println("Creating patches from '" + tmpMerged.getName() + "'...");
System.out.println("Loading files from '" + tmpOriginalUnpatched.getName() + "'...");
Map<String, byte[]> memoryCacheUnpatched;
try(InputStream is = new FileInputStream(tmpOriginalUnpatched)) {
memoryCacheUnpatched = JARMemoryCache.loadJAR(is);
}
if(memoryCacheUnpatched == null) {
throw new IOException("Failed to load JAR into memory: '" + tmpOriginalUnpatched.getName());
}
System.out.println("Loading files from '" + tmpMerged.getName() + "'...");
Map<String, byte[]> memoryCacheMerged;
try(InputStream is = new FileInputStream(tmpMerged)) {
memoryCacheMerged = JARMemoryCache.loadJAR(is);
}
if(memoryCacheMerged == null) {
throw new IOException("Failed to load JAR into memory: '" + tmpMerged.getName());
}
Set<String> deleteList = new HashSet();
deleteList.addAll(memoryCacheUnpatched.keySet());
System.out.println("Generating patch files..");
System.out.println("(Writing to: " + tmpMergedDiffs.getName() + ")");
System.out.println("(this may take a while)");
System.out.print(" ");
int cnt = 0;
try(ZipOutputStream mgd = new ZipOutputStream(new FileOutputStream(tmpMergedDiffs))) {
mgd.setLevel(5);
for(Entry<String,byte[]> met : memoryCacheMerged.entrySet()) {
String n = met.getKey();
byte[] orig = memoryCacheUnpatched.get(n);
if(orig == null) {
System.err.println("Error: tried to patch file '" + n + "' that doesn't exist in the minecraft source");
continue;
}
deleteList.remove(n);
if(writeDiff(orig, met.getValue(), n, mgd)) {
++cnt;
if(cnt % 75 == 74) {
System.out.print(".");
}
}
}
System.out.println();
System.out.println("Wrote " + cnt + " patch files.");
mgd.putNextEntry(new ZipEntry("delete.txt"));
PrintWriter delWriter = new PrintWriter(mgd);
delWriter.println("# " + deleteList.size() + " files to delete:");
for(String s : deleteList) {
delWriter.println(s);
}
delWriter.flush();
System.out.println("Wrote " + deleteList.size() + " deletes.");
}
}
private static boolean writeDiff(byte[] old, byte[] _new, String outName, ZipOutputStream output) throws IOException {
if(Arrays.equals(old, _new)) {
return false;
}
String oldStr = toStringIfValid(old);
String newStr = oldStr == null ? null : toStringIfValid(_new);
if(oldStr == null || newStr == null) {
output.putNextEntry(new ZipEntry(makeName(outName, "replace")));
IOUtils.write(_new, output);
return true;
}else {
List<String> oldLines = Lines.linesList(oldStr);
List<String> newLines = Lines.linesList(newStr);
Patch<String> deltas = DiffUtils.diff(oldLines, newLines);
// List<String> diffFile = UnifiedDiffUtils.generateUnifiedDiff(outName, outName, oldLines, deltas, ApplyPatchesToZip.patchContextLength);
//
// if(diffFile.size() == 0) {
// return false;
// }
//
// output.putNextEntry(new ZipEntry(makeName(outName, "edit")));
// PrintWriter foutStream = new PrintWriter(output);
// for(int i = 0, l = diffFile.size(); i < l; ++i) {
// foutStream.println(diffFile.get(i));
// }
// foutStream.flush();
output.putNextEntry(new ZipEntry(makeName(outName, "edit")));
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"));
EaglerContextRedacted.writeContextRedacted(deltas, writer);
writer.flush();
return true;
}
}
private static String makeName(String input, String type) {
int lastSlash = input.lastIndexOf('/');
int lastDot = input.lastIndexOf('.');
if(lastDot > lastSlash + 1) {
return input.substring(0, lastDot) + "." + type + input.substring(lastDot);
}else {
return input + "." + type;
}
}
private static final CharsetDecoder utf8Decoder = StandardCharsets.UTF_8.newDecoder();
private static String toStringIfValid(byte[] in) {
ByteBuffer inn = ByteBuffer.wrap(in);
CharBuffer cb;
try {
cb = utf8Decoder.decode(inn);
}catch(Throwable t) {
return null;
}
return cb.toString();
}
public static boolean mergeDirect() {
try {
return mergeDirect0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'merge_direct'!");
t.printStackTrace();
return false;
}
}
private static boolean mergeDirect0() throws Throwable {
if(!PullRequestTask.pullRequest()) {
System.err.println();
System.err.println("Error: could not create merge_direct pull request!");
return false;
}
try {
if(!mergeTask0()) {
System.err.println();
System.err.println("Exception encountered while running task 'merge_direct'!");
return false;
}
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'merge_direct'!");
t.printStackTrace();
return false;
}
return true;
}
}

View File

@ -0,0 +1,426 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.diff;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.zip.CRC32;
import org.apache.commons.io.FileUtils;
import com.github.difflib.DiffUtils;
import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.formatter.EclipseFormatter;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.InsertJavaDoc;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileWriterUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class PullRequestTask {
public static boolean pullRequest() {
try {
return pullRequest0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'pullrequest'!");
t.printStackTrace();
return false;
}
}
private static boolean pullRequest0() throws Throwable {
File originalUnpatchedSourceMainJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_src.jar");
File originalSourceMainJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_src_patch.jar");
File minecraftJavadocTmp = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_src_javadoc.jar");
File originalSourceMain = new File(EaglerBuildTools.repositoryRoot, "sources/main/java");
File originalSourceTeaVM = new File(EaglerBuildTools.repositoryRoot, "sources/teavm/java");
File originalSourceLWJGL = new File(EaglerBuildTools.repositoryRoot, "sources/lwjgl/java");
File originalUnpatchedSourceResourcesJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_res.jar");
File originalSourceResourcesJar = new File(EaglerBuildToolsConfig.getTemporaryDirectory(), "MinecraftSrc/minecraft_res_patch.jar");
File originalSourceResources = new File(EaglerBuildTools.repositoryRoot, "sources/resources");
File diffFromMain = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/main/java");
File diffFromTeaVM = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/teavm/java");
File diffFromLWJGL = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "src/lwjgl/java");
File diffFromResources = new File(EaglerBuildToolsConfig.getWorkspaceDirectory(), "desktopRuntime/resources");
File pullRequestTo = new File(EaglerBuildTools.repositoryRoot, "pullrequest");
boolean prExist = pullRequestTo.exists();
if(prExist && !(pullRequestTo.isDirectory() && pullRequestTo.list().length == 0)) {
System.out.println();
System.out.print("Warning: The 'pullrequest' folder already exists in your repository. Overwrite? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("The pull request was cancelled.");
return true;
}else {
try {
FileUtils.deleteDirectory(pullRequestTo);
prExist = false;
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + pullRequestTo.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
}
}
if(!prExist && !pullRequestTo.mkdirs()) {
System.err.println("ERROR: Could not create folder \"" + pullRequestTo.getAbsolutePath() + "\"!");
}
File pullRequestToMain = new File(pullRequestTo, "source");
File pullRequestToResources = new File(pullRequestTo, "resources");
boolean flag = false;
int i = copyAllModified(diffFromTeaVM, originalSourceTeaVM);
if(i > 0) {
flag = true;
}
System.out.println("Found " + i + " changed files in /src/teavm/java/");
i = copyAllModified(diffFromLWJGL, originalSourceLWJGL);
if(i > 0) {
flag = true;
}
System.out.println("Found " + i + " changed files in /src/lwjgl/java/");
i = createDiffFiles(originalSourceMain, minecraftJavadocTmp, originalUnpatchedSourceMainJar,
originalSourceMainJar, diffFromMain, pullRequestToMain, true);
if(i > 0) {
flag = true;
}
System.out.println("Found " + i + " changed files in /src/main/java/");
i = createDiffFiles(originalSourceResources, originalSourceResourcesJar, originalUnpatchedSourceResourcesJar,
null, diffFromResources, pullRequestToResources, false);
if(i > 0) {
flag = true;
}
System.out.println("Found " + i + " changed files in /desktopRuntime/resources/");
if(!flag) {
System.out.println("ERROR: No modified files were found!");
if(pullRequestTo.exists()) {
pullRequestTo.delete();
}
}
return true;
}
private static int createDiffFiles(File folderOriginal, File jarOriginal, File jarOriginalUnpatched, File originalJarNoJavadoc,
File folderEdited, File folderOut, boolean isJava) throws Throwable {
if(!folderEdited.isDirectory()) {
return 0;
}
boolean createdFolderOut = folderOut.isDirectory();
int cnt = 0;
Collection<File> workspaceFiles = FileUtils.listFiles(folderEdited, null, true);
Map<String,byte[]> jarEntriesUnpatched;
if(jarOriginalUnpatched != null) {
System.out.println("Loading files from '" + jarOriginalUnpatched.getName() + "'...");
try(FileInputStream is = new FileInputStream(jarOriginalUnpatched)) {
jarEntriesUnpatched = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesUnpatched = new WeakHashMap();
}
Map<String,byte[]> jarEntriesPatched;
if(jarOriginal != null) {
System.out.println("Loading files from '" + jarOriginal.getName() + "'...");
try(FileInputStream is = new FileInputStream(jarOriginal)) {
jarEntriesPatched = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesPatched = new WeakHashMap();
}
Map<String,byte[]> jarEntries = new HashMap();
jarEntries.putAll(jarEntriesUnpatched);
jarEntries.putAll(jarEntriesPatched);
Map<String,byte[]> jarEntriesNoJavadoc;
if(originalJarNoJavadoc != null) {
System.out.println("Loading files from '" + originalJarNoJavadoc.getName() + "'...");
try(FileInputStream is = new FileInputStream(originalJarNoJavadoc)) {
jarEntriesNoJavadoc = JARMemoryCache.loadJAR(is);
}
}else {
jarEntriesNoJavadoc = new WeakHashMap();
}
System.out.println("Comparing...");
System.out.println("(this may take a while)");
String editedPrefix = folderEdited.getAbsolutePath();
Set<String> filesReplaced = new HashSet();
for(File wf : workspaceFiles) {
String newPath = wf.getAbsolutePath().replace(editedPrefix, "");
if(newPath.indexOf('\\') != -1) {
newPath = newPath.replace('\\', '/');
}
if(newPath.startsWith("/")) {
newPath = newPath.substring(1);
}
File orig = new File(folderOriginal, newPath);
byte[] jarData = null;
boolean replacedFileExists = orig.exists();
if(replacedFileExists) {
filesReplaced.add(newPath);
if(copyFileIfChanged(wf, orig)) {
++cnt;
}
}else if((jarData = jarEntries.get(newPath)) != null) {
filesReplaced.add(newPath);
byte [] o = jarData;
byte [] n = FileUtils.readFileToByteArray(wf);
boolean changed = false;
if(o.length != n.length) {
if(!createdFolderOut) {
if(!folderOut.mkdirs()) {
throw new IOException("Could not create folder: \"" + folderOut.getAbsolutePath() + "\"!");
}
createdFolderOut = true;
}
String noJavaDocString = null;
byte[] noJavaDoc = jarEntriesNoJavadoc.get(newPath);
if(noJavaDoc != null) {
noJavaDocString = new String(noJavaDoc, StandardCharsets.UTF_8);
}
if(writeDiff(o, n, folderOut, newPath, isJava, noJavaDocString)) {
changed = true;
++cnt;
}
}else {
for(int i = 0; i < o.length; ++i) {
if(o[i] != n[i]) {
if(!createdFolderOut) {
if(!folderOut.mkdirs()) {
throw new IOException("Could not create folder: \"" + folderOut.getAbsolutePath() + "\"!");
}
createdFolderOut = true;
}
String noJavaDocString = null;
byte[] noJavaDoc = jarEntriesNoJavadoc.get(newPath);
if(noJavaDoc != null) {
noJavaDocString = new String(noJavaDoc, StandardCharsets.UTF_8);
}
if(writeDiff(o, n, folderOut, newPath, isJava, noJavaDocString)) {
changed = true;
++cnt;
}
break;
}
}
}
if(!changed && !jarEntriesPatched.containsKey(newPath)) {
FileUtils.writeByteArrayToFile(new File(folderOut, makeName(newPath, "recreate")), jarData);
++cnt;
}
}else {
filesReplaced.add(newPath);
FileUtils.copyFile(wf, orig);
++cnt;
}
}
if(jarEntriesPatched.size() > 0) {
for(Entry<String,byte[]> etr : jarEntriesPatched.entrySet()) {
if(filesReplaced.contains(etr.getKey())) {
continue;
}
if(!(new File(folderEdited, etr.getKey())).exists()) {
if(!createdFolderOut) {
if(!folderOut.mkdirs()) {
throw new IOException("Could not create folder: \"" + folderOut.getAbsolutePath() + "\"!");
}
createdFolderOut = true;
}
FileUtils.writeStringToFile(new File(folderOut, makeName(etr.getKey(), "delete")),
"#hash: " + getCRC32(etr.getValue()), "UTF-8");
++cnt;
}
}
}
return cnt;
}
private static boolean writeDiff(byte[] old, byte[] _new, File outDir, String outName, boolean isJava, String javaNotJavadoc) throws IOException {
String oldStr = toStringIfValid(old);
String newStr = oldStr == null ? null : toStringIfValid(_new);
if(oldStr == null || newStr == null) {
FileUtils.writeByteArrayToFile(new File(outDir, makeName(outName, "replace")), _new);
}else {
if(javaNotJavadoc != null) {
oldStr = javaNotJavadoc;
}
//oldStr = stripJavadocAndFormat(oldStr);
newStr = stripJavadocAndFormat(newStr);
List<String> oldLines = Lines.linesList(oldStr);
List<String> newLines = Lines.linesList(newStr);
Patch<String> deltas = DiffUtils.diff(oldLines, newLines);
List<String> diffFile = UnifiedDiffUtils.generateUnifiedDiff(outName, outName, oldLines, deltas, ApplyPatchesToZip.patchContextLength);
if(diffFile.size() == 0) {
return false;
}
File fout = new File(outDir, makeName(outName, "edit"));
File p = fout.getParentFile();
if(!p.isDirectory()) {
if(!p.mkdirs()) {
throw new IOException("Failed to create directory \"" + p.getAbsolutePath() + "\"!");
}
}
try(PrintWriter foutStream = new PrintWriter(new FileWriterUTF(fout))) {
for(int i = 0, l = diffFile.size(); i < l; ++i) {
foutStream.println(diffFile.get(i));
}
}
}
return true;
}
private static String stripJavadocAndFormat(String input) {
input = InsertJavaDoc.stripDocForDiff(input);
input = EclipseFormatter.processSource(input, System.lineSeparator());
return input;
}
private static int copyAllModified(File inDir, File outDir) throws IOException {
if(!inDir.isDirectory()) {
return 0;
}
int cnt = 0;
Collection<File> workspaceFiles = FileUtils.listFiles(inDir, null, true);
String editedPrefix = inDir.getAbsolutePath();
for(File wf : workspaceFiles) {
String newPath = wf.getAbsolutePath().replace(editedPrefix, "");
if(newPath.indexOf('\\') != -1) {
newPath = newPath.replace('\\', '/');
}
if(newPath.startsWith("/")) {
newPath = newPath.substring(1);
}
File orig = new File(outDir, newPath);
if(copyFileIfChanged(wf, orig)) {
++cnt;
}
}
return cnt;
}
private static String makeName(String input, String type) {
int lastSlash = input.lastIndexOf('/');
int lastDot = input.lastIndexOf('.');
if(lastDot > lastSlash + 1) {
return input.substring(0, lastDot) + "." + type + input.substring(lastDot);
}else {
return input + "." + type;
}
}
private static final CharsetDecoder utf8Decoder = StandardCharsets.UTF_8.newDecoder();
private static String toStringIfValid(byte[] in) {
ByteBuffer inn = ByteBuffer.wrap(in);
CharBuffer cb;
try {
cb = utf8Decoder.decode(inn);
}catch(Throwable t) {
return null;
}
return cb.toString();
}
private static final String hex = "0123456789ABCDEF";
private static String hex32(long in) {
char[] ret = new char[8];
for(int i = 7; i >= 0; --i) {
ret[i] = hex.charAt((int)((in >> (i << 2)) & 0xF));
}
return new String(ret);
}
private static String getCRC32(File in) throws IOException {
CRC32 crc = new CRC32();
crc.update(FileUtils.readFileToByteArray(in));
return hex32(crc.getValue());
}
private static String getCRC32(byte[] in) {
CRC32 crc = new CRC32();
crc.update(in);
return hex32(crc.getValue());
}
private static boolean checkCRC32(File in1, File in2) throws IOException {
CRC32 crc = new CRC32();
crc.update(FileUtils.readFileToByteArray(in1));
long v1 = crc.getValue();
crc.reset();
crc.update(FileUtils.readFileToByteArray(in2));
return v1 != crc.getValue();
}
private static boolean copyFileIfChanged(File in1, File in2) throws IOException {
if(!in2.exists()) {
FileUtils.copyFile(in1, in2);
return true;
}
if(in1.lastModified() == in2.lastModified()) {
return false;
}
CRC32 crc = new CRC32();
byte[] f1 = FileUtils.readFileToByteArray(in1);
crc.update(f1);
long v1 = crc.getValue();
crc.reset();
byte[] f2 = FileUtils.readFileToByteArray(in2);
crc.update(f2);
if(v1 != crc.getValue()) {
//System.out.println("changed: " + in1.getAbsolutePath());
FileUtils.writeByteArrayToFile(in2, f1);
return true;
}else {
return false;
}
}
}

View File

@ -0,0 +1,42 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.formatter;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatter;
import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.TextEdit;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class EclipseFormatter {
private static final DefaultCodeFormatter formatter = new DefaultCodeFormatter(DefaultCodeFormatterOptions.getEclipseDefaultSettings());
public static String processSource(String input, String lineSeparator) {
try {
IDocument doc = new Document();
doc.set(input);
TextEdit edit = formatter.format(CodeFormatter.K_COMPILATION_UNIT |
CodeFormatter.F_INCLUDE_COMMENTS, input, 0, input.length(), 0, lineSeparator);
edit.apply(doc);
return doc.get();
}catch(Throwable t) {
System.err.println("Code formatting failed!");
t.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,130 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class CSVMappings {
public final Map<String, Symbol> csvFieldsMappings = new HashMap();
public final Map<String, Symbol> csvMethodsMappings = new HashMap();
public final Map<String, Param> csvParamsMappings = new HashMap();
public final Map<String, Param[]> csvParamsForFunction = new HashMap();
public static class Symbol {
public final String name;
public final int mod;
public final String comment;
public Symbol(String name, int mod, String comment) {
this.name = name;
this.mod = mod;
this.comment = comment;
}
}
public static class Param {
public final String name;
public final int mod;
public Param(String name, int mod) {
this.name = name;
this.mod = mod;
}
}
public void loadMethodsFile(Reader reader) throws IOException {
loadSymbols(reader, csvMethodsMappings, "methods.csv");
}
public void loadFieldsFile(Reader reader) throws IOException {
loadSymbols(reader, csvFieldsMappings, "fields.csv");
}
private void loadSymbols(Reader reader, Map<String, Symbol> map, String debugFileName) throws IOException {
try {
CSVParser ps = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader);
Iterator<CSVRecord> rows = ps.iterator();
while(rows.hasNext()) {
CSVRecord rec = rows.next();
String srgName = rec.get("searge");
String deobfName = rec.get("name");
int mod = Integer.parseInt(rec.get("side"));
String comment = rec.get("desc");
map.put(srgName, new Symbol(deobfName, mod, comment));
}
System.out.println(" Loaded " + map.size() + " symbols from " + debugFileName);
}catch(Throwable t) {
t.printStackTrace();
throw new IOException("Invalid " + debugFileName + " file!");
}
}
public void loadParamsFile(Reader reader) throws IOException {
try {
CSVParser ps = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(reader);
Iterator<CSVRecord> rows = ps.iterator();
while(rows.hasNext()) {
CSVRecord rec = rows.next();
String srgName = rec.get("param");
String deobfName = rec.get("name");
int mod = Integer.parseInt(rec.get("side"));
csvParamsMappings.put(srgName, new Param(deobfName, mod));
String fName = srgName.substring(srgName.indexOf('_') + 1);
if(!fName.startsWith("i")) {
int i2 = fName.indexOf('_');
if(i2 != -1) {
int ordinal = -1;
String ordStr = fName.substring(i2 + 1);
if(ordStr.length() >= 2) {
try {
ordinal = Integer.parseInt(ordStr.substring(0, ordStr.length() - 1));
}catch(NumberFormatException ex) {
}
}
if(ordinal >= 0) {
fName = "func_" + fName.substring(0, i2);
Param[] prm = csvParamsForFunction.get(fName);
if(prm == null || prm.length <= ordinal) {
Param[] prm2 = new Param[ordinal + 1];
if(prm != null) {
System.arraycopy(prm, 0, prm2, 0, prm.length);
}
prm = prm2;
}
prm[ordinal] = new Param(deobfName, mod);
csvParamsForFunction.put(fName, prm);
}
}
}
}
System.out.println(" Loaded " + csvParamsMappings.size() + " symbols from params.csv");
}catch(Throwable t) {
throw new IOException("Invalid params.csv file!");
}
}
}

View File

@ -0,0 +1,127 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class CreateUnpatched {
public static boolean createUnpatched() {
try {
return createUnpatched0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'unpatched'!");
t.printStackTrace();
return false;
}
}
private static boolean createUnpatched0() throws Throwable {
File tmpDirectory = EaglerBuildToolsConfig.getTemporaryDirectory();
File mcpDir = new File(tmpDirectory, "ModCoderPack");
File minecraftSrc = new File(tmpDirectory, "MinecraftSrc/minecraft_src.jar");
File minecraftRes = new File(tmpDirectory, "MinecraftSrc/minecraft_res.jar");
File outputFile = new File("./MinecraftSrc.zip");
if(outputFile.exists()) {
System.err.println("ERROR: The file 'MinecraftSrc.zip' already exists in this directory!");
System.err.println("Delete it and re-run 'unpatched' to try again");
return false;
}
if(!mcpDir.isDirectory()) {
System.err.println("The '" + mcpDir.getName() + "' directory was not found in the temporary directory!");
System.err.println("Please run the 'init' command to create it");
return false;
}
if(!minecraftSrc.isFile()) {
System.err.println("The '" + minecraftSrc.getName() + "' file was not found in the temporary directory!");
System.err.println("Please run the 'init' command to create it");
return false;
}
if(!minecraftRes.isFile()) {
System.err.println("The '" + minecraftRes.getName() + "' file was not found in the temporary directory!");
System.err.println("Please run the 'init' command to create it");
return false;
}
File tmpJavadocOut = new File(tmpDirectory, "MinecraftSrc/minecraft_unpatched_javadoc.jar");
System.out.println();
System.out.println("Preparing source in '" + minecraftSrc.getName() + "'...");
System.out.println();
CSVMappings mp = new CSVMappings();
InsertJavaDoc.processSource(minecraftSrc, tmpJavadocOut, mcpDir, mp, false);
try(ZipOutputStream zot = new ZipOutputStream(new FileOutputStream(outputFile))) {
zot.setLevel(0);
int tl;
System.out.println("Extracting '" + tmpJavadocOut.getName() + "' into '" + outputFile.getName() + "'...");
try(FileInputStream fin = new FileInputStream(tmpJavadocOut)) {
tl = extractZipTo(new ZipInputStream(fin), zot, "src");
}
System.out.println("Extracted " + tl + " files.");
System.out.println();
System.out.println("Extracting '" + minecraftRes.getName() + "' into '" + outputFile.getName() + "'...");
try(FileInputStream fin = new FileInputStream(minecraftRes)) {
tl = extractZipTo(new ZipInputStream(fin), zot, "res");
}
System.out.println("Extracted " + tl + " files.");
}
if(!tmpJavadocOut.delete()) {
System.err.println();
System.err.println("ERROR: failed to delete '" + tmpJavadocOut.getName() + "' from temporary directory!");
}
return true;
}
private static int extractZipTo(ZipInputStream zin, ZipOutputStream zout, String pfx) throws IOException {
int cnt = 0;
ZipEntry in;
while((in = zin.getNextEntry()) != null) {
if(in.isDirectory()) {
continue;
}
String n = in.getName();
if(n.startsWith("/")) {
n = n.substring(1);
}
if(n.startsWith("META-INF")) {
continue;
}
ZipEntry out = new ZipEntry(pfx + "/" + n);
zout.putNextEntry(out);
IOUtils.copy(zin, zout, 8192);
++cnt;
}
return cnt;
}
}

View File

@ -0,0 +1,241 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.ApplyPatchesToZip;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.formatter.EclipseFormatter;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.JARSubprocess;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class DecompileMinecraft {
public static boolean decompileMinecraft(File mcpDataTMP, File minecraftJar, File minecraftSrc, File assetsJson, boolean writeJavaDoc) throws Throwable {
File filterOut = new File(minecraftSrc, "minecraft_classes.jar");
System.out.println();
System.out.println("Extracting '" + minecraftJar.getAbsolutePath() + "\" to \"" + filterOut.getAbsolutePath() + "\"...");
int xt = 0;
try(ZipInputStream jarIn = new ZipInputStream(new FileInputStream(minecraftJar));
ZipOutputStream jarOut = new ZipOutputStream(new FileOutputStream(filterOut))) {
jarOut.setLevel(0);
jarOut.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
jarOut.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
ZipEntry et;
String nm;
while((et = jarIn.getNextEntry()) != null) {
if(!et.isDirectory() && (nm = et.getName()).endsWith(".class")) {
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.copy(jarIn, jarOut);
++xt;
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to extract \"" + minecraftJar.getAbsolutePath() + "\" to \"" + filterOut.getAbsolutePath() + "\"!");
ex.printStackTrace();
if(filterOut.exists()) {
filterOut.delete();
}
return false;
}
System.out.println("Extracted " + xt + " class files.");
File deobfOut = new File(minecraftSrc, "minecraft_specialsource.jar");
System.out.println();
System.out.println("Running SpecialSource...");
int ex = JARSubprocess.runJava(mcpDataTMP, new String[] {
"-cp", filterOut.getAbsolutePath() + JARSubprocess.classPathSeperator + "runtime.jar",
"net.md_5.specialsource.SpecialSource", "-i", filterOut.getAbsolutePath(), "-o",
deobfOut.getAbsolutePath(), "-m", "minecraft.srg", "--kill-source"
}, " [SpecialSource]");
filterOut.delete();
if(ex == 0) {
System.out.println("SpecialSource completed successfully.");
}else {
System.err.println("ERROR: MCP SpecialSource execution failed!");
return false;
}
System.out.println();
File deobfOut2 = new File(minecraftSrc, "minecraft_mcinjector.jar");
System.out.println("Running MCInjector...");
ex = JARSubprocess.runJava(mcpDataTMP, new String[] {
"-cp", filterOut.getAbsolutePath() + JARSubprocess.classPathSeperator + "runtime.jar",
"de.oceanlabs.mcp.mcinjector.MCInjector", "--jarIn", deobfOut.getAbsolutePath(), "--jarOut",
deobfOut2.getAbsolutePath(), "--mapIn", "minecraft.exc", "--jsonIn", "exceptor.json",
"--lvt", "STRIP"
}, " [MCInjector]");
deobfOut.delete();
if(ex == 0) {
System.out.println("MCInjector completed successfully.");
}else {
System.err.println("ERROR: MCP MCInjector execution failed!");
return false;
}
System.out.println();
File ffOut = new File(minecraftSrc, "fernflower.tmp");
if(ffOut.isFile()) {
ffOut.delete();
}else if(ffOut.isDirectory()) {
FileUtils.deleteDirectory(ffOut);
}
if(!ffOut.mkdir()) {
System.err.println("ERROR: Could not create Fernflower output directory!");
return false;
}
System.out.println("Decompiling with Fernflower...");
System.out.println("This will take a while, go get a drink or something lol.");
System.out.println();
System.out.println("Staying hydrated is important when u work on a fucked up project that");
System.out.println("will make you angry enough put your fists through your bedroom wall");
System.out.println();
ex = JARSubprocess.runJava(mcpDataTMP, new String[] {
"-jar", "fernflower.jar", "-din=1", "-rbr=1", "-dgs=1", "-asc=1", "-rsy=1", "-iec=1",
"-ren=0", "-jvn=1", "-udv=1", "-ump=1", "-log=WARN", deobfOut2.getAbsolutePath(),
ffOut.getAbsolutePath()
}, " [Fernflower]");
deobfOut2.delete();
if(ex == 0) {
System.out.println("Decompiler completed successfully.");
}else {
System.err.println("ERROR: Fernflower decompiler failed!");
return false;
}
System.out.println();
File[] ff = ffOut.listFiles();
File decomp = null;
for(int i = 0; i < ff.length; ++i) {
if(ff[i].getName().endsWith(".jar")) {
if(ff[i].getName().equalsIgnoreCase("minecraft_mcinjector.jar")) {
decomp = ff[i];
}else {
if(decomp == null) {
decomp = ff[i];
}
}
}
}
if(decomp == null) {
System.err.println("Could not find Fernflower output jar! (in " + ffOut.getAbsolutePath() + ")");
return false;
}
File formatOut = new File(minecraftSrc, "minecraft_src.jar");
System.out.println("Formatting source for patches...");
System.out.println(" (Using default Eclipse format)");
System.out.print(" ");
xt = 0;
try(ZipInputStream jarIn = new ZipInputStream(new FileInputStream(decomp));
ZipOutputStream jarOut = new ZipOutputStream(new FileOutputStream(formatOut))) {
jarOut.setLevel(5);
jarOut.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
jarOut.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
ZipEntry et;
String nm;
while((et = jarIn.getNextEntry()) != null) {
if((nm = et.getName()).endsWith(".java")) {
String txt = IOUtils.toString(jarIn, "UTF-8");
txt = EclipseFormatter.processSource(txt, "\n");
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.write(txt, jarOut, "UTF-8");
++xt;
if(xt % 75 == 74) {
System.out.print(".");
}
}else {
if(!nm.startsWith("META-INF")) {
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.copy(jarIn, jarOut, 4096);
}
}
}
}
System.out.println();
System.out.println("Formatted " + xt + " classes.");
System.out.println();
try {
FileUtils.deleteDirectory(ffOut);
}catch(IOException exx) {
}
File patchOut = new File(minecraftSrc, "minecraft_src_patch.jar");
try {
ApplyPatchesToZip.applyPatches(formatOut, null, new File(EaglerBuildTools.repositoryRoot, "patches/minecraft"), patchOut, true, true);
}catch(Throwable t) {
System.err.println("ERROR: Could not apply 'patches' directory to: " + patchOut.getName());
return false;
}
File javadocOut = new File(minecraftSrc, "minecraft_src_javadoc.jar");
CSVMappings comments = writeJavaDoc ? new CSVMappings() : null;
if(!InsertJavaDoc.processSource(patchOut, javadocOut, mcpDataTMP, comments)) {
System.err.println("ERROR: Could not create javadoc!");
return false;
}
File resourcesOut = new File(minecraftSrc, "minecraft_res.jar");
if(!LoadResources.loadResources(minecraftJar, assetsJson, resourcesOut, mcpDataTMP, new File(minecraftSrc, "minecraft_languages.zip"))) {
System.err.println("ERROR: Could not copy resources!");
return false;
}
File patchResourcesOut = new File(minecraftSrc, "minecraft_res_patch.jar");
try {
ApplyPatchesToZip.applyPatches(resourcesOut, null, new File(EaglerBuildTools.repositoryRoot, "patches/resources"), patchResourcesOut, true, true);
}catch(Throwable t) {
System.err.println("ERROR: Could not apply 'patches' directory to: " + patchResourcesOut.getName());
t.printStackTrace();
return false;
}
return true;
}
}

View File

@ -0,0 +1,175 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import org.apache.commons.io.FileUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class FFMPEG {
public static final boolean windows = System.getProperty("os.name").toLowerCase().contains("windows");
public static String foundFFMPEG = null;
public static void confirmFFMPEG() {
if(checkFFMPEGOnPath()) {
foundFFMPEG = "ffmpeg";
return;
}
if(windows) {
File f = new File("mcp918/ffmpeg.exe");
if(!f.isFile()) {
System.out.println();
System.out.println("ERROR: 'ffmpeg.exe' wasn't found in the 'mcp918' folder!");
System.out.println();
System.out.println("Please visit one of the following URLs to download it:");
System.out.println(" - https://www.gyan.dev/ffmpeg/builds/");
System.out.println(" - https://github.com/BtbN/FFmpeg-Builds/releases");
System.out.println();
System.out.println("Locate 'bin/ffmpeg.exe' in the .zip file you download and");
System.out.println("place it in the 'mcp918' folder and press enter to continue");
System.out.println();
try {
while(System.in.read() != '\n') {
try {
Thread.sleep(20l);
} catch (InterruptedException e) {
}
}
}catch(IOException ex) {
}
confirmFFMPEG();
}else {
foundFFMPEG = f.getAbsolutePath();
}
}else {
do {
File f = new File("mcp918/ffmpeg");
if(f.isFile() && f.canExecute()) {
foundFFMPEG = f.getAbsolutePath();
return;
}
System.out.println();
System.out.println("ERROR: ffmpeg is not installed on this system!");
System.out.println();
System.out.println("Please install it to continue, you can use the package");
System.out.println("manager on most distros to do this automatically:");
System.out.println(" - Debian: apt install ffmpeg");
System.out.println(" - Ubuntu: apt install ffmpeg");
System.out.println(" - Fedora: dnf install ffmpeg");
System.out.println(" - Arch: pacman -S ffmpeg");
System.out.println();
System.out.println("Alternatively, place the 'ffmpeg' executable in the");
System.out.println("'mcp918' folder of this repository");
System.out.println();
System.out.println("Make sure it has chmod +x");
System.out.println();
System.out.println("Press enter to continue once it has installed");
System.out.println();
try {
while(System.in.read() != '\n') {
try {
Thread.sleep(20l);
} catch (InterruptedException e) {
}
}
}catch(IOException ex) {
}
}while(!checkFFMPEGOnPath());
foundFFMPEG = "ffmpeg";
}
}
public static int run(File rundir, String... args) {
String[] e = new String[args.length + 1];
System.arraycopy(args, 0, e, 1, args.length);
if(foundFFMPEG == null) {
confirmFFMPEG();
}
e[0] = foundFFMPEG;
ProcessBuilder pb = new ProcessBuilder(e);
pb.directory(rundir);
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
try {
Process p = pb.start();
while(true) {
try {
return p.waitFor();
} catch (InterruptedException ee) {
}
}
}catch(IOException ex) {
System.err.println("Could not start ffmpeg process!");
ex.printStackTrace();
return -1;
}
}
public static byte[] encodeOgg(File temporaryDir, byte[] bytesInput, int samples, int bitrate, boolean stereo) throws IOException {
File src = new File(temporaryDir, "temp.src.ogg");
FileUtils.writeByteArrayToFile(src, bytesInput);
File dst = new File(temporaryDir, "temp.dst.ogg");
int i;
if (stereo) {
i = run(temporaryDir, "-y", "-v", "error", "-i", "temp.src.ogg", "-c:a", "libvorbis", "-ac", "2",
"-apply_phase_inv", "1", "-b:a", "" + bitrate + "k", "-ar", "" + samples, "temp.dst.ogg");
} else {
i = run(temporaryDir, "-y", "-v", "error", "-i", "temp.src.ogg", "-c:a", "libvorbis", "-ac", "1",
"-apply_phase_inv", "0", "-b:a", "" + bitrate + "k", "-ar", "" + samples, "temp.dst.ogg");
}
src.delete();
if(i != 0) {
throw new IOException("FFMPEG returned error code: " + i);
}
byte[] read = FileUtils.readFileToByteArray(dst);
dst.delete();
return read;
}
public static boolean checkFFMPEGOnPath() {
ProcessBuilder pb = new ProcessBuilder("ffmpeg", "-version");
Process proc;
try {
proc = pb.start();
}catch(IOException ex) {
return false;
}
int exitCode;
while(true) {
try {
exitCode = proc.waitFor();
break;
} catch (InterruptedException e) {
}
}
return exitCode == 0;
}
}

View File

@ -0,0 +1,231 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.lax1dude.eaglercraft.v1_8.buildtools.decompiler.ParameterSplitter;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings.Param;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings.Symbol;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileReaderUTF;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileWriterUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class GenerateEXCs {
public static boolean generateEXCs(File mcpDataTMP, File excOut, CSVMappings params) {
System.out.println();
System.out.println("Generating \"" + excOut.getName() + "\" from \"" + mcpDataTMP.getName() + "\"...");
File paramsCSV = new File(mcpDataTMP, "params.csv");
try(FileReaderUTF fr = new FileReaderUTF(paramsCSV)) {
params.loadParamsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + paramsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
Map<Integer,String> paramsTmp = new HashMap();
Set<String> definedFunctions = new HashSet();
int pcount = 0;
int mcount = 0;
int pgcount = 0;
try(BufferedReader is = new BufferedReader(new FileReaderUTF(new File(mcpDataTMP, "joined.exc")));
PrintWriter os = new PrintWriter(new FileWriterUTF(excOut));) {
String s;
while((s = is.readLine()) != null) {
int idx = s.lastIndexOf('|');
if(idx != -1) {
String pfx = s.substring(0, idx);
String func = null;
int p1 = pfx.indexOf('(');
if(p1 != -1) {
func = pfx.substring(0, p1);
func = pfx.substring(func.lastIndexOf('.') + 1);
}
if(func != null) {
definedFunctions.add(func);
}
if(idx != s.length() - 1) {
paramsTmp.clear();
String[] prms = s.substring(idx + 1).split(",");
String[] nprms = new String[prms.length];
int lpc = 0;
for(int i = 0; i < prms.length; ++i) {
Param p = params.csvParamsMappings.get(prms[i]);
if(p != null) {
nprms[i] = p.name;
++pcount;
++lpc;
}
}
if(lpc != prms.length) {
if(p1 != -1) {
String sig = pfx.substring(p1);
sig = sig.substring(0, sig.indexOf('='));
pgcount += ParameterSplitter.getParameterArray(sig, nprms);
}
for(int i = 0; i < nprms.length; ++i) {
if(nprms[i] == null) {
nprms[i] = "param0" + i;
}
}
}
s = pfx + "|" + String.join(",", nprms);
}else if(func != null) {
int idxx = func.indexOf('_');
int idxx2 = func.lastIndexOf('_');
if(idxx2 > idxx) {
func = func.substring(0, idxx2 - 1);
}
Param[] pars = params.csvParamsForFunction.get(func);
String sig = null;
if(p1 != -1) {
sig = pfx.substring(p1);
sig = sig.substring(0, sig.indexOf('='));
}
if(pars == null) {
if(sig != null) {
String[] sg = ParameterSplitter.getParameterSigArray(sig, "par");
if(sg != null) {
s = pfx + "|" + String.join(",", sg);
}
pgcount += sg.length;
}
}else {
int notNullLen = 0;
for(int i = 0; i < pars.length; ++i) {
if(pars[i] != null) {
++notNullLen;
}
}
String[] sg = new String[notNullLen];
notNullLen = 0;
for(int i = 0; i < pars.length; ++i) {
if(pars[i] != null) {
sg[notNullLen++] = pars[i].name;
++pcount;
}
}
s = pfx + "|" + String.join(",", sg);
}
}
}
int idx3 = s.indexOf('(');
if(idx3 != -1) {
int idx4 = s.lastIndexOf('.', idx3);
if(idx4 != -1) {
String func = s.substring(idx4 + 1, idx3);
Symbol rp = params.csvMethodsMappings.get(func);
if(rp != null) {
String pfx = s.substring(0, idx4);
String pofx = s.substring(idx3);
s = pfx + "." + rp.name + pofx;
++mcount;
}
}
}
os.println(s);
}
os.println();
os.println("# auto generated entries start here:");
try(BufferedReader iss = new BufferedReader(new FileReaderUTF(new File(mcpDataTMP, "joined.srg")))) {
while((s = iss.readLine()) != null) {
if(s.startsWith("MD:")) {
int idx = s.lastIndexOf(' ');
if(idx > 0) {
int idx2 = s.lastIndexOf(' ', idx - 1);
String fname = s.substring(idx2 + 1, idx);
String fnameShort = fname;
String fsig = s.substring(idx + 1);
fnameShort = fname.substring(fname.lastIndexOf('/') + 1);
int idx3 = fnameShort.lastIndexOf('_');
if(idx3 != -1 && fnameShort.lastIndexOf('_', idx3 - 1) > 0) {
fnameShort = fnameShort.substring(0, idx3);
}
if(definedFunctions.add(fnameShort)) {
String[] sg = ParameterSplitter.getParameterSigArray(fsig, "par");
Param[] pars = params.csvParamsForFunction.get(fnameShort);
if(pars != null) {
int notNullLen = 0;
for(int i = 0; i < pars.length; ++i) {
if(pars[i] != null) {
++notNullLen;
}
}
if(notNullLen > 0) {
notNullLen = 0;
for(int i = 0; i < pars.length; ++i) {
if(pars[i] != null) {
int ii = notNullLen++;
if(ii < sg.length) {
sg[ii] = pars[i].name;
++pcount;
}
}
}
int idx4 = fname.lastIndexOf('/');
String ppfx = fname.substring(0, idx4);
String ppfunc = fname.substring(idx4 + 1);
Symbol rp = params.csvMethodsMappings.get(ppfunc);
if(rp != null) {
ppfunc = rp.name;
++mcount;
}
fname = ppfx + "." + ppfunc;
os.println(fname + fsig + "=|" + String.join(",", sg));
}
}else {
if(sg != null) {
if(sg.length > 0) {
pgcount += sg.length;
int idx4 = fname.lastIndexOf('/');
String ppfx = fname.substring(0, idx4);
String ppfunc = fname.substring(idx4 + 1);
Symbol rp = params.csvMethodsMappings.get(ppfunc);
if(rp != null) {
ppfunc = rp.name;
++mcount;
}
fname = ppfx + "." + ppfunc;
os.println(fname + fsig + "=|" + String.join(",", sg));
}
}
}
}
}
}
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to write \"" + excOut.getName() + "\" from \"joined.exc\"!");
ex.printStackTrace();
return false;
}
System.out.println(" - Deobf " + pcount + " params to \"" + excOut.getName() + "\"");
System.out.println(" - Generate " + pgcount + " params to \"" + excOut.getName() + "\"");
return true;
}
}

View File

@ -0,0 +1,100 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings.Symbol;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileReaderUTF;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileWriterUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class GenerateSRGs {
public static boolean generate(File mcpDataTMP, File srgOut, CSVMappings csv) throws Throwable {
System.out.println();
System.out.println("Generating \"" + srgOut.getName() + "\" from \"" + mcpDataTMP.getName() + "\"...");
File methodsCSV = new File(mcpDataTMP, "methods.csv");
try(FileReaderUTF fr = new FileReaderUTF(methodsCSV)) {
csv.loadMethodsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + methodsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
File fieldsCSV = new File(mcpDataTMP, "fields.csv");
try(FileReaderUTF fr = new FileReaderUTF(fieldsCSV)) {
csv.loadFieldsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + fieldsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
int ccount = 0;
int mcount = 0;
int fcount = 0;
try(BufferedReader is = new BufferedReader(new FileReaderUTF(new File(mcpDataTMP, "joined.srg")));
PrintWriter os = new PrintWriter(new FileWriterUTF(srgOut));) {
String s;
while((s = is.readLine()) != null) {
if(s.startsWith("MD:")) {
int lastSpace = s.lastIndexOf(' ');
String sig = s.substring(lastSpace + 1);
s = s.substring(0, lastSpace);
int lastSlash = s.lastIndexOf('/');
String fd = s.substring(lastSlash + 1);
s = s.substring(0, lastSlash);
Symbol sm = csv.csvMethodsMappings.get(fd);
if(sm != null) {
++mcount;
fd = sm.name;
}
os.println(s + "/" + fd + " " + sig);
}else if(s.startsWith("FD:")) {
int lastSlash = s.lastIndexOf('/');
String fd = s.substring(lastSlash + 1);
s = s.substring(0, lastSlash);
Symbol sm = csv.csvFieldsMappings.get(fd);
if(sm != null) {
++fcount;
fd = sm.name;
}
os.println(s + "/" + fd);
}else if(s.startsWith("CL:")) {
++ccount;
os.println(s);
}else {
os.println(s);
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to write \"" + srgOut.getName() + "\" from \"joined.srg\"!");
ex.printStackTrace();
return false;
}
System.out.println(" - Deobf " + ccount + " classes to \"" + srgOut.getName() + "\"");
System.out.println(" - Deobf " + mcount + " methods to \"" + srgOut.getName() + "\"");
System.out.println(" - Deobf " + fcount + " fields to \"" + srgOut.getName() + "\"");
return true;
}
}

View File

@ -0,0 +1,135 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class InitMCP {
public static boolean initTask(File f, File mcpDataTMP) throws Throwable {
File mcpUnifiedJar = new File(mcpDataTMP, "runtime.jar");
String[] jarsToUnify = new String[] { "mcinjector.jar", "specialsource.jar" }; //, "retroguard.jar" };
boolean[] jarsFound = new boolean[jarsToUnify.length];
String[] configToCopy = new String[] { "exceptor.json", "fields.csv", "joined.exc",
"joined.srg", "methods.csv", "params.csv", "fernflower.jar" };
boolean[] configFound = new boolean[configToCopy.length];
Set<String> copiedFiles = new HashSet();
System.out.println();
System.out.println("Extracting \"" + f.getAbsolutePath() + "\" to \"" + mcpDataTMP.getAbsolutePath() + "\"...");
try(ZipInputStream is = new ZipInputStream(new FileInputStream(f));
ZipOutputStream os = new ZipOutputStream(new FileOutputStream(mcpUnifiedJar))) {
os.setLevel(0);
os.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
os.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
ZipEntry e;
entry_read: while((e = is.getNextEntry()) != null) {
String zn = e.getName();
if(zn.startsWith("/")) {
zn = zn.substring(1);
}
for(int ii = 0; ii < jarsToUnify.length; ++ii) {
if(zn.endsWith(jarsToUnify[ii])) {
System.out.println(" " + jarsToUnify[ii] + " -> " + mcpUnifiedJar.getName());
ZipInputStream iis = new ZipInputStream(is);
ZipEntry e2;
while((e2 = iis.getNextEntry()) != null) {
if(e2.isDirectory()) {
continue;
}
String n = e2.getName();
int i = n.indexOf("META-INF");
if(i == 0 || i == 1) {
continue;
}
if(copiedFiles.add(n)) {
ZipEntry e3 = new ZipEntry(e2.getName());
os.putNextEntry(e3);
IOUtils.copy(iis, os, 4096);
}
}
jarsFound[ii] = true;
continue entry_read;
}
}
for(int ii = 0; ii < configToCopy.length; ++ii) {
if(zn.endsWith(configToCopy[ii])) {
System.out.println(" " + configToCopy[ii] + " -> " + configToCopy[ii]);
try(OutputStream oss = new FileOutputStream(new File(mcpDataTMP, configToCopy[ii]))) {
IOUtils.copy(is, oss, 32768);
}
configFound[ii] = true;
continue entry_read;
}
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to extract \"" + f.getAbsolutePath() + "\" to \"" + mcpDataTMP.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
boolean err = false;
for(int ii = 0; ii < jarsToUnify.length; ++ii) {
if(!jarsFound[ii]) {
err = true;
System.err.println("JAR not found: \"" + jarsToUnify[ii] + "\"!");
}
}
for(int ii = 0; ii < configToCopy.length; ++ii) {
if(!configFound[ii]) {
err = true;
System.err.println("Config not found: \"" + configToCopy[ii] + "\"!");
}
}
if(err) {
System.err.println("ERROR: Could not extract all required MCP files from \"" + f.getName() + "\"!");
return false;
}
CSVMappings mappings = new CSVMappings();
File srgsOut = new File(mcpDataTMP, "minecraft.srg");
if(!GenerateSRGs.generate(mcpDataTMP, srgsOut, mappings)) {
System.err.println("ERROR: could not generate joined \"minecraft.srg\" file from conf in \"" + mcpDataTMP.getAbsolutePath() + "\"!");
return false;
}
File excsOut = new File(mcpDataTMP, "minecraft.exc");
if(!GenerateEXCs.generateEXCs(mcpDataTMP, excsOut, mappings)) {
System.err.println("ERROR: could not generate joined \"minecraft.exc\" file from conf in \"" + mcpDataTMP.getAbsolutePath() + "\"!");
return false;
}
return true;
}
}

View File

@ -0,0 +1,158 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.commons.io.FileUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class InitTask {
private static File locatedMCPZip = null;
private static File locatedMinecraftJar = null;
private static File locatedAssetsJson = null;
public static boolean initTask() {
try {
return initTask0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'init'!");
t.printStackTrace();
return false;
}
}
private static boolean initTask0() throws Throwable {
System.out.println("Scanning 'mcp918' folder...");
File mcp918dir = new File(EaglerBuildTools.repositoryRoot, "mcp918");
if(!mcp918dir.isDirectory()) {
System.err.println("ERROR: \"" + mcp918dir.getAbsolutePath() + "\" is not a directory!");
return false;
}
for(File f : mcp918dir.listFiles()) {
if(f.getName().equalsIgnoreCase("mcp918.zip")) {
locatedMCPZip = f;
}
if(locatedMCPZip == null && f.getName().endsWith(".zip")) {
locatedMCPZip = f;
}
if(f.getName().equalsIgnoreCase("1.8.8.jar")) {
locatedMinecraftJar = f;
}
if(locatedMinecraftJar == null && f.getName().endsWith(".jar")) {
locatedMinecraftJar = f;
}
if(f.getName().equalsIgnoreCase("1.8.json")) {
locatedAssetsJson = f;
}
if(locatedAssetsJson == null && f.getName().endsWith(".json")) {
locatedAssetsJson = f;
}
}
if(locatedMCPZip == null) {
System.err.println("ERROR: could not find ./mcp918/mcp918.zip! Please locate it and copy it into the 'mcp918' folder.");
return false;
}
if(locatedMinecraftJar == null) {
locatedMinecraftJar = MinecraftLocator.locateMinecraftVersionJar("1.8.8");
if(locatedMinecraftJar == null) {
System.err.println("ERROR: could not find ./mcp918/1.8.8.jar! Please locate it and copy it into the 'mcp918' folder.");
return false;
}
}
if(locatedAssetsJson == null) {
locatedAssetsJson = MinecraftLocator.locateMinecraftVersionAssets("1.8");
if(locatedAssetsJson == null) {
System.err.println("ERROR: could not find ./mcp918/1.8.json! Please locate it and copy it into the 'mcp918' folder.");
return false;
}
}
FFMPEG.confirmFFMPEG();
File buildToolsTmp = EaglerBuildToolsConfig.getTemporaryDirectory();
boolean btExist = buildToolsTmp.exists();
if(btExist && !(buildToolsTmp.isDirectory() && buildToolsTmp.list().length == 0)) {
System.out.println();
System.out.println("Notice: BuildTools is already initialized.");
System.out.println();
System.out.println("you must revert all changes in the 'patches' directory of");
System.out.println("this repo back to the main repository's current commits,");
System.out.println("otherwise the 'pullrequest' command wll not work properly");
System.out.println();
System.out.print("Do you want to re-initialize? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("Ok nice, the re-init will be cancelled. (thank god)");
return true;
}else {
try {
FileUtils.deleteDirectory(buildToolsTmp);
btExist = false;
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + buildToolsTmp.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
}
}
File mcpDataTMP = new File(buildToolsTmp, "ModCoderPack");
if(!mcpDataTMP.isDirectory() && !mcpDataTMP.mkdirs()) {
System.err.println("ERROR: failed to create \"" + mcpDataTMP.getAbsolutePath() + "\"!");
return false;
}
boolean skipMCP = false;
if(!skipMCP && !InitMCP.initTask(locatedMCPZip, mcpDataTMP)) {
System.err.println("ERROR: could not initialize MCP from \"" + locatedMCPZip.getAbsolutePath() + "\"!");
return false;
}
File minecraftSrcTmp = new File(buildToolsTmp, "MinecraftSrc");
if(!minecraftSrcTmp.isDirectory() && !minecraftSrcTmp.mkdirs()) {
System.err.println("ERROR: failed to create \"" + minecraftSrcTmp.getAbsolutePath() + "\"!");
return false;
}
if(!DecompileMinecraft.decompileMinecraft(mcpDataTMP, locatedMinecraftJar, minecraftSrcTmp, locatedAssetsJson, true)) {
System.err.println("ERROR: could not decompile and patch 1.8.8.jar from \"" + locatedMinecraftJar.getAbsolutePath() + "\"!");
return false;
}
return true;
}
}

View File

@ -0,0 +1,389 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.Lines;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.init.CSVMappings.Symbol;
import net.lax1dude.eaglercraft.v1_8.buildtools.util.FileReaderUTF;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class InsertJavaDoc {
public static final String enumImport = "import static net.lax1dude.eaglercraft.v1_8.opengl.RealOpenGLEnums.*;";
private static final String[] typeModifiersFields = new String[] {
"public", "private", "protected", "static",
"final", "volatile", "transient"
};
private static boolean isTypeModifierField(String tk) {
for(int i = 0; i < typeModifiersFields.length; ++i) {
if(typeModifiersFields[i].equals(tk)) {
return true;
}
}
return false;
}
private static final String[] typeModifiersMethods = new String[] {
"public", "private", "protected", "static",
"final", "synchronized", "abstract", "default"
};
private static final Pattern illegalCharactersNotATypeName = Pattern.compile("[^a-zA-Z0-9_\\-\\$\\[\\]<>\\.]");
private static boolean isTypeModifierMethod(String tk) {
for(int i = 0; i < typeModifiersMethods.length; ++i) {
if(typeModifiersMethods[i].equals(tk)) {
return true;
}
}
return false;
}
public static boolean processSource(File fileIn, File fileOut, File mcpDataTMP, CSVMappings csv) throws Throwable {
return processSource(fileIn, fileOut, mcpDataTMP, csv, true);
}
public static boolean processSource(File fileIn, File fileOut, File mcpDataTMP, CSVMappings csv, boolean compress) throws Throwable {
System.out.println("Adding javadoc...");
if(csv == null) {
System.out.println("(writing enums only, skipping field/method annotations)");
}
//RealOpenGLEnums.initEnums();
//System.out.println("Loaded " + RealOpenGLEnums.enumNames.size() + " OpenGL enums");
List<String> copyrightComment = null;
try(BufferedReader is = new BufferedReader(new FileReaderUTF(new File(EaglerBuildTools.repositoryRoot, "patches/minecraft/output_license.txt")))) {
copyrightComment = new ArrayList();
copyrightComment.add("/**+");
String ln;
while((ln = is.readLine()) != null) {
copyrightComment.add(" * " + ln);
}
copyrightComment.add(" * ");
copyrightComment.add(" */");
}
Map<String, List<Symbol>> methodsInClasses = new HashMap();
Map<String, List<Symbol>> fieldsInClasses = new HashMap();
if(csv != null) {
File methodsCSV = new File(mcpDataTMP, "methods.csv");
try(FileReaderUTF fr = new FileReaderUTF(methodsCSV)) {
csv.loadMethodsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + methodsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
File fieldsCSV = new File(mcpDataTMP, "fields.csv");
try(FileReaderUTF fr = new FileReaderUTF(fieldsCSV)) {
csv.loadFieldsFile(fr);
}catch(IOException ex) {
System.err.println("ERROR: failed to read \"" + fieldsCSV.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
try(BufferedReader is = new BufferedReader(new FileReaderUTF(new File(mcpDataTMP, "joined.srg")))) {
String s;
while((s = is.readLine()) != null) {
if(s.startsWith("MD:")) {
s = s.trim();
int idxx = s.lastIndexOf(' ');
int idxx2 = s.lastIndexOf(' ', idxx - 1);
s = s.substring(idxx2 + 1, idxx);
idxx = s.lastIndexOf('/');
String s1 = s.substring(0, idxx);
String s2 = s.substring(idxx + 1);
Symbol sm = csv.csvMethodsMappings.get(s2);
if(sm != null && sm.comment != null && sm.comment.length() > 0) {
List<Symbol> sbls = methodsInClasses.get(s1);
if(sbls == null) {
methodsInClasses.put(s1, sbls = new ArrayList());
}
sbls.add(sm);
}
}else if(s.startsWith("FD:")) {
s = s.trim();
int idxx = s.lastIndexOf(' ');
s = s.substring(idxx + 1);
idxx = s.lastIndexOf('/');
String s1 = s.substring(0, idxx);
String s2 = s.substring(idxx + 1);
Symbol sm = csv.csvFieldsMappings.get(s2);
if(sm != null && sm.comment != null && sm.comment.length() > 0) {
List<Symbol> sbls = fieldsInClasses.get(s1);
if(sbls == null) {
fieldsInClasses.put(s1, sbls = new ArrayList());
}
sbls.add(sm);
}
}
}
}
}
OpenGLEnumManager.loadEnumMap();
System.out.print(" ");
int xt = 0;
int modm = 0;
int modf = 0;
final int[] enums = new int[1];
Consumer<Integer> enumCounter = new Consumer<Integer>() {
@Override
public void accept(Integer t) {
enums[0] += t.intValue();
}
};
try(ZipInputStream jarIn = new ZipInputStream(new FileInputStream(fileIn));
ZipOutputStream jarOut = new ZipOutputStream(new FileOutputStream(fileOut))) {
jarOut.setLevel(compress ? 5 : 0);
jarOut.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
jarOut.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
ZipEntry et;
String nm;
while((et = jarIn.getNextEntry()) != null) {
if(et.isDirectory()) {
continue;
}
nm = et.getName();
if(nm.endsWith(".java")) {
String fs = IOUtils.toString(jarIn, "UTF-8");
List<String> linesLst = new ArrayList();
linesLst.addAll(Lines.linesList(fs));
if(copyrightComment != null) {
for(int i = 0; i < linesLst.size(); ++i) {
String ln = linesLst.get(i);
if(!ln.startsWith("import")) {
if(ln.startsWith("public")) {
ln = ln.substring(6).trim();
}
if(ln.startsWith("class") || ln.startsWith("enum") || ln.startsWith("interface") || ln.startsWith("@interface")) {
linesLst.addAll(i, copyrightComment);
i += copyrightComment.size();
break;
}
}
}
}
String cnm = nm.substring(0, nm.length() - 5);
List<Symbol> meths = csv == null ? null : methodsInClasses.get(cnm);
List<Symbol> fields = csv == null ? null : fieldsInClasses.get(cnm);
if(meths != null || fields != null) {
for(int i = 0; i < linesLst.size(); ++i) {
String ln2 = linesLst.get(i);
boolean notMethod = ln2.endsWith(";");
String ln = ln2;
String indent = "";
while(ln.length() > 0 && Character.isWhitespace(ln.charAt(0))) {
indent += ln.charAt(0);
ln = ln.substring(1);
}
String[] tokens = ln.split("\\s+");
boolean hasTypeDecl = false;
boolean hasMethodDecl = false;
boolean hasType = false;
for(int j = 0; j < tokens.length; ++j) {
if(tokens[j].length() > 0) {
boolean b1 = false;
boolean b2 = false;
if(isTypeModifierField(tokens[j])) {
b1 = true;
hasTypeDecl = true;
}
if(!notMethod && isTypeModifierMethod(tokens[j])) {
b2 = true;
hasMethodDecl = true;
}
if(b1 || b2) {
continue;
}else if(!hasType) {
if(illegalCharactersNotATypeName.matcher(tokens[j]).find()) {
break;
}else {
hasType = true;
continue;
}
}
int idx = 0;
if(hasTypeDecl && j < tokens.length - 1 && tokens[j + 1].equals("=")) {
if(fields != null) {
for(int k = 0, l = fields.size(); k < l; ++k) {
Symbol ss = fields.get(k);
if(ss.name.equals(tokens[j])) {
List<String> lines = wordWrapComment(ss.comment, indent);
linesLst.addAll(i, lines);
i += lines.size();
++modf;
break;
}
}
}
}else if(((idx = tokens[j].indexOf('(')) != -1 && j > 0) || hasMethodDecl) {
if(meths != null) {
if(idx > 0) {
String sss = tokens[j].substring(0, idx);
for(int k = 0, l = meths.size(); k < l; ++k) {
Symbol ss = meths.get(k);
if(ss.name.equals(sss)) {
List<String> lines = wordWrapComment(ss.comment, indent);
linesLst.addAll(i, lines);
i += lines.size();
++modm;
break;
}
}
}
}
}
break;
}
}
}
}
int cnt0 = enums[0];
for(int i = 0, l = linesLst.size(); i < l; ++i) {
linesLst.set(i, OpenGLEnumManager.insertIntoLine(linesLst.get(i), enumCounter));
}
if(cnt0 != enums[0]) {
for(int i = 0, l = linesLst.size(); i < l; ++i) {
String line = linesLst.get(i);
if(line.startsWith("package")) {
linesLst.addAll(i + 1, Arrays.asList("", enumImport));
break;
}
}
}
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.write(String.join(System.lineSeparator(), linesLst), jarOut, "UTF-8");
++xt;
if(xt % 75 == 74) {
System.out.print(".");
}
}else {
if(!nm.startsWith("META-INF")) {
ZipEntry z2 = new ZipEntry(nm);
jarOut.putNextEntry(z2);
IOUtils.copy(jarIn, jarOut, 4096);
}
}
}
}catch(IOException ex) {
System.err.println("Failed to process jar '" + fileIn.getName() + "' and write it to '" + fileOut.getName() + "!");
ex.printStackTrace();
return false;
}
System.out.println();
System.out.println("Added " + enums[0] + " OpenGL enums");
if(csv != null) {
System.out.println("Added " + modm + " comments to methods");
System.out.println("Added " + modf + " comments to fields");
}
System.out.println();
return true;
}
private static List<String> wordWrapComment(String strIn, String indent) {
String[] wds = strIn.split("\\s+");
List<String> ret = new ArrayList();
ret.add(indent + "/**+");
String ln = "";
for(int i = 0; i < wds.length; ++i) {
if(ln.length() > 0 && wds[i].length() + ln.length() > 60) {
ret.add(indent + " * " + ln);
ln = "";
}
ln += ln.length() > 0 ? " " + wds[i] : wds[i];
}
if(ln.length() > 0) {
ret.add(indent + " * " + ln);
}
ret.add(indent + " */");
return ret;
}
public static String stripDocForDiff(String fileIn) {
List<String> linesIn = Lines.linesList(fileIn);
OpenGLEnumManager.loadEnumMap();
List<String> linesOut = new ArrayList();
boolean addOpenGLImport = false;
for(int i = 0, l = linesIn.size(); i < l; ++i) {
String line = linesIn.get(i);
if(line.trim().startsWith("/**+")) {
for(; i < l; ++i) {
if(linesIn.get(i).endsWith("*/")) {
break;
}
}
}else {
String line2 = OpenGLEnumManager.stripFromLine(line);
if(line2 != null) {
linesOut.add(line2);
addOpenGLImport = true;
}else {
linesOut.add(line);
}
}
}
if(addOpenGLImport) {
int idx = linesOut.indexOf(enumImport);
if(idx != -1) {
if(idx - 1 >= 0 && linesOut.get(idx - 1).trim().length() == 0 && linesOut.size() > 1) {
idx -= 1;
linesOut.remove(idx);
linesOut.remove(idx);
}else {
linesOut.remove(idx);
}
}
}
return String.join(System.lineSeparator(), linesOut);
}
}

View File

@ -0,0 +1,180 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.JSONException;
import org.json.JSONObject;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildTools;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class LoadResources {
public static boolean loadResources(File minecraftJarIn, File assetsIndexIn, File assetsJarOut, File tmpDir, File languagesZipOut) {
System.out.println("Copying resources from '" + minecraftJarIn.getName() + "' into '" + assetsJarOut.getName() + "'");
try(ZipOutputStream os = new ZipOutputStream(new FileOutputStream(assetsJarOut))) {
os.setLevel(5);
os.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF"));
os.write("Manifest-Version: 1.0\nCreated-By: Eaglercraft BuildTools\n".getBytes(StandardCharsets.UTF_8));
try(ZipInputStream is = new ZipInputStream(new FileInputStream(minecraftJarIn))) {
ZipEntry e;
while((e = is.getNextEntry()) != null) {
if(e.isDirectory()) {
continue;
}
String zn = e.getName();
if(zn.startsWith("/")) {
zn = zn.substring(1);
}
if(zn.startsWith("META-INF") || zn.endsWith(".class")) {
continue;
}
os.putNextEntry(e);
IOUtils.copy(is, os, 4096);
}
}
System.out.println();
System.out.println("Reading 'assetsIndexTransformer.json'...");
ResourceRulesList rules;
try {
rules = ResourceRulesList.loadResourceRules(new File(EaglerBuildTools.repositoryRoot, "mcp918/assetsIndexTransformer.json"));
}catch(IOException ex) {
System.err.println();
System.err.println("ERROR: failed to read 'mcp918/assetsIndexTransformer.json'!");
ex.printStackTrace();
return false;
}
System.out.println();
System.out.println("Reading asset index '" + assetsIndexIn.getAbsolutePath() + "'...");
try(ZipOutputStream os2 = new ZipOutputStream(new FileOutputStream(languagesZipOut))) {
os2.setLevel(5);
try {
JSONObject json = (new JSONObject(FileUtils.readFileToString(assetsIndexIn, StandardCharsets.UTF_8))).getJSONObject("objects");
Iterator<String> itr = json.keys();
System.out.println("Downloading assets from 'https://resources.download.minecraft.net/'...");
while(itr.hasNext()) {
String name = itr.next();
JSONObject obj = json.getJSONObject(name);
ResourceRulesList.ResourceRule r = rules.get(name);
if(r.action == ResourceRulesList.Action.EXCLUDE) {
System.out.println("Skipping file '" + name + "'");
continue;
}
String hash = obj.getString("hash");
int len = obj.getInt("size");
System.out.println("Downloading '" + name + "' (" + formatByteLength(len) + ") ...");
URL url;
try {
url = new URL("https://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash);
}catch(MalformedURLException ex) {
System.err.println("Resource file '" + name + "' had an invalid URL!");
ex.printStackTrace();
continue;
}
byte[] downloadedFile = new byte[len];
try(InputStream is = url.openStream()) {
int dl = 0;
int i = 0;
while(dl != len && (i = is.read(downloadedFile, dl, len - dl)) > 0) {
dl += i;
}
int a = is.available();
if(dl != len || a > 0) {
throw new IOException("File '" + url.toString() + "' was the wrong length! " + (a > 0 ? "" + a + " bytes remaining" : "" + (len - dl) + " bytes missing"));
}
}catch(IOException ex) {
System.err.println("Resource file '" + url.toString() + "' could not be downloaded!");
ex.printStackTrace();
continue;
}
if(r.action == ResourceRulesList.Action.ENCODE) {
try {
System.out.println(" - encoding ogg: " + (r.ffmpegSamples / 1000) + "kHz, " + r.ffmpegBitrate + "kbps, " + (r.ffmpegStereo ? "stereo" : "mono"));
downloadedFile = FFMPEG.encodeOgg(tmpDir, downloadedFile, r.ffmpegSamples, r.ffmpegBitrate, r.ffmpegStereo);
}catch(IOException ex) {
System.err.println("Resource file '" + name + "' could not be encoded!");
ex.printStackTrace();
continue;
}
}else if(r.action == ResourceRulesList.Action.LANGUAGES_ZIP) {
int j = name.lastIndexOf('/');
if(j != -1) {
name = name.substring(j + 1);
}
System.out.println(" - writing language '" + name + "' to '" + languagesZipOut.getName() + "'");
os2.putNextEntry(new ZipEntry(name));
os2.write(downloadedFile);
continue;
}
os.putNextEntry(new ZipEntry("assets/" + name));
os.write(downloadedFile);
}
}catch(IOException | JSONException ex) {
System.err.println("ERROR: failed to download additional assets from '" + assetsIndexIn.getName() + "'!");
ex.printStackTrace();
return false;
}
}
}catch(IOException ex) {
System.err.println("ERROR: failed to copy from '" + minecraftJarIn.getName() + "' -> '" +assetsJarOut.getName() + "'!");
ex.printStackTrace();
return false;
}
return true;
}
private static String formatByteLength(int len) {
if(len < 4096) {
return "" + len;
}else if(len < 1024 * 4096) {
return "" + (len / 1024) + "k";
}else {
return "" + (len / 1024 / 1024) + "M";
}
}
}

View File

@ -0,0 +1,81 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class MinecraftLocator {
private static boolean hasTriedToFind = false;
private static File directory = null;
private static File locateOrCopyFile(String name, String copyPath) {
File f = new File("./mcp918/" + name);
if(f.isFile()) {
return f;
}
if(!hasTriedToFind) {
hasTriedToFind = true;
String var0 = System.getProperty("os.name").toLowerCase();
if(var0.contains("win")) {
String ad = System.getenv("APPDATA");
if(ad != null) {
directory = new File(ad, ".minecraft");
}else {
directory = new File(System.getProperty("user.home"), ".minecraft");
}
}else if(var0.contains("mac")) {
directory = new File(System.getProperty("user.home"), "Library/Application Support/minecraft");
}else {
directory = new File(System.getProperty("user.home"), ".minecraft");
}
if(!directory.isDirectory()) {
directory = new File(System.getProperty("user.home"), "minecraft");
if(!directory.isDirectory()) {
directory = null;
}
}
}
if(directory == null) {
return null;
}else {
File f2 = new File(directory, copyPath);
if(f2.isFile()) {
try {
System.out.println("Copying '" + copyPath + "' from your .minecraft directory into './mcp918'...");
FileUtils.copyFile(f2, f, true);
return f;
} catch (IOException e) {
System.err.println("ERROR: failed to copy '" + copyPath + "' from your .minecraft directory into './mcp918'!");
e.printStackTrace();
return null;
}
}else {
return null;
}
}
}
public static File locateMinecraftVersionJar(String name) {
return locateOrCopyFile(name + ".jar", "versions/" + name + "/" + name + ".jar");
}
public static File locateMinecraftVersionAssets(String name) {
return locateOrCopyFile(name + ".json", "assets/indexes/" + name + ".json");
}
}

View File

@ -0,0 +1,228 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Consumer;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class OpenGLEnumManager {
private static boolean hasLoaded = false;
public static final Set<String> classNames = new HashSet();
public static final Map<String,String> enumsForGLStateManager = new HashMap();
public static final Map<String,Map<Integer,String>> enumsForFunctionKV = new HashMap();
public static final Map<String,Map<String,Integer>> enumsForFunctionVK = new HashMap();
public static boolean loadEnumMap() {
if(hasLoaded) {
return true;
}
hasLoaded = true;
try {
String enumsPath = "/lang/enums.json";
System.out.println("Loading OpenGL enums: " + enumsPath);
int fcnt = 0;
int ecnt = 0;
String jsonData;
try(InputStream is = OpenGLEnumManager.class.getResourceAsStream(enumsPath)) {
if(is == null) {
throw new FileNotFoundException("classpath:/" + enumsPath);
}
jsonData = IOUtils.toString(is, "UTF-8");
}
JSONArray enumJSON = (new JSONObject(jsonData)).getJSONArray("enums");
for(Object o : enumJSON.toList()) {
List<Object> enumData = (List<Object>) o;
List<String> functionsToAdd = new ArrayList();
Map<Integer,String> enumsToAddKV = new HashMap();
Map<String,Integer> enumsToAddVK = new HashMap();
Map<String,Object> functionSet = (Map<String,Object>)enumData.get(0);
for(Entry<String,Object> etr : functionSet.entrySet()) {
classNames.add(etr.getKey());
List<Object> functionArr = (List<Object>)etr.getValue();
for(Object func : functionArr) {
functionsToAdd.add(etr.getKey() + "." + (String)func);
}
}
Map<String,Object> enumSet = (Map<String,Object>)enumData.get(1);
for(Entry<String,Object> etr : enumSet.entrySet()) {
Map<String,Object> enumEnums = (Map<String,Object>)etr.getValue();
for(Entry<String,Object> etr2 : enumEnums.entrySet()) {
Integer intg = Integer.parseInt(etr2.getKey());
enumsToAddKV.put(intg, (String)etr2.getValue());
enumsToAddVK.put((String)etr2.getValue(), intg);
++ecnt;
}
}
for(String fn : functionsToAdd) {
if(!enumsForFunctionKV.containsKey(fn)) {
++fcnt;
enumsForFunctionKV.put(fn, enumsToAddKV);
enumsForFunctionVK.put(fn, enumsToAddVK);
}
}
}
String glStateEnumsPath = "/lang/statemgr.json";
System.out.println("Loading OpenGL enums: " + glStateEnumsPath);
try(InputStream is = OpenGLEnumManager.class.getResourceAsStream(glStateEnumsPath)) {
if(is == null) {
throw new FileNotFoundException("classpath:/" + glStateEnumsPath);
}
jsonData = IOUtils.toString(is, "UTF-8");
}
JSONObject enumStateJSON = (new JSONObject(jsonData)).getJSONObject("statemgr_mappings");
for(Entry<String,Object> etr : enumStateJSON.toMap().entrySet()) {
String f = etr.getKey();
String m = (String)etr.getValue();
enumsForGLStateManager.put(f, m);
if(!enumsForFunctionKV.containsKey(f) && enumsForFunctionKV.containsKey(m)) {
enumsForFunctionKV.put(f, enumsForFunctionKV.get(m));
enumsForFunctionVK.put(f, enumsForFunctionVK.get(m));
++fcnt;
}
}
for(String str : enumsForGLStateManager.keySet()) {
int idx = str.indexOf('.');
if(idx != -1) {
classNames.add(str.substring(0, idx));
}
}
System.out.println("Loaded " + ecnt + " enums for " + fcnt + " functions");
return true;
}catch(Throwable ex) {
System.err.println("ERROR: could not load opengl enum map!");
ex.printStackTrace();
return false;
}
}
public static String insertIntoLine(String input, Consumer<Integer> progressCallback) {
int idx1 = input.indexOf('.');
if(idx1 != -1) {
String pfx = input.substring(0, idx1);
String p2 = pfx.trim();
if(classNames.contains(p2)) {
String fn = input.substring(idx1 + 1);
int idx2 = fn.indexOf('(');
if(idx2 != -1) {
String argz = fn.substring(idx2 + 1);
fn = fn.substring(0, idx2);
int idx3 = argz.lastIndexOf(')');
String pofx = "";
if(idx3 == -1) {
idx3 = argz.length();
}else {
pofx = argz.substring(idx3);
}
Map<Integer,String> repValues = enumsForFunctionKV.get(p2 + "." + fn);
if(repValues != null) {
argz = argz.substring(0, idx3);
String[] args = argz.split(", ");
int cnt = 0;
for(int i = 0; i < args.length; ++i) {
Integer j;
try {
j = Integer.valueOf(args[i]);
}catch(NumberFormatException ex) {
continue;
}
String estr = repValues.get(j);
if(estr != null) {
args[i] = estr;
++cnt;
}
}
if(cnt > 0) {
input = pfx + "." + fn + "(" + String.join(", ", args) + pofx;
if(progressCallback != null) {
progressCallback.accept(cnt);
}
}
}
}
}
}
return input;
}
public static String stripFromLine(String input) {
int idx1 = input.indexOf('.');
if(idx1 != -1) {
String pfx = input.substring(0, idx1);
String p2 = pfx.trim();
if(classNames.contains(p2)) {
String fn = input.substring(idx1 + 1);
int idx2 = fn.indexOf('(');
if(idx2 != -1) {
String argz = fn.substring(idx2 + 1);
fn = fn.substring(0, idx2);
int idx3 = argz.lastIndexOf(')');
String pofx = "";
if(idx3 == -1) {
idx3 = argz.length();
}else {
pofx = argz.substring(idx3);
}
Map<String,Integer> repValues = enumsForFunctionVK.get(p2 + "." + fn);
if(repValues != null) {
argz = argz.substring(0, idx3);
String[] args = argz.split(", ");
int cnt = 0;
for(int i = 0; i < args.length; ++i) {
Integer estr = repValues.get(args[i]);
if(estr != null) {
args[i] = estr.toString();
++cnt;
}
}
if(cnt > 0) {
return pfx + "." + fn + "(" + String.join(", ", args) + pofx;
}
}
}
}
}
return null;
}
}

View File

@ -0,0 +1,125 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class ResourceRulesList {
public static ResourceRulesList loadResourceRules(File conf) throws IOException {
List<ResourceRule> list = new ArrayList();
try {
JSONArray rulesArray = new JSONObject(FileUtils.readFileToString(conf, StandardCharsets.UTF_8)).getJSONArray("rules");
for(int i = 0, l = rulesArray.length(); i < l; ++i) {
JSONObject obj = rulesArray.getJSONObject(i);
Iterator<String> itr = obj.keys();
while(itr.hasNext()) {
String name = itr.next();
JSONObject a = obj.getJSONObject(name);
boolean wildcard = name.endsWith("*");
if(wildcard) {
name = name.substring(0, name.length() - 1);
}
Action action = Action.valueOf(a.getString("action").toUpperCase());
int ffmpegSamples = 16000;
int ffmpegBitrate = 48;
boolean ffmpegStereo = false;
if(action == Action.ENCODE) {
JSONObject ffmpegObj = a.optJSONObject("ffmpeg", null);
if(ffmpegObj != null) {
ffmpegSamples = ffmpegObj.optInt("samples", ffmpegSamples);
ffmpegBitrate = ffmpegObj.optInt("bitrate", ffmpegBitrate);
ffmpegStereo = ffmpegObj.optBoolean("stereo", ffmpegStereo);
}
}
list.add(new ResourceRule(name, wildcard, action, ffmpegSamples, ffmpegBitrate, ffmpegStereo));
}
}
}catch(JSONException ex) {
throw new IOException("Invalid JSON file: " + conf.getAbsolutePath(), ex);
}
return new ResourceRulesList(list);
}
private final List<ResourceRule> list;
private ResourceRulesList(List<ResourceRule> list) {
this.list = list;
}
public ResourceRule get(String str) {
for(int i = 0, l = list.size(); i < l; ++i) {
ResourceRule r = list.get(i);
if(r.wildcard) {
if(str.startsWith(r.path)) {
return r;
}
}else {
if(str.equals(r.path)) {
return r;
}
}
}
return defaultRule;
}
private static final ResourceRule defaultRule = new ResourceRule("", true, Action.EXCLUDE, 16000, 48, false);
public static class ResourceRule {
private final String path;
private final boolean wildcard;
public final Action action;
public final int ffmpegSamples;
public final int ffmpegBitrate;
public final boolean ffmpegStereo;
protected ResourceRule(String path, boolean wildcard, Action action, int ffmpegSamples, int ffmpegBitrate,
boolean ffmpegStereo) {
this.path = path;
this.wildcard = wildcard;
this.action = action;
this.ffmpegSamples = ffmpegSamples;
this.ffmpegBitrate = ffmpegBitrate;
this.ffmpegStereo = ffmpegStereo;
}
}
public static enum Action {
INCLUDE, EXCLUDE, ENCODE, LANGUAGES_ZIP
}
}

View File

@ -0,0 +1,396 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
import net.lax1dude.eaglercraft.v1_8.buildtools.task.diff.ApplyPatchesToZip;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class SetupWorkspace {
public static boolean setupWorkspace() {
return setupWorkspace0(false);
}
public static boolean pullRequestTest() {
return setupWorkspace0(true);
}
private static boolean setupWorkspace0(boolean applyPullRequest) {
File tmp = EaglerBuildToolsConfig.getTemporaryDirectory();
File dst = EaglerBuildToolsConfig.getWorkspaceDirectory();
try {
return setupWorkspace1(tmp, dst, applyPullRequest);
}catch(Throwable t) {
System.err.println();
if(applyPullRequest) {
System.err.println("Exception encountered while running task 'pullrequest_test'!");
}else {
System.err.println("Exception encountered while running task 'workspace'!");
}
t.printStackTrace();
return false;
}
}
private static boolean setupWorkspace1(File btTmpDirectory, File workspaceDirectory, boolean applyPullRequest) throws Throwable {
boolean wsExist = workspaceDirectory.exists();
if(wsExist && !(workspaceDirectory.isDirectory() && workspaceDirectory.list().length == 0)) {
System.err.println();
System.err.println("WARNING: A workspace already exists in \"" + workspaceDirectory.getAbsolutePath() + "\"!");
System.err.println();
System.err.println("Any changes you've made to the code will be lost!");
System.err.println();
System.out.print("Do you want to reset the workspace? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("Ok nice, the workspace folder will not be reset. (thank god)");
System.out.println();
System.out.println("Edit 'buildtools_config.json' to set up a different workspace folder");
return true;
}else {
try {
FileUtils.deleteDirectory(workspaceDirectory);
wsExist = false;
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + workspaceDirectory.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
}
}
File mcTmpDirectory = new File(btTmpDirectory, "MinecraftSrc");
File minecraftResJar = new File(mcTmpDirectory, "minecraft_res_patch.jar");
File minecraftJavadocTmp = new File(mcTmpDirectory, "minecraft_src_javadoc.jar");
System.out.println();
System.out.println("Setting up dev workspace in \"" + workspaceDirectory.getAbsolutePath() + "\"...");
System.out.println();
if(!workspaceDirectory.isDirectory() && !workspaceDirectory.mkdirs()) {
System.err.println("ERROR: could not create \"" + workspaceDirectory.getAbsolutePath() + "\"!");
throw new IOException("Could not create \"" + workspaceDirectory.getAbsolutePath() + "\"!");
}
if(!minecraftJavadocTmp.isFile()) {
System.err.println("ERROR: could not find 'minecraft_src_javadoc.jar' in your current temporary directory!");
System.err.println("Run the 'init' command again to generate it");
return false;
}
if(!minecraftResJar.isFile()) {
System.err.println("ERROR: could not find 'minecraft_res_patch.jar' in your current temporary directory!");
System.err.println("Run the 'init' command again to generate it");
return false;
}
File repoSources = new File("./sources");
File repoSourcesSetup = new File(repoSources, "setup/workspace_template");
File repoSourcesGame = new File(repoSources, "main/java");
File repoSourcesTeaVM = new File(repoSources, "teavm/java");
File repoSourcesLWJGL = new File(repoSources, "lwjgl/java");
File repoSourcesResources = new File(repoSources, "resources");
File srcMainJava = new File(workspaceDirectory, "src/main/java");
File srcLWJGLJava = new File(workspaceDirectory, "src/lwjgl/java");
File srcTeaVMJava = new File(workspaceDirectory, "src/teavm/java");
File resourcesExtractTo = new File(workspaceDirectory, "desktopRuntime/resources");
File mcLanguagesZip = new File(mcTmpDirectory, "minecraft_languages.zip");
File mcLanguagesExtractTo = new File(workspaceDirectory, "javascript/lang");
System.out.println("Copying files from \"/setup/workspace_template/\" to \"" + workspaceDirectory.getName() + "\"...");
try {
FileUtils.copyDirectory(repoSourcesSetup, workspaceDirectory);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/setup/workspace_template/\" to \"" + workspaceDirectory.getAbsolutePath() + "\"!");
throw ex;
}
String os = System.getProperty("os.name").toLowerCase();
if(os.contains("linux") || os.contains("macos") || os.contains("osx")) {
File gradleW = new File(workspaceDirectory, "gradlew");
if(!gradleW.setExecutable(true)) {
System.err.println("ERROR: could not set executable bit on 'gradlew'!");
System.err.println("Enter the root directory of the repository and run 'chmod +x gradlew' if you need access to the gradlew command");
}
}
File existingGi = new File(workspaceDirectory, ".gitignore");
if((existingGi.exists() && !existingGi.delete()) || !(new File(workspaceDirectory, ".gitignore.default").renameTo(existingGi))) {
System.err.println("ERROR: Could not rename \".gitignore.default\" to \".gitignore\" in the workspace directory!");
}
if(repoSourcesTeaVM.isDirectory()) {
System.out.println("Copying files from \"/sources/teavm/java/\" to workspace...");
try {
if(!srcTeaVMJava.isDirectory() && !srcTeaVMJava.mkdirs()) {
System.err.println("ERROR: Could not create destination directory!");
return false;
}
FileUtils.copyDirectory(repoSourcesTeaVM, srcTeaVMJava);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/sources/teavm/java/\" to \"" + srcTeaVMJava.getAbsolutePath() + "\"!");
throw ex;
}
}
System.out.println("Copying files from \"/sources/main/java/\" to workspace...");
try {
FileUtils.copyDirectory(repoSourcesGame, srcMainJava);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/sources/main/java/\" to \"" + srcMainJava.getAbsolutePath() + "\"!");
throw ex;
}
if(repoSourcesLWJGL.isDirectory()) {
System.out.println("Copying files from \"/sources/lwjgl/java/\" to workspace...");
try {
if(!srcLWJGLJava.isDirectory() && !srcLWJGLJava.mkdirs()) {
System.err.println("ERROR: Could not create destination directory!");
return false;
}
FileUtils.copyDirectory(repoSourcesLWJGL, srcLWJGLJava);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/sources/lwjgl/java/\" to \"" + srcLWJGLJava.getAbsolutePath() + "\"!");
throw ex;
}
}
System.out.println("Copying files from \"/sources/resources/\" to workspace...");
try {
if(!resourcesExtractTo.isDirectory() && !resourcesExtractTo.mkdirs()) {
System.err.println("ERROR: Could not create destination directory!");
return false;
}
FileUtils.copyDirectory(repoSourcesResources, resourcesExtractTo);
}catch(IOException ex) {
System.err.println("ERROR: could not copy \"/sources/resources/\" to \"" + resourcesExtractTo.getAbsolutePath() + "\"!");
throw ex;
}
if(applyPullRequest) {
System.out.println();
System.out.println("Applying \"pullrequest\" directory to \"minecraft_src_patch.jar\"...");
File unpatchOut = new File(mcTmpDirectory, "minecraft_src.jar");
File patchOut = new File(mcTmpDirectory, "minecraft_src_patch.jar");
File unpatchResOut = new File(mcTmpDirectory, "minecraft_res.jar");
File patchResOut = new File(mcTmpDirectory, "minecraft_res_patch.jar");
File tmpPatchedPatchOut = new File(mcTmpDirectory, "minecraft_src_pullrequest_patch.jar");
File tmpPatchedPatchJavadocOut = new File(mcTmpDirectory, "minecraft_src_pullrequest_javadoc.jar");
File tmpPatchedPatchResOut = new File(mcTmpDirectory, "minecraft_res_pullrequest_patch.jar");
try {
ApplyPatchesToZip.applyPatches(patchOut, unpatchOut, new File("./pullrequest/source"), tmpPatchedPatchOut, false, false);
}catch(Throwable t) {
System.err.println();
System.err.println("ERROR: Could not apply pullrequest directory patches to: " + patchOut.getName());
System.err.println(t.toString());
tmpPatchedPatchOut.delete();
return false;
}
CSVMappings comments = new CSVMappings();
if(!InsertJavaDoc.processSource(tmpPatchedPatchOut, tmpPatchedPatchJavadocOut,
new File(btTmpDirectory, "ModCoderPack"), comments)) {
System.err.println();
System.err.println("ERROR: Could not create pullrequest javadoc!");
return false;
}
tmpPatchedPatchOut.delete();
try {
ApplyPatchesToZip.applyPatches(patchResOut, unpatchResOut, new File("./pullrequest/resources"), tmpPatchedPatchResOut, false, false);
}catch(Throwable t) {
System.err.println();
System.err.println("ERROR: Could not apply pullrequest directory patches to: " + patchResOut.getName());
System.err.println(t.toString());
tmpPatchedPatchOut.delete();
tmpPatchedPatchResOut.delete();
return false;
}
minecraftJavadocTmp = tmpPatchedPatchJavadocOut;
minecraftResJar = tmpPatchedPatchResOut;
}else {
System.out.println("Extracting files from \"minecraft_src_javadoc.jar\" to \"/src/main/java/\"...");
}
try {
if(!srcMainJava.isDirectory() && !srcMainJava.mkdirs()) {
System.err.println("ERROR: Could not create destination directory!");
return false;
}
extractJarTo(minecraftJavadocTmp, srcMainJava);
}catch(IOException ex) {
System.err.println("ERROR: could not extract \"" + minecraftJavadocTmp.getName() + ".jar\" to \"" +
srcMainJava.getAbsolutePath() + "\"!");
throw ex;
}
System.out.println("Extracting files from \"minecraft_res_patch.jar\" to \"/desktopRuntime/resources/\"...");
try {
extractJarTo(minecraftResJar, resourcesExtractTo);
}catch(IOException ex) {
System.err.println("ERROR: could not extract \"" + minecraftResJar.getName() + "\" to \"" +
resourcesExtractTo.getAbsolutePath() + "\"!");
throw ex;
}
if(applyPullRequest) {
minecraftJavadocTmp.delete();
minecraftResJar.delete();
}
System.out.println("Extracting files from \"minecraft_languages.zip\" to \"/javascript/lang/\"...");
try {
extractJarTo(mcLanguagesZip, mcLanguagesExtractTo);
}catch(IOException ex) {
System.err.println("ERROR: could not extract \"" + mcLanguagesZip.getName() + "\" to \"" +
mcLanguagesExtractTo.getAbsolutePath() + "\"!");
throw ex;
}
System.out.println("Creating eclipse project for desktop runtime...");
if(!createDesktopRuntimeProject(new File(repoSources, "setup/eclipseProjectFiles"), workspaceDirectory)) {
System.err.println("ERROR: could not create eclipse project for desktop runtime!");
return false;
}
return true;
}
public static int extractJarTo(File in, File out) throws IOException {
int cnt = 0;
try(ZipInputStream jarIn = new ZipInputStream(new FileInputStream(in))) {
ZipEntry e;
while((e = jarIn.getNextEntry()) != null) {
if(e.isDirectory()) {
continue;
}
String n = e.getName();
if(n.startsWith("/")) {
n = n.substring(1);
}
if(!n.startsWith("META-INF")) {
File o = new File(out, n);
if(!o.exists()) {
File p = o.getParentFile();
if(!p.isDirectory() && !p.mkdirs()) {
throw new IOException("Could not create directory: " + p.getAbsolutePath());
}
try(FileOutputStream os = new FileOutputStream(o)) {
IOUtils.copy(jarIn, os, 4096);
++cnt;
}
}
}
}
}
return cnt;
}
private static boolean createDesktopRuntimeProject(File templateFolderIn, File workspaceDirectory) throws Throwable {
File desktopRuntimeDirectory = new File(workspaceDirectory, "desktopRuntime");
File desktopRuntimeProjectDir = new File(desktopRuntimeDirectory, "eclipseProject");
if(!desktopRuntimeProjectDir.isDirectory() && !desktopRuntimeProjectDir.mkdirs()) {
System.err.println("ERROR: failed to create directory: \"" + desktopRuntimeProjectDir.getAbsolutePath() + "\"!");
return false;
}
File binFolder = new File(desktopRuntimeProjectDir, "bin");
if(!binFolder.isDirectory() && !binFolder.mkdir()) {
System.err.println("ERROR: failed to create directory: \"" + binFolder.getAbsolutePath() + "\"!");
return false;
}
String dotClasspathFile = FileUtils.readFileToString(new File(templateFolderIn, ".classpath"), "UTF-8");
String dotClasspathEntryFile = FileUtils.readFileToString(new File(templateFolderIn, "classpath_entry.txt"), "UTF-8");
String dotProjectFile = FileUtils.readFileToString(new File(templateFolderIn, ".project"), "UTF-8");
String debugRuntimeLaunchConfig = FileUtils.readFileToString(new File(templateFolderIn, "eaglercraftDebugRuntime.launch"), "UTF-8");
String mainClassConfFile = FileUtils.readFileToString(new File(templateFolderIn, "main_class.txt"), "UTF-8");
List<String> classpathEntries = new ArrayList();
File[] flist = desktopRuntimeDirectory.listFiles();
for(int i = 0; i < flist.length; ++i) {
File f = flist[i];
if(f.getName().endsWith(".jar")) {
classpathEntries.add(dotClasspathEntryFile.replace("${JAR_PATH}", bsToS(f.getAbsolutePath())));
}
}
dotClasspathFile = dotClasspathFile.replace("${LIBRARY_CLASSPATH}", String.join(System.lineSeparator(), classpathEntries));
FileUtils.writeStringToFile(new File(desktopRuntimeProjectDir, ".classpath"), dotClasspathFile, "UTF-8");
dotProjectFile = dotProjectFile.replace("${LWJGL_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/lwjgl/java")).getAbsolutePath()));
dotProjectFile = dotProjectFile.replace("${MAIN_SRC_FOLDER}", bsToS((new File(workspaceDirectory, "src/main/java")).getAbsolutePath()));
FileUtils.writeStringToFile(new File(desktopRuntimeProjectDir, ".project"), dotProjectFile, "UTF-8");
debugRuntimeLaunchConfig = debugRuntimeLaunchConfig.replace("${MAIN_CLASS_FILE}", mainClassConfFile);
String mainClassSubstr = mainClassConfFile.substring(mainClassConfFile.indexOf('/') + 1);
if(mainClassSubstr.endsWith(".java")) {
mainClassSubstr = mainClassSubstr.substring(0, mainClassSubstr.length() - 5);
}
mainClassSubstr = mainClassSubstr.replace('/', '.');
debugRuntimeLaunchConfig = debugRuntimeLaunchConfig.replace("${MAIN_CLASS_NAME}", mainClassSubstr);
debugRuntimeLaunchConfig = debugRuntimeLaunchConfig.replace("${WORKING_DIRECTORY}", bsToS(desktopRuntimeDirectory.getAbsolutePath()));
FileUtils.writeStringToFile(new File(desktopRuntimeProjectDir, "eaglercraftDebugRuntime.launch"), debugRuntimeLaunchConfig, "UTF-8");
File dotSettingsPrefFile = new File(templateFolderIn, "org.eclipse.jdt.core.prefs");
File destDotSettingsFolder = new File(desktopRuntimeProjectDir, ".settings");
if(!destDotSettingsFolder.isDirectory() && !destDotSettingsFolder.mkdir()) {
System.err.println("ERROR: failed to create directory: \"" + destDotSettingsFolder.getAbsolutePath() + "\"!");
return false;
}
FileUtils.copyFile(dotSettingsPrefFile, new File(destDotSettingsFolder, "org.eclipse.jdt.core.prefs"));
return true;
}
private static String bsToS(String in) {
return in.replace('\\', '/');
}
}

View File

@ -0,0 +1,84 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.init;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.commons.io.FileUtils;
import net.lax1dude.eaglercraft.v1_8.buildtools.EaglerBuildToolsConfig;
public class TaskClean {
public static boolean taskClean() {
try {
return taskClean0();
}catch(Throwable t) {
System.err.println();
System.err.println("Exception encountered while running task 'clean'!");
t.printStackTrace();
return false;
}
}
private static boolean taskClean0() throws Throwable {
File buildToolsTmp = EaglerBuildToolsConfig.getTemporaryDirectory();
File pullRequestTo = new File("pullrequest");
boolean btExist = buildToolsTmp.exists();
boolean prExist = pullRequestTo.exists();
if((btExist && !(buildToolsTmp.isDirectory() && buildToolsTmp.list().length == 0)) ||
(prExist && !(pullRequestTo.isDirectory() && pullRequestTo.list().length == 0))) {
System.out.println();
System.out.println("Notice: Clean will delete the init directory and also");
System.out.println("all of the files in the current pull request");
System.out.println();
System.out.println("you must revert all changes in the 'patches' directory of");
System.out.println("this repo back to the main repository's current commits,");
System.out.println("otherwise the 'pullrequest' command wll not work properly");
System.out.println();
System.out.print("Do you want to clean? [Y/n]: ");
String ret = "n";
try {
ret = (new BufferedReader(new InputStreamReader(System.in))).readLine();
}catch(IOException ex) {
// ?
}
ret = ret.toLowerCase();
if(!ret.startsWith("y")) {
System.out.println();
System.out.println("Ok nice, the clean will be cancelled. (thank god)");
return true;
}else {
try {
if(prExist) {
System.out.println();
System.out.println("Deleting pull request...");
FileUtils.deleteDirectory(pullRequestTo);
prExist = false;
}
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + pullRequestTo.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
try {
if(btExist) {
System.out.println();
System.out.println("Deleting init directory...");
FileUtils.deleteDirectory(buildToolsTmp);
btExist = false;
}
}catch(IOException ex) {
System.err.println("ERROR: Could not delete \"" + buildToolsTmp.getAbsolutePath() + "\"!");
ex.printStackTrace();
return false;
}
}
}
return true;
}
}

View File

@ -0,0 +1,128 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import net.lax1dude.eaglercraft.v1_8.buildtools.gui.TeaVMBinaries;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class TeaVMBridge {
private static URLClassLoader classLoader = null;
/**
* <h3>List of required options:</h3>
* <table>
* <tr><td><b>classPathEntries</b></td><td>-&gt; BuildStrategy.setClassPathEntries(List&lt;String&gt;)</td></tr>
* <tr><td><b>entryPointName</b></td><td>-&gt; BuildStrategy.setEntryPointName(String)</td></tr>
* <tr><td><b>mainClass</b></td><td>-&gt; BuildStrategy.setMainClass(String)</td></tr>
* <tr><td><b>minifying</b></td><td>-&gt; BuildStrategy.setMinifying(boolean)</td></tr>
* <tr><td><b>optimizationLevel</b></td><td>-&gt; BuildStrategy.setOptimizationLevel(TeaVMOptimizationLevel)</td></tr>
* <tr><td><b>generateSourceMaps</b></td><td>-&gt; BuildStrategy.setSourceMapsFileGenerated(boolean)</td></tr>
* <tr><td><b>targetDirectory</b></td><td>-&gt; BuildStrategy.setTargetDirectory(String)</td></tr>
* <tr><td><b>targetFileName</b></td><td>-&gt; BuildStrategy.setTargetFileName(String)</td></tr>
* </table>
* <br>
*/
public static boolean compileTeaVM(Map<String, Object> options) throws TeaVMClassLoadException, TeaVMRuntimeException {
File[] cp = TeaVMBinaries.getTeaVMCompilerClasspath();
URL[] urls = new URL[cp.length];
for(int i = 0; i < cp.length; ++i) {
try {
urls[i] = cp[i].toURI().toURL();
} catch (MalformedURLException e) {
throw new TeaVMClassLoadException("Could not resolve URL for: " + cp[i].getAbsolutePath(), e);
}
}
Method found = null;
try {
if(classLoader == null) {
classLoader = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
}
Class c = classLoader.loadClass("net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm.TeaVMBridgeImpl");
Method[] methods = c.getDeclaredMethods();
for(int i = 0; i < methods.length; ++i) {
Method m = methods[i];
if(m.getName().equals("compileTeaVM")) {
found = m;
}
}
if(found == null) {
throw new NoSuchMethodException("compileTeaVM");
}
}catch(TeaVMClassLoadException | NoSuchMethodException | ClassNotFoundException t) {
throw new TeaVMClassLoadException("Could not link TeaVM compiler!", t);
}catch(RuntimeException t) {
String msg = t.getMessage();
if(msg.startsWith("[TeaVMBridge]")) {
throw new TeaVMRuntimeException(msg.substring(13).trim(), t.getCause());
}else {
throw new TeaVMRuntimeException("Uncaught exception was thrown!", t);
}
}catch(Throwable t) {
throw new TeaVMRuntimeException("Uncaught exception was thrown!", t);
}
try {
Object ret = found.invoke(null, options);
return ret != null && (ret instanceof Boolean) && ((Boolean)ret).booleanValue();
}catch(InvocationTargetException ex) {
throw new TeaVMRuntimeException("Uncaught exception was thrown!", ex.getCause());
} catch (Throwable t) {
throw new TeaVMRuntimeException("Failed to invoke 'compileTeaVM'!", t);
}
}
public static class TeaVMClassLoadException extends RuntimeException {
public TeaVMClassLoadException(String message, Throwable cause) {
super(message, cause);
}
public TeaVMClassLoadException(String message) {
super(message);
}
}
public static class TeaVMRuntimeException extends RuntimeException {
public TeaVMRuntimeException(String message, Throwable cause) {
super(message, cause);
}
public TeaVMRuntimeException(String message) {
super(message);
}
}
public static void free() {
if(classLoader != null) {
try {
classLoader.close();
classLoader = null;
} catch (IOException e) {
System.err.println("Memory leak, failed to release TeaVM JAR ClassLoader!");
e.printStackTrace();
}
}
}
}

View File

@ -0,0 +1,28 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class FileReaderUTF extends InputStreamReader {
public FileReaderUTF(File file) throws FileNotFoundException {
super(new FileInputStream(file), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,28 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class FileWriterUTF extends OutputStreamWriter {
public FileWriterUTF(File file) throws IOException {
super(new FileOutputStream(file), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,116 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class JARSubprocess {
public static final char classPathSeperator;
static {
classPathSeperator = System.getProperty("os.name").toLowerCase().contains("windows") ? ';' : ':';
}
public static int runJava(File directory, String[] javaExeArguments, String logPrefix) throws IOException {
if(logPrefix.length() > 0 && !logPrefix.endsWith(" ")) {
logPrefix = logPrefix + " ";
}
String javaHome = System.getProperty("java.home");
if(classPathSeperator == ';') {
File javaExe = new File(javaHome, "bin/java.exe");
if(!javaExe.isFile()) {
javaExe = new File(javaHome, "java.exe");
if(!javaExe.isFile()) {
throw new IOException("Could not find /bin/java.exe equivelant on java.home! (java.home=" + javaHome + ")");
}
}
javaHome = javaExe.getAbsolutePath();
}else {
File javaExe = new File(javaHome, "bin/java");
if(!javaExe.isFile()) {
javaExe = new File(javaHome, "java");
if(!javaExe.isFile()) {
throw new IOException("Could not find /bin/java equivelant on java.home! (java.home=" + javaHome + ")");
}
}
javaHome = javaExe.getAbsolutePath();
}
String[] fullArgs = new String[javaExeArguments.length + 1];
fullArgs[0] = javaHome;
System.arraycopy(javaExeArguments, 0, fullArgs, 1, javaExeArguments.length);
ProcessBuilder exec = new ProcessBuilder(fullArgs);
exec.directory(directory);
Process ps = exec.start();
InputStream is = ps.getInputStream();
InputStream ise = ps.getErrorStream();
BufferedReader isb = new BufferedReader(new InputStreamReader(is));
BufferedReader iseb = new BufferedReader(new InputStreamReader(ise));
String isbl = "";
String isebl = "";
int maxReadPerLoop = 128;
int c = 0;
do {
boolean tick = false;
c = 0;
while(isb.ready() && (!iseb.ready() || ++c < maxReadPerLoop)) {
char cc = (char)isb.read();
if(cc != '\r') {
if(cc == '\n') {
System.out.println(logPrefix + isbl);
isbl = "";
}else {
isbl += cc;
}
}
tick = true;
}
c = 0;
while(iseb.ready() && (!isb.ready() || ++c < maxReadPerLoop)) {
char cc = (char)iseb.read();
if(cc != '\r') {
if(cc == '\n') {
System.err.println(logPrefix + isebl);
isebl = "";
}else {
isebl += cc;
}
}
tick = true;
}
if(!tick) {
try {
Thread.sleep(10l);
} catch (InterruptedException e) {
}
}
} while(ps.isAlive());
while(true) {
try {
return ps.waitFor();
} catch (InterruptedException e) {
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,18 @@
Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
NOT FOR COMMERCIAL OR MALICIOUS USE
Prohibited sharing, distribution, and repurposing these files includes but is not limited to: Publicly sharing or distributing any significant portion, modified or unmodified, of any source code files produced by the buildtools commands without minification or obfuscation, with the exception of patch files. Publicly repurposing, without permission, the source code for any file which is a part of the Eaglercraft runtime, as in any additional source files required for output of buildtools commands to run on a specific platform. Publicly repurposing, without permission, any resource file found in the project's default resource pack that does not exist in vanilla Minecraft resource packs. And, additionally, publicly repurposing, without permission, any data produced by the act of compiling or converting the files described in these previous three cases, besides the compiled or minified application (the 'game') itself.
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 HOLDER 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.
Prohibited commercial use includes selling access to any files or data (including the game itself) contained or produced by this repository, requiring the direct forced viewing of advertisement presented when a user attempts to load a compiled version of this project (or follow a hyperlink to the project's source or files derived from it, examples include using adfoc.us or adf.ly on your site), and selling content in any form that can only be accessed through the use of this project or files produced by or derived from it. Making a pay-to-win multiplayer server, for example, would be prohibited under these terms.
Malicious use includes creating and/or distributing modified versions of the game's 1.8 client (often referred to as "hacked clients") which give you an unfair advantage on multiplayer servers, creating and/or distributing modified clients which allow you to exploit bugs in EaglercraftXBungee or Eagler-compatible server software, creating and/or distributing modified clients which allow you to exploit bugs in Minecraft servers or Minecraft-compatible server software, or creating and/or distributing modified clients which allow you to exploit bugs in portions of any other software used in companion with EaglerXBungee or on an Eagler-compatible server (e.g. VIAaaS, NGINX, Caddy)
Distribution of any file or a product of compilation or conversion covered by this document must retain all existing copyright notices found within the file and folders before any modifications were made.
BY VIOLATING THESE TERMS YOU AGREE TO A BLOCK/BAN FROM ALL SOURCES OF DOCUMENTATION AND SUPPORT FOR THIS PROJECT, PERMISSION TO USE THESE FILES WAS GIVEN TO YOU IN GOOD FAITH THAT THE WORK WILL NOT BE ABUSED, AND VIOLATING THIS AGREEMENT IS A DEMONSTRATION OF A LACK OF RESPECT AND GOOD INTENTIONS ON BEHALF OF YOUR EFFORTS TO LEARN HOW TO USE THESE TOOLS CORRECTLY AND IS JUSTIFICATION FOR YOUR EXCLUSION FROM ANY AND ALL SOURCES OF DOCUMENTATION OR SUPPORT THAT WILL ASSIST YOU TO CONTINUE TO VIOLATE THESE TERMS

View File

@ -0,0 +1,86 @@
Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT,
AND ALL FILES NORMALLY FOUND IN AN UNMODIFIED MINECRAFT
RESOURCE PACK, YOU ARE NOT ALLOWED TO SHARE, DISTRIBUTE,
OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE SOFTWARE
IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE
PROJECT AUTHOR.
NOT FOR COMMERCIAL OR MALICIOUS USE
<press enter>
Prohibited sharing, distribution, and repurposing these
files includes but is not limited to: Publicly sharing or
distributing any significant portion, modified or
unmodified, of any source code files produced by the
buildtools commands without minification or obfuscation,
with the exception of patch files. Publicly repurposing,
without permission, the source code for any file which is
a part of the Eaglercraft runtime, as in any additional
source files required for output of buildtools commands to
run on a specific platform. Publicly repurposing, without
permission, any resource file found in the project's
default resource pack that does not exist in vanilla
Minecraft resource packs. And, additionally, publicly
repurposing, without permission, any data produced by the
act of compiling or converting the files described in
these previous three cases, besides the compiled or
minified application (the 'game') itself.
<press enter>
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
HOLDER 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.
<press enter>
Prohibited commercial use includes selling access to any
files or data (including the game itself) contained or
produced by this repository, requiring the direct forced
viewing of advertisement presented when a user attempts to
load a compiled version of this project (or follow a
hyperlink to the project's source or files derived from it,
examples include using adfoc.us or adf.ly on your site),
and selling content in any form that can only be accessed
through the use of this project or files produced by or
derived from it. Making a pay-to-win multiplayer server,
for example, would be prohibited under these terms.
<press enter>
Malicious use includes creating and/or distributing
modified versions of the game's 1.8 client (often referred
to as "hacked clients") which give you an unfair advantage
on multiplayer servers, creating and/or distributing
modified clients which allow you to exploit bugs in
EaglercraftXBungee or Eagler-compatible server software,
creating and/or distributing modified clients which allow
you to exploit bugs in Minecraft servers or
Minecraft-compatible server software, or creating and/or
distributing modified clients which allow you to exploit
bugs in portions of any other software used in companion
with EaglerXBungee or on an Eagler-compatible server (e.g.
VIAaaS, NGINX, Caddy)
<press enter>
Distribution of any file or a product of compilation or
conversion covered by this document must retain all
existing copyright notices found within the file and
folders before any modifications were made.
<press enter>
BY VIOLATING THESE TERMS YOU AGREE TO A BLOCK/BAN FROM
ALL SOURCES OF DOCUMENTATION AND SUPPORT FOR THIS PROJECT,
PERMISSION TO USE THESE FILES WAS GIVEN TO YOU IN GOOD
FAITH THAT THE WORK WILL NOT BE ABUSED, AND VIOLATING
THIS AGREEMENT IS A DEMONSTRATION OF A LACK OF RESPECT
AND GOOD INTENTIONS ON BEHALF OF YOUR EFFORTS TO LEARN
HOW TO USE THESE TOOLS CORRECTLY AND IS JUSTIFICATION FOR
YOUR EXCLUSION FROM ANY AND ALL SOURCES OF DOCUMENTATION
OR SUPPORT THAT WILL ASSIST YOU TO CONTINUE TO VIOLATE
THESE TERMS
<press enter>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
{
"statemgr_mappings": {
"GlStateManager.alphaFunc": "GL11.glAlphaFunc",
"GlStateManager.colorMaterial": "GL11.glColorMaterial",
"GlStateManager.depthFunc": "GL11.glDepthFunc",
"GlStateManager.blendFunc": "GL11.glBlendFunc",
"GlStateManager.tryBlendFuncSeparate": "GL14.glBlendFuncSeparate",
"GlStateManager.setFog": "GL11.glFogi",
"GlStateManager.cullFace": "GL11.glCullFace",
"GlStateManager.doPolygonOffset": "GL11.glPolygonOffset",
"GlStateManager.colorLogicOp": "GL11.glLogicOp",
"GlStateManager.texGen": "GL11.glTexGeni",
"GlStateManager.func_179105_a": "GL11.glTexGen",
"GlStateManager.setActiveTexture": "GL13.glActiveTexture",
"GlStateManager.shadeModel": "GL11.glShadeModel",
"GlStateManager.clear": "GL11.glClear",
"GlStateManager.matrixMode": "GL11.glMatrixMode",
"GlStateManager.getFloat": "GL11.glGetFloat"
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

4
buildtools/teavm-bridge/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.gradle
.settings
build
bin

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>eaglercraft-teavm-bridge</name>
<comment>Project teavm-bridge created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,24 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceCompatibility = 1.8
targetCompatibility = 1.8
sourceSets {
main {
java {
srcDir 'src/main/java'
}
}
}
repositories {
mavenCentral()
}
dependencies {
/** we use 0.6.1 due to performance issues on 7.0.0 */
implementation 'org.teavm:teavm-cli:0.6.1'
implementation 'org.teavm:teavm-tooling:0.6.1'
}

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

183
buildtools/teavm-bridge/gradlew vendored Normal file
View File

@ -0,0 +1,183 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed 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
#
# https://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.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

100
buildtools/teavm-bridge/gradlew.bat vendored Normal file
View File

@ -0,0 +1,100 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,10 @@
/*
* This file was generated by the Gradle 'init' task.
*
* The settings file is used to specify which projects to include in your build.
*
* Detailed information about configuring a multi-project build in Gradle can be found
* in the user manual at https://docs.gradle.org/6.0/userguide/multi_project_builds.html
*/
rootProject.name = 'eaglercraft-teavm-bridge'

View File

@ -0,0 +1,181 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.task.teavm;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.teavm.diagnostics.Problem;
import org.teavm.diagnostics.ProblemProvider;
import org.teavm.tooling.TeaVMTargetType;
import org.teavm.tooling.builder.BuildException;
import org.teavm.tooling.builder.BuildResult;
import org.teavm.tooling.builder.BuildStrategy;
import org.teavm.tooling.builder.ClassLoaderFactory;
import org.teavm.tooling.builder.InProcessBuildStrategy;
import org.teavm.vm.TeaVMOptimizationLevel;
import org.teavm.vm.TeaVMPhase;
import org.teavm.vm.TeaVMProgressFeedback;
import org.teavm.vm.TeaVMProgressListener;
/**
* Copyright (c) 2022 LAX1DUDE. All Rights Reserved.
*
* WITH THE EXCEPTION OF PATCH FILES, MINIFIED JAVASCRIPT, AND ALL FILES
* NORMALLY FOUND IN AN UNMODIFIED MINECRAFT RESOURCE PACK, YOU ARE NOT ALLOWED
* TO SHARE, DISTRIBUTE, OR REPURPOSE ANY FILE USED BY OR PRODUCED BY THE
* SOFTWARE IN THIS REPOSITORY WITHOUT PRIOR PERMISSION FROM THE PROJECT AUTHOR.
*
* NOT FOR COMMERCIAL OR MALICIOUS USE
*
* (please read the 'LICENSE' file this repo's root directory for more info)
*
*/
public class TeaVMBridgeImpl {
static {
System.out.println("[TeaVMBridge] Class was loaded");
}
/**
* <h3>List of required options:</h3>
* <table>
* <tr><td><b>classPathEntries</b></td><td>-&gt; BuildStrategy.setClassPathEntries(List&lt;String&gt;)</td></tr>
* <tr><td><b>entryPointName</b></td><td>-&gt; BuildStrategy.setEntryPointName(String)</td></tr>
* <tr><td><b>mainClass</b></td><td>-&gt; BuildStrategy.setMainClass(String)</td></tr>
* <tr><td><b>minifying</b></td><td>-&gt; BuildStrategy.setMinifying(boolean)</td></tr>
* <tr><td><b>optimizationLevel</b></td><td>-&gt; BuildStrategy.setOptimizationLevel(TeaVMOptimizationLevel)</td></tr>
* <tr><td><b>generateSourceMaps</b></td><td>-&gt; BuildStrategy.setSourceMapsFileGenerated(boolean)</td></tr>
* <tr><td><b>targetDirectory</b></td><td>-&gt; BuildStrategy.setTargetDirectory(String)</td></tr>
* <tr><td><b>targetFileName</b></td><td>-&gt; BuildStrategy.setTargetFileName(String)</td></tr>
* </table>
* <br>
*/
public static boolean compileTeaVM(Map<String, Object> options) throws RuntimeException {
System.out.println();
System.out.println("[TeaVMBridge] Configuring InProcessBuildStrategy:");
for(Entry<String, Object> etr : options.entrySet()) {
System.out.println("[TeaVMBridge] " + etr.getKey() + " = " + etr.getValue());
}
System.out.println();
final List<URLClassLoader> openedClassLoaders = new ArrayList();
BuildStrategy buildStrategy = new InProcessBuildStrategy(new ClassLoaderFactory() {
@Override
public ClassLoader create(URL[] var1, ClassLoader var2) {
URLClassLoader classLoader = new URLClassLoader(var1, var2);
synchronized(openedClassLoaders) {
openedClassLoaders.add(classLoader);
}
return classLoader;
}
});
long start = System.currentTimeMillis();
BuildResult result = null;
try {
buildStrategy.setClassPathEntries((List<String>)options.get("classPathEntries"));
buildStrategy.setDebugInformationGenerated(false);
buildStrategy.setEntryPointName((String)options.get("entryPointName"));
buildStrategy.setMainClass((String)options.get("mainClass"));
buildStrategy.setMaxTopLevelNames(10000); // TODO: what does this do? sounds important
buildStrategy.setMinifying(((Boolean)options.get("minifying")).booleanValue());
buildStrategy.setOptimizationLevel(TeaVMOptimizationLevel.valueOf((String)options.get("optimizationLevel")));
buildStrategy.setSourceFilesCopied(false);
buildStrategy.setSourceMapsFileGenerated(((Boolean)options.get("generateSourceMaps")).booleanValue());
buildStrategy.setTargetDirectory((String)options.get("targetDirectory"));
buildStrategy.setTargetFileName((String)options.get("targetFileName"));
buildStrategy.setTargetType(TeaVMTargetType.JAVASCRIPT);
buildStrategy.setProgressListener(new TeaVMProgressListener() {
@Override
public TeaVMProgressFeedback progressReached(int var1) {
return TeaVMProgressFeedback.CONTINUE;
}
@Override
public TeaVMProgressFeedback phaseStarted(TeaVMPhase var1, int var2) {
if(var1 == TeaVMPhase.DEPENDENCY_ANALYSIS) {
System.out.println("[TeaVMBridge] Analyzing dependencies...");
}else if(var1 == TeaVMPhase.COMPILING) {
System.out.println("[TeaVMBridge] Running compiler...");
}
return TeaVMProgressFeedback.CONTINUE;
}
});
try {
result = buildStrategy.build();
}catch(BuildException ex) {
throw new RuntimeException("[TeaVMBridge] BuildException thrown while building!", ex.getCause());
}catch(Throwable t) {
throw new RuntimeException("[TeaVMBridge] Unhandled exception thrown while building!", t);
}
}finally {
for(int i = 0, l = openedClassLoaders.size(); i < l; ++i) {
URLClassLoader cl = openedClassLoaders.get(i);
try {
cl.close();
}catch(Throwable t) {
System.out.println("[TeaVMBridge] ERROR: could not free classloader " + cl + ": " + t.toString());
}
}
}
System.out.println();
System.out.println("[TeaVMBridge] Build complete! Took " + ((System.currentTimeMillis() - start) / 1000l) + " seconds");
boolean returnError = false;
ProblemProvider prov = result.getProblems();
if(prov != null) {
List<Problem> problems = prov.getProblems();
if(problems != null && problems.size() > 0) {
returnError = true;
System.err.println("[TeaVMBridge] Encountered " + problems.size() + " problems while building:");
for(int i = 0, l = problems.size(); i < l; ++i) {
Problem p = problems.get(i);
System.err.println("[TeaVMBridge] - " + p.getSeverity() + ": " + p.getClass() + " : " + p.getLocation() + " - " + p.getText() + " - params: " + collectionToString(p.getParams()));
}
System.err.println();
}
List<Problem> severeProblems = prov.getSevereProblems();
if(severeProblems != null && severeProblems.size() > 0) {
returnError = true;
System.err.println("[TeaVMBridge] Encountered " + severeProblems.size() + " high-severity problems while building:");
for(int i = 0, l = severeProblems.size(); i < l; ++i) {
Problem p = severeProblems.get(i);
System.err.println("[TeaVMBridge] - " + p.getSeverity() + ": " + p.getClass() + " : " + p.getLocation() + " - " + p.getText() + " - params: " + collectionToString(p.getParams()));
}
System.err.println();
}
}
return !returnError;
}
private static String collectionToString(Object[] params) {
if(params.length == 0) {
return "[ ]";
}
StringBuilder ret = new StringBuilder();
ret.append("[ ");
for(int i = 0; i < params.length; ++i) {
if(i > 0) {
ret.append(" , ");
}
ret.append(params[i]);
}
ret.append(" ]");
return ret.toString();
}
}

Some files were not shown because too many files have changed in this diff Show More