upload eaglercraft u22 source (DO NOT SHARE))

This commit is contained in:
radmanplays 2024-02-10 10:21:14 +03:30
commit 7b3fd05555
3234 changed files with 322628 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##/*

687
CREDITS Normal file
View File

@ -0,0 +1,687 @@
EaglercraftX Developers
~~~~~~~~~~~~~~~~~~~~~~~
lax1dude:
- Creator of Eaglercraft
- Ported the Minecraft 1.8 src to TeaVM
- Wrote HW accelerated OpenGL 1.3 emulator
- Wrote the default shader pack
- Made the integrated PBR resource pack
- Wrote all desktop emulation code
- Wrote EaglercraftXBungee
- Wrote WebRTC Relay Server
- Wrote the patch and build system
ayunami2000:
- Many bug fixes
- WebRTC LAN worlds
- Added resource packs
- Added screen recording
- Added seamless fullscreen
- 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: ANGLE
Project Author: Google
Project URL: https://angleproject.org/
Used For: OpenGL ES 3.0 emulation in desktop debug runtime
* Copyright 2018 The ANGLE Project Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc.
* Ltd., nor the names of their 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: JOML
Project Author: httpdigest
Project URL: https://github.com/JOML-CI/JOML
Used For: Math library for some calculations used by the renderer
* The MIT License (MIT)
*
* Copyright (c) 2015-2023 JOML
*
* 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: NVIDIA FXAA
Project Author: Timothy Lottes, NVIDIA
Project URL: https://gist.github.com/kosua20/0c506b81b3812ac900048059d2383126
Used For: in-game hardware accelerated FXAA antialiasing (when enabled)
* ==============================================================================
*
*
* NVIDIA FXAA 3.11 by TIMOTHY LOTTES
*
*
* ------------------------------------------------------------------------------
* COPYRIGHT (C) 2010, 2011 NVIDIA CORPORATION. ALL RIGHTS RESERVED.
* ------------------------------------------------------------------------------
* TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED
* *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS
* OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA
* OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR
* CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR
* LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION,
* OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE
* THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGES.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Project Name: fix-webm-duration
Project Author: Yury Sitnikov
Project URL: https://github.com/yusitnikov/fix-webm-duration
Used For: Post-processing screen recordings to add durations to the file headers
* The MIT license
*
* Copyright (c) 2018 Yury Sitnikov
*
* 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.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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##"

13
LICENSE Normal file
View File

@ -0,0 +1,13 @@
Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
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.

145
README.md Normal file
View File

@ -0,0 +1,145 @@
# EaglercraftX 1.8
### Play Minecraft 1.8 in your browser, supports singleplayer and multiplayer
![EaglercraftX 1.8 Screenshot Main Menu](https://media.discordapp.net/attachments/1042594789943689327/1205041865678786581/eagler-1.8-u22-titlescreen-480p.png?ex=65d6edb1&is=65c478b1&hm=5b077d32eb06e9e2eb95792136bf74af3c51748caa1d0750370aa6eb0a77d255&)
### 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**
- **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**
- **Software 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
## Singleplayer
As of January 2024, singleplayer and shared worlds have been added to EaglercraftX 1.8.
Worlds are saved to your browser's local storage and are available even if your device does not have an internet connection. You can also import and export worlds in EaglercraftX as EPK files to copy them between devices and send them to your friends.
You can also import and export your existing vanilla Minecraft 1.8 worlds into EaglercraftX using ZIP files if you want to try playing all your old 1.8 maps in a modern browser. The glitch that caused some chunks to become corrupt when exporting worlds as vanilla in Eaglercraft 1.5.2 no longer happens in EaglercraftX 1.8, its perfect now. Beware that the inventories of LAN world players are not saved when the world is converted to vanilla, and pets (dogs, cats, horses, etc) might sometimes forget their owners due to the UUID changes.
## Shared Worlds
**This feature used to be known as "LAN Worlds" but has been renamed to "Shared Worlds" to avoid confusion**
If you would like to invite other players to join your singleplayer world and play the game together, use the "Invite" button in the pause menu. You can configure gamemode and cheats for the other players joining your world, you can also decide if you would like to hide your world from other people on your wifi network or advertise your world to them. If hidden is "off" then other people on your same wifi network will see your world listed on their game's "Multiplayer" screen with all of their servers like how sharing LAN worlds behave in vanilla Minecraft 1.8.
Once you press "Start Shared World", EaglercraftX 1.8 will give you a "join code" (usually 5 letters) to share with your friends. On a different device, go the "Multiplayer" screen and press "Direct Connect" and press "Join Shared World", enter the join code given to you when you started the shared world and press "Join World". Given a few seconds, the client should successfully be able to join your shared world from any other device on the internet that also has unrestricted internet access. If it does not work, check the "Network Settings" screen and make sure you and your friends all have the same set of shared world relay URLs configured or your clients will not be able to find each other.
If you would like to host your own relay, the JAR file and instructions can be downloaded from the "Network Settings" screen in the client. EaglercraftX 1.8 uses the same "LAN world" relay server that is used by Eaglercraft 1.5.2, if you would like the relay source code find a random copy of the Eaglercraft 1.5.2 source code and it should be located in the "sp-relay" folder. The relay has not been updated since then, it has only been renamed from "LAN world relay" to "Shared world relay".
## PBR Shaders
EaglercraftX 1.8 includes a deferred physically-based renderer modeled after the GTA V rendering engine with many new improvements and a novel raytracing technique for fast realistic reflections. It can be enabled in the "Shaders" menu in the game's options screen. Shader packs in EaglercraftX are just a component of resource packs, so any custom shaders you install will be in the form of a resource pack. EaglercraftX also comes with a very well optimized built-in PBR shader pack and also a concise built-in PBR material texture pack to give all blocks and items in the game realistic lighting and materials that looks better than most vanilla Minecraft shader packs. The default shader and texture packs were created from scratch by lax1dude, shaders packs made for vanilla Minecraft will not work in EaglercraftX and no shaders in EaglercraftX were taken from vanilla Minecraft shader packs.
## Making a Server
To make a server for EaglercraftX 1.8 the recommended software to use is EaglercraftXBungee ("EaglerXBungee") which is included in this repository in the `gateway/EaglercraftXBungee` folder. This is a plugin designed to be used with BungeeCord to allow Eaglercraft players to join your BungeeCord server. It is assumed that the reader already knows what BungeeCord is and has a working server set up that is joinable via java edition. If you don't know what BungeeCord is, please research the topic yourself first before continuing. Waterfall and FlameCord have also been tested, but EaglerXBungee was natively compiled against BungeeCord.
### Installation
Obtain the latest version of the EaglerXBungee JAR file (it can be downloaded in the client from the "Multiplayer" screen) and place it in the "plugins" folder of your BungeeCord server. It's recommended to only join native Minecraft 1.8 servers through an EaglerXBungee server but plugins like ProtocolSupport have allowed some people to join newer servers too.
Configuration files and other plugin data will be written in `plugins/EaglercraftXBungee`
### Online Mode Instructions
1. Enable `online_mode` in BungeeCord's `config.yml` file and make sure it works
2. Join the BungeeCord server using Minecraft Java Edition while logged into your Microsoft account
3. Run the `/eagler` command, it will give you a temporary login code
4. Disconnect from the server, close java edition, launch EaglercraftX 1.8
5. Set your profile username to the username of your Microsoft account
6. Go to the "Multiplayer" menu, press "Direct Connect", press "Connect to Server", then enter "ws://localhost:8081/"
7. If you are using a VPS, replace "localhost" with the IP address of the VPS when you connect
8. Press "Join Server", a login screen will be displayed, enter the temporary login code into the password field
9. EaglerXBungee will log you into the server as the Microsoft account you generated the login code with
Players using EaglercraftX will be able to see the vanilla skins of players on the server using vanilla Minecraft, but players on the server using vanilla Minecraft won't be able to see the skins of players using Eaglercraft. Instead they will see the skin of the Minecraft account that was used when the Eaglercraft player originally ran the `/eagler` command.
To disable this vanilla player skin feature and stop the plugin from downloading the textures of any player heads spawned with commands, edit the EaglercraftXBungee `settings.yml` file in the `plugins/EaglercraftXBungee` folder and change `download_vanilla_skins_to_clients` to `false`. Ratelimits configured in `settings.yml` define the maximum number of times per minute a single player is allowed to trigger profile/skin lookups and also define the maximum number of times per minute the entire server is allowed to actually perform profile/skin lookups.
By default, EaglercraftXBungee will use a local SQLite database in the server's working directory to store player skins and authentication codes. SQLite will be downloaded automatically if it is not already present. If you would like to use MySQL or something else instead, EaglercraftXBungee is JDBC-based and supports any database type that you can find a driver for. You can set the path of the database, path of the driver JAR, and the name of the driver class (example: `org.sqlite.JDBC`) for storing player skins in `settings.yml` and for storing login codes and profiles in `authservice.yml`.
### Offline Mode Instructions
By setting `online_mode` to `false` in the BungeeCord `config.yml` the authentication system will be disabled and players will no longer be required to first generate a code to log in. This should only be used for testing or if you can't get the authentication system to work. EaglercraftXBungee's skin system is supposed to be able to display SkinsRestorer skins if you plan to have vanilla players on the server but it's not guaranteed.
### Built-in HTTP server
When configuring the EaglercraftXBungee `listeners.yml` file, every listener includes an `http_server` section that can be used to configure the listener to also behave like a regular HTTP server when the websocket address is entered into a browser. If this is disabled people will get the normal "404 Websocket Upgrade Failure" instead when they accidentally type your server address into their browser. `root` defines the path to the folder containing index.html and the other files you want to host, relative to the `plugins/EaglercraftXBungee` folder. This can be useful for hosting the client if the offline download doesn't work for some reason but might slow your BungeeCord server down if lots of people are loading it all the time.
## Launch Options
The EaglercraftX 1.8 client is configured primarily through a variable called `window.eaglercraftXOpts` that must be set before the client starts up.
The default eaglercraftXOpts values is this:
const relayId = Math.floor(Math.random() * 3);
window.eaglercraftXOpts = {
demoMode: false,
container: "game_frame",
assetsURI: "assets.epk",
localesURI: "lang/",
worldsDB: "worlds",
servers: [
{ addr: "ws://localhost:8081/", name: "Local test server" }
],
relays: [
{ addr: "wss://relay.deev.is/", comment: "lax1dude relay #1", primary: relayId == 0 },
{ addr: "wss://relay.lax1dude.net/", comment: "lax1dude relay #2", primary: relayId == 1 },
{ addr: "wss://relay.shhnowisnottheti.me/", comment: "ayunami relay #1", primary: relayId == 2 }
]
};
### List of available options
- `container:` the ID of the HTML element to create the canvas in **(required)**
- `assetsURI:` the URL of the assets.epk file **(required)**
- `localesURI:` the URL where extra .lang files can be found
- `worldsDB:` the name of the IndexedDB database to store worlds in
- `demoMode:` whether to launch the game in java edition demo mode
- `servers:` a list of default servers to display on the Multiplayer screen
- `relays:` the default list of shared world relays to use for invites
- `checkShaderGLErrors:` enables more verbose opengl error logging for the shaders
- `enableDownloadOfflineButton:` whether to show a "Download Offline" button on the title screen
- `downloadOfflineButtonLink:` overrides the download link for the "Download Offline" button
- `html5CursorSupport:` enables support for showing the CSS "pointer" cursor over buttons
- `allowUpdateSvc:` enables the certificate-based update system
- `allowUpdateDL:` allows the client to download new updates it finds
- `logInvalidCerts:` print update certificates with invalid signatures to console
- `enableSignatureBadge:` show a badge on the title screen indicating if digital signature is valid
- `checkRelaysForUpdates:` proprietary feature used in offline downloads
## 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
A javascript-based modding API resembling Minecraft Forge may be implemented someday though for adding custom content to the game.

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">
"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.worldsDB) opts.worldsDB = "worlds";
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,59 @@
<!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">
"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 %%%%%%%%%%%%
const relayId = Math.floor(Math.random() * 3);
window.eaglercraftXOpts = {
demoMode: false,
container: "game_frame",
assetsURI: "assets.epk",
localesURI: "lang/",
worldsDB: "worlds",
servers: [
/* example: { addr: "ws://localhost:8081/", name: "Local test server" } */
],
relays: [
{ addr: "wss://relay.deev.is/", comment: "lax1dude relay #1", primary: relayId == 0 },
{ addr: "wss://relay.lax1dude.net/", comment: "lax1dude relay #2", primary: relayId == 1 },
{ addr: "wss://relay.shhnowisnottheti.me/", comment: "ayunami relay #1", primary: relayId == 2 }
]
};
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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,169 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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-2024 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,185 @@
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.
*
* 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.
*
*/
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,48 @@
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.
*
* 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.
*
*/
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,66 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,449 @@
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.
*
* 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.
*
*/
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,90 @@
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.
*
* 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.
*
*/
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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-2024 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"));
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(),
(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,60 @@
package net.lax1dude.eaglercraft.v1_8.buildtools.gui;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
/**
* Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,69 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,225 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,69 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,220 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
public class TeaVMBinaries {
public static class MavenJAREntry {
public final String jar;
public final String maven;
public File file;
private MavenJAREntry(String maven) {
this.jar = maven.substring(maven.lastIndexOf('/') + 1);
this.maven = maven;
}
}
public static final MavenJAREntry teavmCore = new MavenJAREntry("org/teavm/teavm-core/0.9.2/teavm-core-0.9.2.jar");
public static final MavenJAREntry teavmCli = new MavenJAREntry("org/teavm/teavm-cli/0.9.2/teavm-cli-0.9.2.jar");
public static final MavenJAREntry teavmTooling = new MavenJAREntry("org/teavm/teavm-tooling/0.9.2/teavm-tooling-0.9.2.jar");
public static final MavenJAREntry teavmPlatform = new MavenJAREntry("org/teavm/teavm-platform/0.9.2/teavm-platform-0.9.2.jar");
public static final MavenJAREntry teavmClasslib = new MavenJAREntry("org/teavm/teavm-classlib/0.9.2/teavm-classlib-0.9.2.jar");
public static final MavenJAREntry teavmInterop = new MavenJAREntry("org/teavm/teavm-interop/0.9.2/teavm-interop-0.9.2.jar");
public static final MavenJAREntry teavmJSO = new MavenJAREntry("org/teavm/teavm-jso/0.9.2/teavm-jso-0.9.2.jar");
public static final MavenJAREntry teavmJSOApis = new MavenJAREntry("org/teavm/teavm-jso-apis/0.9.2/teavm-jso-apis-0.9.2.jar");
public static final MavenJAREntry teavmJSOImpl = new MavenJAREntry("org/teavm/teavm-jso-impl/0.9.2/teavm-jso-impl-0.9.2.jar");
public static final MavenJAREntry teavmRelocatedLibsASM = new MavenJAREntry("org/teavm/teavm-relocated-libs-asm/0.9.2/teavm-relocated-libs-asm-0.9.2.jar");
public static final MavenJAREntry teavmRelocatedLibsASMAnalysis = new MavenJAREntry("org/teavm/teavm-relocated-libs-asm-analysis/0.9.2/teavm-relocated-libs-asm-analysis-0.9.2.jar");
public static final MavenJAREntry teavmRelocatedLibsASMCommons = new MavenJAREntry("org/teavm/teavm-relocated-libs-asm-commons/0.9.2/teavm-relocated-libs-asm-commons-0.9.2.jar");
public static final MavenJAREntry teavmRelocatedLibsASMTree = new MavenJAREntry("org/teavm/teavm-relocated-libs-asm-tree/0.9.2/teavm-relocated-libs-asm-tree-0.9.2.jar");
public static final MavenJAREntry teavmRelocatedLibsASMUtil = new MavenJAREntry("org/teavm/teavm-relocated-libs-asm-util/0.9.2/teavm-relocated-libs-asm-util-0.9.2.jar");
public static final MavenJAREntry teavmRelocatedLibsHPPC = new MavenJAREntry("org/teavm/teavm-relocated-libs-hppc/0.9.2/teavm-relocated-libs-hppc-0.9.2.jar");
public static final MavenJAREntry teavmRelocatedLibsRhino = new MavenJAREntry("org/teavm/teavm-relocated-libs-rhino/0.9.2/teavm-relocated-libs-rhino-0.9.2.jar");
public static final MavenJAREntry asm = new MavenJAREntry("org/ow2/asm/asm/9.5/asm-9.5.jar");
public static final MavenJAREntry asmAnalysis = new MavenJAREntry("org/ow2/asm/asm-analysis/9.5/asm-analysis-9.5.jar");
public static final MavenJAREntry asmCommons = new MavenJAREntry("org/ow2/asm/asm-commons/9.5/asm-commons-9.5.jar");
public static final MavenJAREntry asmTree = new MavenJAREntry("org/ow2/asm/asm-tree/9.5/asm-tree-9.5.jar");
public static final MavenJAREntry asmUtil = new MavenJAREntry("org/ow2/asm/asm-util/9.5/asm-util-9.5.jar");
public static final MavenJAREntry hppc = new MavenJAREntry("com/carrotsearch/hppc/0.9.1/hppc-0.9.1.jar");
public static final MavenJAREntry rhino = new MavenJAREntry("org/mozilla/rhino/1.7.14/rhino-1.7.14.jar");
public static final MavenJAREntry teavmMetaprogrammingAPI = new MavenJAREntry("org/teavm/teavm-metaprogramming-api/0.9.2/teavm-metaprogramming-api-0.9.2.jar");
public static final MavenJAREntry teavmMetaprogrammingImpl = new MavenJAREntry("org/teavm/teavm-metaprogramming-impl/0.9.2/teavm-metaprogramming-impl-0.9.2.jar");
public static final MavenJAREntry teavmJodaTime = new MavenJAREntry("joda-time/joda-time/2.12.2/joda-time-2.12.2.jar");
public static final MavenJAREntry teavmJZLIB = new MavenJAREntry("com/jcraft/jzlib/1.1.3/jzlib-1.1.3.jar");
private static final MavenJAREntry[] jarsList = new MavenJAREntry[] { teavmCore, teavmCli, teavmTooling,
teavmPlatform, teavmClasslib, teavmInterop, teavmJSO, teavmJSOApis, teavmJSOImpl, teavmRelocatedLibsASM,
teavmRelocatedLibsASMAnalysis, teavmRelocatedLibsASMCommons, teavmRelocatedLibsASMTree,
teavmRelocatedLibsASMUtil, teavmRelocatedLibsHPPC, teavmRelocatedLibsRhino, asm, asmAnalysis, asmCommons,
asmTree, asmUtil, hppc, rhino, teavmMetaprogrammingAPI, teavmMetaprogrammingImpl, teavmJodaTime,
teavmJZLIB
};
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 {
for(int i = 0; i < jarsList.length; ++i) {
jarsList[i].file = null;
}
if(url.lastIndexOf('/') != url.length() - 1) {
url += "/";
}
for(int i = 0; i < jarsList.length; ++i) {
MavenJAREntry jar = jarsList[i];
String urlConc = url + jar.maven;
try {
File f = new File(outputDir, jar.jar);
copyURLToFileCheck404(urlConc, f);
jar.file = 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 {
for(int i = 0; i < jarsList.length; ++i) {
jarsList[i].file = null;
}
discoverJars(directory);
List<String> missingJars = new ArrayList();
for(int i = 0; i < jarsList.length; ++i) {
MavenJAREntry jar = jarsList[i];
if(jar.file == null) {
missingJars.add(jar.jar);
}
}
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();
for(int j = 0; j < jarsList.length; ++j) {
if(n.equals(jarsList[j].jar)) {
jarsList[j].file = f;
}
}
}
}
}
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.file, teavmCli.file, teavmTooling.file, teavmInterop.file,
teavmRelocatedLibsASM.file, teavmRelocatedLibsASMAnalysis.file, teavmRelocatedLibsASMCommons.file,
teavmRelocatedLibsASMTree.file, teavmRelocatedLibsASMUtil.file, teavmRelocatedLibsHPPC.file,
teavmRelocatedLibsRhino.file, asm.file, asmAnalysis.file, asmCommons.file, asmTree.file, asmUtil.file,
hppc.file, rhino.file, teavmMetaprogrammingAPI.file, teavmBridge };
}
public static String[] getTeaVMRuntimeClasspath() {
return new String[] { teavmJodaTime.file.getAbsolutePath(), teavmJZLIB.file.getAbsolutePath(),
teavmClasslib.file.getAbsolutePath(), teavmInterop.file.getAbsolutePath(), teavmJSO.file.getAbsolutePath(),
teavmJSOApis.file.getAbsolutePath(), teavmJSOImpl.file.getAbsolutePath(),
teavmMetaprogrammingAPI.file.getAbsolutePath(), teavmMetaprogrammingImpl.file.getAbsolutePath(),
teavmPlatform.file.getAbsolutePath() };
}
}

View File

@ -0,0 +1,611 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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-2023 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));
}
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(),
(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,184 @@
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.io.OutputStream;
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.Map.Entry;
import java.util.WeakHashMap;
import java.util.zip.ZipEntry;
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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();
}
public static void writeIntegratedServerClass(String fileId, String fileIn, OutputStream os) throws IOException {
List<String> lines = new ArrayList(Lines.linesList(fileIn));
String str;
for(int i = 0; i < lines.size(); ++i) {
String lineIn = lines.get(i);
if(lineIn.startsWith("import net.minecraft.")) {
lines.set(i, "import net.lax1dude.eaglercraft.v1_8.sp.server.classes." + lineIn.substring(7));
}else if(lineIn.contains(" class ") || lineIn.startsWith("class ")) {
lines.addAll(i + 1, Arrays.asList(new String[] {
"",
" static {",
" __checkIntegratedContextValid(\"" + fileId + "\");",
" }",
""
}));
lines.addAll(i, Arrays.asList(new String[] {
"import static net.lax1dude.eaglercraft.v1_8.sp.server.classes.ContextUtil.__checkIntegratedContextValid;",
""
}));
break;
}else if(lineIn.startsWith("package ")) {
lines.set(i, "package net.lax1dude.eaglercraft.v1_8.sp.server.classes." + lineIn.substring(8));
}
}
IOUtils.writeLines(lines, null, os, "UTF-8");
}
}

View File

@ -0,0 +1,150 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,277 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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();
int lastSourcePos = 0;
int lastTargetPos = 0;
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();
int sourcePosRelative = sourcePos - lastSourcePos;
Chunk<String> target = delta.getTarget();
int targetPos = target.getPosition();
List<String> linesToWrite = target.getLines();
int targetLen = linesToWrite.size();
int targetPosRelative = targetPos - lastTargetPos;
output.println(blockType + " " + targetPosRelative + (targetLen > 0 ? " : " + (targetPosRelative + targetLen) : "") + " @ "
+ sourcePosRelative + (sourceLen > 0 ? " : " + (sourcePosRelative + sourceLen) : ""));
output.println();
if(targetLen > 0) {
for(int j = 0, ll = linesToWrite.size(); j < ll; ++j) {
output.println(blockPrefix + linesToWrite.get(j));
}
output.println();
}
lastSourcePos = sourcePos + sourceLen;
lastTargetPos = targetPos + targetLen;
}
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;
int lastSourcePos = 0;
int lastTargetPos = 0;
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) {
lastSourcePos += sourceStart;
lastTargetPos += targetStart;
newPatch.addDelta(makeDelta(currentDeltaType, lastSourcePos, sourceLen, lastTargetPos, targetLen, context, targetLines));
lastSourcePos += sourceLen;
lastTargetPos += targetLen;
}
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) {
lastSourcePos += sourceStart;
lastTargetPos += targetStart;
newPatch.addDelta(makeDelta(currentDeltaType, lastSourcePos, sourceLen, lastTargetPos, targetLen, context, targetLines));
lastSourcePos += sourceLen;
lastTargetPos += targetLen;
}
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,49 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,34 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,531 @@
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.
*
* 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.
*
*/
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,428 @@
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.
*
* 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.
*
*/
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,44 @@
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.
*
* 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.
*
*/
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,132 @@
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.
*
* 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.
*
*/
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,129 @@
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.
*
* 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.
*
*/
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,247 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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");
z2 = new ZipEntry("net/lax1dude/eaglercraft/v1_8/sp/server/classes/" + nm);
jarOut.putNextEntry(z2);
ApplyPatchesToZip.writeIntegratedServerClass(nm.substring(0, nm.length() - 5), txt, jarOut);
++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());
t.printStackTrace();
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,177 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,233 @@
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.
*
* 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.
*
*/
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,102 @@
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.
*
* 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.
*
*/
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,137 @@
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.
*
* 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.
*
*/
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,160 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,391 @@
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.
*
* 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.
*
*/
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.contains(" class ") || ln.contains(" enum ") || ln.contains(" interface ") || ln.contains(" @interface ") || 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);
if(cnm.startsWith("net/lax1dude/eaglercraft/v1_8/sp/server/classes/")) {
cnm = cnm.substring(48);
}
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,182 @@
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.
*
* 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.
*
*/
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,83 @@
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.
*
* 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.
*
*/
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,230 @@
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.
*
* 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.
*
*/
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,127 @@
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.
*
* 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.
*
*/
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,398 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,99 @@
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;
/**
* Copyright (c) 2022 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,130 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
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,30 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
public class FileReaderUTF extends InputStreamReader {
public FileReaderUTF(File file) throws FileNotFoundException {
super(new FileInputStream(file), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,30 @@
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-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
public class FileWriterUTF extends OutputStreamWriter {
public FileWriterUTF(File file) throws IOException {
super(new FileOutputStream(file), StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,146 @@
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;
import java.util.ArrayList;
import java.util.List;
/**
* Copyright (c) 2022-2023 lax1dude. All Rights Reserved.
*
* 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.
*
*/
public class JARSubprocess {
public static final char classPathSeperator;
static {
classPathSeperator = System.getProperty("os.name").toLowerCase().contains("windows") ? ';' : ':';
}
private static final List<Process> activeProcesses = new ArrayList();
private static boolean shutdownThreadStarted = false;
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();
synchronized(activeProcesses) {
if(!shutdownThreadStarted) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
synchronized(activeProcesses) {
for(Process proc : activeProcesses) {
try {
if(proc.isAlive()) {
proc.destroy();
}
}catch(Throwable t) {
}
}
}
}
}, "Subprocess Exit Thread"));
shutdownThreadStarted = true;
}
activeProcesses.add(ps);
}
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,3 @@
Copyright (c) 2022-2024 lax1dude, ayunami2000. All Rights Reserved.
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.

View File

@ -0,0 +1,18 @@
Copyright (c) 2022-2024 lax1dude, ayunami2000.
All Rights Reserved.
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>

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,20 @@
apply plugin: 'java'
apply plugin: 'eclipse'
sourceSets {
main {
java {
srcDir 'src/main/java'
}
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.teavm:teavm-cli:0.9.2'
implementation 'org.teavm:teavm-tooling:0.9.2'
}

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,158 @@
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.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();
BuildStrategy buildStrategy = new InProcessBuildStrategy();
long start = System.currentTimeMillis();
BuildResult result = null;
buildStrategy.setClassPathEntries((List<String>)options.get("classPathEntries"));
buildStrategy.setDebugInformationGenerated(false);
buildStrategy.setEntryPointName((String)options.get("entryPointName"));
buildStrategy.setMainClass((String)options.get("mainClass"));
buildStrategy.setMaxTopLevelNames(16000); // TODO: what does this do? sounds important
buildStrategy.setObfuscated(((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);
}
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