Compare commits

..
Author SHA1 Message Date
Christian 2f7ad51a02 Fix the ghost tile entity issue @ the client. Closes #884
Fix stairs using fungible blocks
Fix fluid draining

Updated FML:
MinecraftForge/FML@b33e7808d8 Fix for new asset URLs
MinecraftForge/FML@82851384f1 Don't delete if md5 fails. Stops derpitude with new assets stuffs.
MinecraftForge/FML@3eb3c2700c Really fix asset and library downloading -.- Wish we could switch over to gradle and not have to go through this headake.
MinecraftForge/FML@f1b3381e61 Fix the "ordering" issue on windows. Windows is poop.
2013-12-18 00:26:02 -05:00
1375 changed files with 29536 additions and 127860 deletions

No files matched your search

+2 -10
View File
@@ -1,15 +1,7 @@
* text eol=lf
*.bat text eol=crlf
*.patch text eol=lf
*.java text eol=lf
*.gradle text eol=crlf
*.patch text
*.png binary
*.gif binary
*.exe binary
*.dll binary
*.jar binary
*.lzma binary
*.zip binary
*.pyd binary
*.cfg text eol=lf
*.py text eol=lf
*.zip binary
+8 -31
View File
@@ -1,32 +1,9 @@
#eclipse
/bin
/.settings
/.classpath
#In case people make their workspace in the repo
*.DS_Store
/logs/
/*.pyc
/forge-*/
/patches-old/
/mcp/
/eclipse/
#idea
/.idea
/classes
*.iml
#gradle
/build
/.gradle
#occupational hazards
/projects/
/repo/
/buildSrc
#Patch rejects
/patches-/
*.patch.rej
# FML changelog
changelog.txt
/patches_old/
/patches_old_bak/
*.py
*.7z
/target/
/temp/
+3
View File
@@ -0,0 +1,3 @@
[submodule "fml"]
path = fml
url = https://github.com/MinecraftForge/FML.git
-22
View File
@@ -1,22 +0,0 @@
Contributing to Forge
=====================
1) Keep patches to Minecraft classes minimal. If you need a lot of things done, you may either add to relevant forge classes or make a new class.
2) An example mod must be provided for all PRs adding events/hooks to Forge. Whether it's a full mod using your proposed hooks, or just a pastebin containing a simple example, an example mod is required. Please also explain in detail what your new hook does.
3) Follow Forge coding guidelines (braces on newlines, spaces instead of tabs, etc)
For more information, refer to [the wiki](https://github.com/MinecraftForge/MinecraftForge/wiki/If-you-want-to-contribute-to-Forge)
Contributor License Agreement
=============================
- You grant Forge a license to use your code contributed to the primary codebase (everything **not** under patches) in Forge, under the LGPLv2.1 license.
- You assign copyright ownership of your contributions to the patches codebase (everything under patches) to Forge, where it will be licensed under the LGPLv2.1 license.
Additionally, while 1.9.4 is being maintained, you will be asked to acknowledge these two additional clauses.
- You grant Forge a license to use your code contributed to the primary codebase (everything **not** under patches) in Forge, under the MinecraftForge license.
- You grant assign copyright ownership of your contributions to the patches codebase (everything under patches) to Forge, where it will be licensed under the MinecraftForge license.
"Forge" is Forge Development LLC, a legally incorporated entity in Oregon, USA.
-28
View File
@@ -1,28 +0,0 @@
This is Forge Mod Loader.
You can find the source code at all times at https://github.com/MinecraftForge/FML
This minecraft mod is a clean open source implementation of a mod loader for minecraft servers
and minecraft clients.
The code is authored by cpw.
It began by partially implementing an API defined by the client side ModLoader, authored by Risugami.
http://www.minecraftforum.net/topic/75440-
This support has been dropped as of Minecraft release 1.7, as Risugami no longer maintains ModLoader.
It also contains suggestions and hints and generous helpings of code from LexManos, author of MinecraftForge.
http://www.minecraftforge.net/
Additionally, it contains an implementation of topological sort based on that
published at http://keithschwarz.com/interesting/code/?dir=topological-sort
It also contains code from the Maven project for performing versioned dependency
resolution. http://maven.apache.org/
It also contains a partial repackaging of the javaxdelta library from http://sourceforge.net/projects/javaxdelta/
with credit to it's authors.
Forge Mod Loader downloads components from the Minecraft Coder Pack
(http://mcp.ocean-labs.de/index.php/Main_Page) with kind permission from the MCP team.
-491
View File
@@ -1,491 +0,0 @@
This minecraft mod, Forge Mod Loader, including all parts herein except as noted below,
is licensed under the GNU LGPL v2.1 or later.
Homepage: https://github.com/MinecraftForge/FML
This software includes portions from the Apache Maven project at
http://maven.apache.org/ specifically the ComparableVersion.java code. It is
included based on guidelines at
http://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html
with notices intact. The only change is a non-functional change of package name.
This software contains a partial repackaging of javaxdelta, a BSD licensed program for generating
binary differences and applying them, sourced from the subversion at http://sourceforge.net/projects/javaxdelta/
authored by genman, heikok, pivot.
The only changes are to replace some Trove collection types with standard Java collections, and repackaged.
=== MCP Data ===
This software includes data from the Minecraft Coder Pack (MCP), with kind permission
from them. The license to MCP data is not transitive - distribution of this data by
third parties requires independent licensing from the MCP team. This data is not
redistributable without permission from the MCP team.
=== Sharing ===
I grant permission for some parts of FML to be redistributed outside the terms of the LGPL, for the benefit of
the minecraft modding community. All contributions to these parts should be licensed under the same additional grant.
-- Runtime patcher --
License is granted to redistribute the runtime patcher code (common/cpw/mods/fml/patcher and subdirectories) under
any alternative open source license as classified by the OSI (http://opensource.org/licenses)
-- ASM transformers --
License is granted to redistribute the ASM transformer code (common/cpw/mods/fml/common/asm/ and subdirectories)
under any alternative open source license as classified by the OSI (http://opensource.org/licenses)
========
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
-483
View File
@@ -1,483 +0,0 @@
Minecraft Forge is licensed under the terms of the LGPL 2.1 found
here http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt and copied
below.
A note on authorship:
All source artifacts are property of their original author, with
the exclusion of the contents of the patches directory and others
copied from it from time to time. Authorship of the contents of
the patches directory is retained by the Minecraft Forge project.
This is because the patches are partially machine generated
artifacts, and are changed heavily due to the way forge works.
Individual attribution within them is impossible.
Consent:
All contributions to Forge must consent to the release of any
patch content to the Forge project.
A note on infectivity:
The LGPL is chosen specifically so that projects may depend on Forge
features without being infected with its license. That is the
purpose of the LGPL. Mods and others using this code via ordinary
Java mechanics for referencing libraries are specifically not bound
by Forge's license for the Mod code.
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
-60
View File
@@ -1,60 +0,0 @@
# How to install Forge: For Players
Go to [http://files.minecraftforge.net](http://files.minecraftforge.net)
and select the minecraft version you wish to get forge for from the list.
You can download the installer for the *Recommended Build* or the
*Lastest build* there. Latest builds may have newer features but may be
more unstable as a result. The installer will attempt to install forge
into your vanilla launcher environment, where you can then create a new
profile using that version and play the game!
Here is a short video from Rorax showing how to install and setup Forge.
[![HOWTO Install Forge](https://img.youtube.com/vi/lB3ArN_-3Oc/0.jpg)](https://www.youtube.com/watch?v=lB3ArN_-3Oc)
For support and user questions, visit [http://www.minecraftforge.net](http://www.minecraftforge.net).
# How to install Forge: For Modders
If you wish to setup a new mod for Forge, visit
[http://files.minecraftforge.net](http://files.minecraftforge.net) and
select the **MDK** download.
This is the `Modder Developer Kit` - basically, an example mod with all
the tooling needed to create a Forge mod workspace ready for use in your
IDE of choice.
Here is a short video from @cpw showing how to install and setup the MDK
in Intellij.
[![HOWTO Install MDK](https://img.youtube.com/vi/PfmlNiHonV0/0.jpg)](https://www.youtube.com/watch?v=PfmlNiHonV0)
# How to install Forge: For those wishing to work on Forge itself
If you wish to actually inspect Forge, submit PRs or otherwise work
with Forge itself, you're in the right place! Clone this (either
directly, or make a Fork first if you want to make a PR) and run
```gradlew.bat setup``` or ```gradlew setup```. This will download and
setup all the bits you need to have a functional Forge workspace.
Here is a short video from @cpw showing how to install and setup Forge
in Intellij.
[![HOWTO Install MDK](https://img.youtube.com/vi/yanCpy8p2ZE/0.jpg)](https://www.youtube.com/watch?v=yanCpy8p2ZE)
## Pull requests
Pull requests should target the current default branch. Currently, that is
the 1.10.x branch for Minecraft 1.10.2.
If you intend to modify a minecraft patch, or add a new one, always run
```gradlew genPatches``` to generate your patch and validate that you
are not doing anything unexpected in your patch.
### Contributor License Agreement
As stated in the (https://github.com/MinecraftForge/MinecraftForge/blob/1.10.x/LICENSE-new.txt)
file, we require all contributors to acknowledge the Forge Contributor
License Agreement. Please ensure you have a valid email address
associated with your github account to do this. If you have previously
signed it, you should be OK.
-36
View File
@@ -1,36 +0,0 @@
*** HOW TO INSTALL ***
For Mod Users:
Download the latest installer from http://files.minecraftforge.net and follow instructions given by the installer.
For Mod Devs:
Download the latest Forge source distribution from http://files.minecraftforge.net and unzip it to a folder.
Open a command prompt, navigate to the directory where you unzipped the Forge sources, and run:
If you have Gradle: gradle setupDevWorkspace
If you DO NOT have Gradle installed:
Windows: ./gradlew.bat setupDevWorkspace
MacOS/Linux: ./gradlew setupDevWorkspace
If you wish to use the Eclipse IDE, run gradle eclipse instead of gradle setupDevWorkspace, or install the Gradle plugin for Eclipse and import the Forge source folder as a Gradle project.
To get the decompiled classes:
If you have Gradle: gradle setupDecompWorkspace
If you DO NOT have Gradle installed:
Windows: ./gradlew.bat setupDecompWorkspace
MacOS/Linux: ./gradlew setupDecompWorkspace
For Contributors: (Note: This assumes you have Gradle installed. If you don't, use ./gradlew(.bat) instead of gradle.
Clone this repository to a folder.
Open a command prompt and navigate to the folder where you cloned this repo.
Run gradle setupForge to setup your development environment.
To use Eclipse, point your Eclipse workspace at the eclipse folder inside the repo.
Requirements (for both mod devs and contributors):
You must have a JDK installed and accessible.
If you do not wish to use the gradle wrapper, you can install Gradle from http://www.gradle.org/ .
+95
View File
@@ -0,0 +1,95 @@
import os
import sys
import fnmatch
import shlex
import difflib
import time, subprocess
from optparse import OptionParser
def cmdsplit(args):
if os.sep == '\\':
args = args.replace('\\', '\\\\')
return shlex.split(args)
def main():
print("Applying patches")
parser = OptionParser()
parser.add_option('-m', '--mcp-dir', action='store', dest='mcp_dir', help='Path to MCP', default=None)
parser.add_option('-p', '--patch-dir', action='store', dest='patch_dir', help='Patches Directory', default=None)
parser.add_option('-t', '--target-dir', action='store', dest='target_dir', help='Target Directory', default=None)
options, _ = parser.parse_args()
if options.mcp_dir is None:
print 'Must supply MCP directory with --mcp-dir'
return
elif options.patch_dir is None:
print 'Must supply patches directory with --patch-dir'
return
elif options.target_dir is None:
print 'Must supplt target directory with --target-dir'
return
print "Applying patches from '%s' to '%s'" % (options.patch_dir, options.target_dir)
apply_patches(options.mcp_dir, options.patch_dir, options.target_dir)
def apply_patches(mcp_dir, patch_dir, target_dir, find=None, rep=None):
# Attempts to apply a directory full of patch files onto a target directory.
sys.path.append(mcp_dir)
temp = os.path.abspath('temp.patch')
cmd = cmdsplit('patch -p2 -i "%s" ' % temp)
if os.name == 'nt':
applydiff = os.path.abspath(os.path.join(mcp_dir, 'runtime', 'bin', 'applydiff.exe'))
cmd = cmdsplit('"%s" -uf -p2 -i "%s"' % (applydiff, temp))
for path, _, filelist in os.walk(patch_dir, followlinks=True):
for cur_file in fnmatch.filter(filelist, '*.patch'):
patch_file = os.path.normpath(os.path.join(patch_dir, path[len(patch_dir)+1:], cur_file))
target_file = os.path.join(target_dir, fix_patch(patch_file, temp, find, rep))
process = subprocess.Popen(cmd, cwd=target_dir, bufsize=-1)
process.communicate()
if os.path.isfile(temp):
os.remove(temp)
def fix_patch(in_file, out_file, find=None, rep=None):
#Fixes the following issues in the patch file if they exist:
# Normalizes the path seperators for the current OS
# Normalizes the line endings
# Returns the path that the file wants to apply to
in_file = os.path.normpath(in_file)
if out_file is None:
tmp_file = in_file + '.tmp'
else:
out_file = os.path.normpath(out_file)
tmp_file = out_file
dir_name = os.path.dirname(out_file)
if dir_name:
if not os.path.exists(dir_name):
os.makedirs(dir_name)
file = 'not found'
with open(in_file, 'rb') as inpatch:
with open(tmp_file, 'wb') as outpatch:
for line in inpatch:
line = line.rstrip('\r\n')
if line[:3] in ['+++', '---', 'Onl', 'dif']:
if not find == None and not rep == None:
line = line.replace('\\', '/').replace(find, rep).replace('/', os.sep)
else:
line = line.replace('\\', '/').replace('/', os.sep)
outpatch.write(line + os.linesep)
else:
outpatch.write(line + os.linesep)
if line[:3] == '---':
file = line[line.find(os.sep, line.find(os.sep)+1)+1:]
if out_file is None:
shutil.move(tmp_file, in_file)
return file
if __name__ == '__main__':
main()
-395
View File
@@ -1,395 +0,0 @@
buildscript {
repositories {
mavenCentral()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT'
}
}
repositories {
maven {
name = "local"
url = "file:///home/cpw/projects/repo"
}
}
apply plugin: "maven"
apply plugin: "net.minecraftforge.gradle.patcher"
apply plugin: "net.minecraftforge.gradle.launch4j"
minecraft.version = "1.10.2"
minecraft {
mappings = 'snapshot_nodoc_20160518'
workspaceDir = "projects"
versionJson = "jsons/${minecraft.version}-dev.json"
buildUserdev = true
buildInstaller = true
installerVersion = "1.4"
def common = {
patchPrefixOriginal "../src-base/minecraft"
patchPrefixChanged "../src-work/minecraft"
mainClassClient "net.minecraft.launchwrapper.Launch"
tweakClassClient "net.minecraftforge.fml.common.launcher.FMLTweaker"
mainClassServer "net.minecraft.launchwrapper.Launch"
tweakClassServer "net.minecraftforge.fml.common.launcher.FMLServerTweaker"
}
projects {
forge {
rootDir "."
patchDir "patches/minecraft"
patchAfter "clean"
genPatchesFrom "clean"
genMcpPatches = false
applyMcpPatches = false
s2sKeepImports = true
with common
}
}
}
group = 'net.minecraftforge'
version = getVersionFromJava(file("src/main/java/net/minecraftforge/common/ForgeVersion.java"))
extractForgeSources { exclude "**/SideOnly.java", "**/Side.java" }
extractForgeResources { exclude "**/log4j2.xml" }
genGradleProjects { addTestCompileDep "junit:junit:4.12" }
processJson {
releaseJson = "jsons/${minecraft.version}-rel.json"
addReplacements([
"@minecraft_version@": project.minecraft.version,
"@version@": project.version,
"@project@": "forge",
"@artifact@": "net.minecraftforge:forge:${project.version}",
"@universal_jar@": { outputJar.archiveName },
"@timestamp@": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
])
}
task changelog(type: JenkinsChangelog) {
// skip if there is no forge jenkins pass
onlyIf {
project.hasProperty('forgeJenkinsPass')
// Not sure what abrar was trying to do here...
//project.file("build/distributions/${project.name}-${project.version}-changelog.txt").text = ""
}
outputs.upToDateWhen { false } // never up to date
serverRoot = "http://ci.jenkins.minecraftforge.net/"
jobName = "minecraftforge"
targetBuild = System.env['BUILD_NUMBER'] ?: project.ext.properties.buildNumber ?:0;
authName = "console_script"
authPassword = project.hasProperty('forgeJenkinsPass') ? project.getProperty('forgeJenkinsPass') : "";
output = "build/distributions/${project.name}-${project.version}-changelog.txt"
}
task crowdin(type: CrowdinDownload) {
output = "build/crowdin.zip"
projectId = 'minecraft-forge'
extract = false // we wanna keep it as a zip. not extract it to a folder named "crowdin.zip"
// task auomatically skips if this is null
if (project.hasProperty('crowdinKey'))
apiKey = project.crowdinKey
}
def extraTxts = [
changelog, // yeah we can do thi, because gradle and groovy are awesome
"CREDITS-fml.txt",
"LICENSE-new.txt",
"MinecraftForge-Credits.txt",
"Paulscode SoundSystem CodecIBXM License.txt",
"Paulscode IBXM Library License.txt"
]
outputJar {
classifier = 'universal'
from extraTxts
// add crowdin locales
from { crowdin.getDidWork() ? zipTree(crowdin.output) : null}
dependsOn 'crowdin'
manifest.attributes([
"Main-Class": "net.minecraftforge.fml.relauncher.ServerLaunchWrapper",
"TweakClass": "net.minecraftforge.fml.common.launcher.FMLTweaker",
"Class-Path": getServerClasspath(file("jsons/${minecraft.version}-rel.json"))
])
}
installer {
classifier = 'installer'
from extraTxts
from "src/main/resources/forge_logo.png"
rename "forge_logo\\.png", "big_logo.png"
}
task signUniversal(type: SignJar, dependsOn: 'outputJar') {
onlyIf {
project.hasProperty('jarsigner')
}
def jarsigner = [:];
if (project.hasProperty('jarsigner'))
jarsigner = project.jarsigner;
alias = 'forge'
exclude "paulscode/**"
storePass = jarsigner.storepass
keyPass = jarsigner.keypass
keyStore = jarsigner.keystore
inputFile = outputJar.archivePath
outputFile = outputJar.archivePath
}
uploadArchives.dependsOn signUniversal
build.dependsOn signUniversal
installer.dependsOn signUniversal
// MDK package
import org.apache.tools.ant.filters.ReplaceTokens
task makeMdk(type: Zip) {
baseName = project.name
classifier = "mdk"
version = project.version
destinationDir = file('build/distributions')
from 'gradlew'
from 'gradlew.bat'
into ('gradle') {
from 'gradle'
}
into ('eclipse') {
from 'mdk/eclipse'
}
from changelog.output
from ('mdk') {
filter(ReplaceTokens, tokens: [
VERSION: project.version,
MAPPINGS: minecraft.mappings.replace('nodoc_', '')
])
exclude 'eclipse'
rename 'gitignore\\.txt', '.gitignore'
from 'MinecraftForge-Credits.txt'
from 'LICENSE-new.txt'
from 'Paulscode IBXM Library License.txt'
from 'Paulscode SoundSystem CodecIBXM License.txt'
from 'CREDITS-fml.txt'
}
}
tasks.build.dependsOn makeMdk
// launch4j
launch4j {
jar = installer.archivePath.canonicalPath
outfile = file("build/distributions/${project.name}-${project.version}-installer-win.exe").canonicalPath
icon = file('icon.ico').canonicalPath
manifest = file('l4jManifest.xml').canonicalPath
jreMinVersion = '1.6.0'
initialHeapPercent = 5;
maxHeapPercent = 100;
}
tasks.generateXmlConfig.dependsOn installer
tasks.build.dependsOn 'launch4j'
// MAVEN
artifacts {
archives changelog.output
archives file("build/distributions/${project.name}-${project.version}-installer-win.exe")
archives makeMdk
}
task ciWriteBuildNumber << {
def file = file("src/main/java/net/minecraftforge/common/ForgeVersion.java");
def bn = System.getenv("BUILD_NUMBER")?:project.ext.properties.buildNumber?:0;
def outfile = "";
def ln = "\n"; //Linux line endings because we're on git!
file.eachLine{ String s ->
if (s.matches("^ public static final int buildVersion = [\\d]+;\$"))
s = " public static final int buildVersion = ${bn};";
if (s.matches('^ public static final String mcVersion = "[^\\"]+";'))
s = " public static final String mcVersion = \"${minecraft.version}\";";
outfile += (s+ln);
}
file.write(outfile);
}
uploadArchives {
repositories.mavenDeployer {
dependsOn 'build'
if (project.hasProperty('forgeMavenPass'))
{
repository(url: "http://files.minecraftforge.net/maven/manage/upload") {
authentication(userName: "forge", password: project.getProperty('forgeMavenPass')) // the elvis operator. look it up.
}
}
else
{
// local repo folder. Might wanna juset use gradle install if you wanans end it to maven-local
repository(url: 'file://localhost/' + project.file('repo').getAbsolutePath())
}
pom {
groupId = project.group
version = project.version
artifactId = project.archivesBaseName
project {
name project.archivesBaseName
packaging 'jar'
description 'Minecraft Forge API'
url 'https://github.com/MinecraftForge/MinecraftForge'
scm {
url 'https://github.com/MinecraftForge/MinecraftForge'
connection 'scm:git:git://github.com/MinecraftForge/MinecraftForge.git'
developerConnection 'scm:git:[email protected]:MinecraftForge/MinecraftForge.git'
}
issueManagement {
system 'github'
url 'https://github.com/MinecraftForge/MinecraftForge/issues'
}
licenses {
license {
name 'Forge Public License'
url 'https://raw.github.com/MinecraftForge/MinecraftForge/master/MinecraftForge-License.txt'
distribution 'repo'
}
}
developers {
developer {
id 'cpw'
name 'cpw'
roles { role 'developer' }
}
developer {
id 'LexManos'
name 'Lex Manos'
roles { role 'developer' }
}
developer {
id 'AbrarSyed'
name 'Abrar Syed'
roles { role 'contributor' }
}
}
}
}
}
}
// HELPER METHODS
import groovy.json.JsonSlurper;
String getServerClasspath(File file)
{
def node = new JsonSlurper().parse(file);
def out = new StringBuilder()
node.versionInfo.libraries.each { lib ->
if (lib.serverreq)
{
// group : artifact : version
def split = lib.name.split(':')
def group = split[0].replace('.', '/')
def artifact = split[1]
def version = split[2]
out += "libraries/$group/$artifact/$version/$artifact-${version}.jar "
}
}
out += "minecraft_server.${minecraft.version}.jar"
return out.toString();
}
String getVersionFromJava(File file)
{
String major = "0";
String minor = "0";
String revision = "0";
String build = "0";
String prefix = "public static final int";
file.eachLine{ String s ->
s = s.trim();
if (s.startsWith(prefix))
{
s = s.substring(prefix.length(), s.length() - 1);
s = s.replace('=', ' ').replace("Version", "").replaceAll(" +", " ").trim();
String[] pts = s.split(" ");
if (pts[0].equals("major")) major = pts[pts.length - 1];
else if (pts[0] == "minor") minor = pts[pts.length - 1];
else if (pts[0] == "revision") revision = pts[pts.length - 1];
}
}
build = System.getenv("BUILD_NUMBER") ?: project.ext.properties.buildNumber ?: 0
String branch = null;
if (!System.getenv().containsKey("GIT_BRANCH"))
{
// TODO: use grgit - Tried to switch 07/07/16 - jgit broken on windows?
branch = "git rev-parse --abbrev-ref HEAD".execute().text.trim()
}
else
{
branch = System.getenv("GIT_BRANCH");
branch = branch.substring(branch.lastIndexOf('/') + 1);
}
def out = "${minecraft.version.replace('-', '_')}-$major.$minor.$revision.$build"
if (branch && branch != 'master' && branch != 'HEAD' && branch != minecraft.version && branch != minecraft.version + '.0')
{
if (!(branch.endsWith('.x') && minecraft.version.startsWith(branch.substring(0, branch.length() -1))))
out += "-$branch"
}
return out;
}
task resetBuildNumber << {
project.ext.properties.buildNumber = 0;
ciWriteBuildNumber.execute()
}
// re-add old tasks for jenkins compat
// should be remvoed, and the jenkisn fixed when no longer building with FG 1.2
task setupForge { dependsOn 'setup', 'ciWriteBuildNumber' }
task buildPackages { dependsOn 'build' }
//Temporary hack to fix compile errors caused by mappings shading in Bootstrap
/*
task fixParams << {
logger.lifecycle('Fixing param names!')
def params = new File(extractMcpMappings.destinationDir, 'params.csv')
def text = params.text
text = text.replaceAll('p_180276_1_,biome,', 'p_180276_1_,biomeIn,')
params.write(text)
}
fixParams.dependsOn('extractMcpMappings')
extractMcpMappings.finalizedBy('fixParams')
*/
+34
View File
@@ -0,0 +1,34 @@
import os, os.path, sys
from optparse import OptionParser
forge_dir = os.path.dirname(os.path.abspath(__file__))
mcp_dir = os.path.abspath('..')
from forge import build_forge_dev
def main():
parser = OptionParser()
parser.add_option('-m', '--mcp-dir', action='store', dest='mcp_dir', help='MCP Path', default=None)
parser.add_option('-b', '--build', action='store', dest='build', help='Build number', default=None)
options, _ = parser.parse_args()
build_num = 0
if not options.build is None:
try:
build_num = int(options.build)
except:
pass
fml_dir = os.path.join(forge_dir, 'fml')
mcp_dir = os.path.join(forge_dir, 'mcp')
if not options.mcp_dir is None:
mcp_dir = os.path.abspath(options.mcp_dir)
elif os.path.isfile(os.path.join('..', 'runtime', 'commands.py')):
mcp_dir = os.path.abspath('..')
sys.exit(build_forge_dev(mcp_dir, forge_dir, fml_dir, build_num))
if __name__ == '__main__':
main()
+113
View File
@@ -0,0 +1,113 @@
import os, os.path, sys, re
import json, urllib2
from pprint import pprint
from urlparse import urlparse
import base64
import optparse, ast
class PreemptiveBasicAuthHandler(urllib2.BaseHandler):
def __init__(self, password_mgr=None):
if password_mgr is None:
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
self.passwd = password_mgr
self.add_password = self.passwd.add_password
def http_request(self,req):
uri = req.get_full_url()
user, pw = self.passwd.find_user_password(None,uri)
if pw is None: return req
raw = "%s:%s" % (user, pw)
auth = 'Basic %s' % base64.b64encode(raw).strip()
req.add_unredirected_header('Authorization', auth)
return req
def https_request(self,req):
return self.http_request(req)
def read_url(url):
handler = PreemptiveBasicAuthHandler()
handler.add_password(None, 'ci.jenkins.minecraftforge.net', 'console_script', 'dc6d48ca20a474beeac280a9a16a926e')
file = urllib2.build_opener(handler).open(url)
data = file.read()
file.close()
return data
def getBuildInfo(url, current_version=None):
data = read_url(url)
data = ast.literal_eval(data)['allBuilds']
data = sorted(data, key=lambda key: key['number'], reverse=False)
items = []
output = []
for build in data:
build['actions'] = filter(lambda act: act is not None, build['actions'])
build['actions'] = filter(lambda act: 'text' in act, build['actions'])
build['actions'] = filter(lambda act: not ' ' in act['text'], build['actions'])
if len(build['actions']) == 0:
build['version'] = current_version
current_version = None
else:
build['version'] = build['actions'][0]['text']
build['items'] = build['changeSet']['items']
for item in build['items']:
item['author'] = item['author']['fullName']
if build['result'] != 'SUCCESS':
items += build['items']
else:
build['items'] = items + build['items']
items = []
output += [build]
build.pop('changeSet')
build.pop('actions')
return sorted(output, key=lambda key: key['number'], reverse=True)
def add_latest_build(url, builds, current_version=None):
data = read_url(url)
data = ast.literal_eval(data)
number = data['number']
if builds[0]['number'] == data['number']:
return builds
for item in data['changeSet']['items']:
item['author'] = item['author']['fullName']
build = {
'number' : data['number'],
'result' : 'SUCCESS', #Currently build should always be success... Else things derp after words
'version' : current_version,
'items' : data['changeSet']['items']
}
return [build] + builds
def make_changelog(job_path, target_build, change_file, current_version=None):
builds = getBuildInfo('%s/api/python?tree=allBuilds[result,number,actions[text],changeSet[items[author[fullName],comment]]]&pretty=true' % job_path, current_version)
builds = add_latest_build('%s/lastBuild/api/python?pretty=true&tree=number,changeSet[items[author[fullName],comment]]' % job_path, builds, current_version)
log = [ "Changelog:" ]
for build in builds:
if int(build['number']) > target_build: continue
if len(build['items']) == 0: continue
log.append('')
if build['version'] is None:
log.append('Build %s' % build['number'])
else:
log.append('Build %s' % build['version'])
for change in build['items']:
comments = filter(lambda cmt: len(cmt) > 0, change['comment'].split('\n'))
if len(comments) > 1:
log.append('\t' + change['author'])
for comment in comments:
log.append('\t\t' + comment)
elif len(comments) == 1:
log.append('\t%s: %s' % (change['author'], comments[0]))
file = open(change_file, 'wb')
for line in log:
file.write('%s\n' % line)
file.close()
if __name__ == '__main__':
make_changelog("http://ci.jenkins.minecraftforge.net/job/minecraftforge/", 70000, 'changelog.txt', 'pinecone')
File renamed without changes.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

@@ -10,7 +10,6 @@ public class Channel {
private int[] global_volume, current_note;
private boolean linear_periods, fast_volume_slides, key_on, silent;
private int sample_idx, sample_frac, step, left_gain, right_gain;
@SuppressWarnings("unused") //Forge
private int volume, panning, fine_tune, period, porta_period, key_add;
private int tremolo_speed, tremolo_depth, tremolo_tick, tremolo_wave, tremolo_add;
private int vibrato_speed, vibrato_depth, vibrato_tick, vibrato_wave, vibrato_add;
@@ -10,8 +10,8 @@ public class Envelope {
set_num_points( 1 );
}
public void set_num_points( int num_points ) {
//int point; Forge: Unused
public void set_num_points( int num_points ) {
int point;
if( num_points <= 0 ) {
num_points = 1;
}
@@ -69,8 +69,7 @@ public class FastTracker2 {
return module;
}
private static Pattern read_xm_pattern( DataInput data_input, int num_channels ) throws IOException {
@SuppressWarnings("unused") //Forge
private static Pattern read_xm_pattern( DataInput data_input, int num_channels ) throws IOException {
int pattern_header_length, packing_type, num_rows, pattern_data_length;
byte[] structure_header, pattern_header, pattern_data;
Pattern pattern;
@@ -85,8 +85,8 @@ public class IBXM {
clear_vol_ramp_buffer();
}
public void seek( int sample_position ) {
//int idx; Forge, Unused
public void seek( int sample_position ) {
int idx;
set_sequence_index( 0, 0 );
next_tick();
while( sample_position > tick_length_samples ) {
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -104,8 +104,7 @@ public class Player {
}
private class Driver implements Runnable {
@Override
public void run() {
public void run() {
if( running ) return;
try {
output_line.open();
File renamed without changes.
File renamed without changes.
@@ -57,9 +57,8 @@ public class ScreamTracker3 {
return s3m_identifier.equals( "SCRM" );
}
public static Module load_s3m( byte[] header_96_bytes, DataInput data_input ) throws IOException {
public static Module load_s3m( byte[] header_96_bytes, DataInput data_input ) throws IOException {
int num_pattern_orders, num_instruments, num_patterns, num_channels;
@SuppressWarnings("unused") //Forge
int flags, tracker_version, master_volume, panning, channel_config, sequence_length;
int instrument_idx, pattern_idx, channel_idx, order_idx, panning_offset;
boolean signed_samples, stereo_mode, default_panning;
@@ -1,22 +1,3 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client;
import java.util.List;
@@ -28,21 +9,19 @@ import net.minecraft.command.CommandHandler;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.WrongUsageException;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ChatMessageComponent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.CommandEvent;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
import static net.minecraft.util.text.TextFormatting.*;
import cpw.mods.fml.client.FMLClientHandler;
import static net.minecraft.util.EnumChatFormatting.*;
/**
* The class that handles client-side chat commands. You should register any
* commands that you want handled on the client with this command handler.
*
*
* If there is a command with the same name registered both on the server and
* client, the client takes precedence!
*
*
*/
public class ClientCommandHandler extends CommandHandler
{
@@ -51,8 +30,8 @@ public class ClientCommandHandler extends CommandHandler
public String[] latestAutoComplete = null;
/**
* @return 1 if successfully executed, -1 if no permission or wrong usage,
* 0 if it doesn't exist or it was canceled (it's sent to the server)
* @return 1 if successfully executed, 0 if wrong usage, it doesn't exist or
* it was canceled.
*/
@Override
public int executeCommand(ICommandSender sender, String message)
@@ -68,7 +47,7 @@ public class ClientCommandHandler extends CommandHandler
String[] args = new String[temp.length - 1];
String commandName = temp[0];
System.arraycopy(temp, 1, args, 0, args.length);
ICommand icommand = getCommands().get(commandName);
ICommand icommand = (ICommand) getCommands().get(commandName);
try
{
@@ -77,52 +56,55 @@ public class ClientCommandHandler extends CommandHandler
return 0;
}
if (icommand.checkPermission(this.getServer(), sender))
if (icommand.canCommandSenderUseCommand(sender))
{
CommandEvent event = new CommandEvent(icommand, sender, args);
if (MinecraftForge.EVENT_BUS.post(event))
{
if (event.getException() != null)
if (event.exception != null)
{
throw event.getException();
throw event.exception;
}
return 0;
}
this.tryExecute(sender, args, icommand, message);
icommand.processCommand(sender, args);
return 1;
}
else
{
sender.addChatMessage(format(RED, "commands.generic.permission"));
sender.sendChatToPlayer(format("commands.generic.permission").setColor(RED));
}
}
catch (WrongUsageException wue)
{
sender.addChatMessage(format(RED, "commands.generic.usage", format(RED, wue.getMessage(), wue.getErrorObjects())));
sender.sendChatToPlayer(format("commands.generic.usage", format(wue.getMessage(), wue.getErrorOjbects())).setColor(RED));
}
catch (CommandException ce)
{
sender.addChatMessage(format(RED, ce.getMessage(), ce.getErrorObjects()));
sender.sendChatToPlayer(format(ce.getMessage(), ce.getErrorOjbects()).setColor(RED));
}
catch (Throwable t)
{
sender.addChatMessage(format(RED, "commands.generic.exception"));
sender.sendChatToPlayer(format("commands.generic.exception").setColor(RED));
t.printStackTrace();
}
return -1;
return 0;
}
//Couple of helpers because the mcp names are stupid and long...
private TextComponentTranslation format(TextFormatting color, String str, Object... args)
private ChatMessageComponent format(String str, Object... args)
{
TextComponentTranslation ret = new TextComponentTranslation(str, args);
ret.getStyle().setColor(color);
return ret;
return ChatMessageComponent.createFromTranslationWithSubstitutions(str, args);
}
public void autoComplete(String leftOfCursor)
private ChatMessageComponent format(String str)
{
return ChatMessageComponent.createFromTranslationKey(str);
}
public void autoComplete(String leftOfCursor, String full)
{
latestAutoComplete = null;
@@ -133,7 +115,7 @@ public class ClientCommandHandler extends CommandHandler
Minecraft mc = FMLClientHandler.instance().getClient();
if (mc.currentScreen instanceof GuiChat)
{
List<String> commands = getTabCompletionOptions(mc.thePlayer, leftOfCursor, mc.thePlayer.getPosition());
List<String> commands = getPossibleCommands(mc.thePlayer, leftOfCursor);
if (commands != null && !commands.isEmpty())
{
if (leftOfCursor.indexOf(' ') == -1)
@@ -156,9 +138,4 @@ public class ClientCommandHandler extends CommandHandler
}
}
}
@Override
protected MinecraftServer getServer() {
return Minecraft.getMinecraft().getIntegratedServer();
}
}
}
@@ -0,0 +1,44 @@
package net.minecraftforge.client;
import net.minecraft.world.EnumGameType;
import net.minecraft.util.EnumOS;
import net.minecraft.client.settings.EnumOptions;
import net.minecraft.item.EnumRarity;
import net.minecraftforge.common.EnumHelper;
public class EnumHelperClient extends EnumHelper
{
private static Class[][] clentTypes =
{
{EnumGameType.class, int.class, String.class},
{EnumOptions.class, String.class, boolean.class, boolean.class},
{EnumOS.class},
{EnumRarity.class, int.class, String.class}
};
public static EnumGameType addGameType(String name, int id, String displayName)
{
return addEnum(EnumGameType.class, name, id, displayName);
}
public static EnumOptions addOptions(String name, String langName, boolean isSlider, boolean isToggle)
{
return addEnum(EnumOptions.class, name, langName, isSlider, isToggle);
}
public static EnumOS addOS2(String name)
{
return addEnum(EnumOS.class, name);
}
public static EnumRarity addRarity(String name, int color, String displayName)
{
return addEnum(EnumRarity.class, name, color, displayName);
}
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Object... paramValues)
{
return addEnum(clentTypes, enumType, enumName, paramValues);
}
}
@@ -0,0 +1,393 @@
package net.minecraftforge.client;
import java.util.HashMap;
import java.util.Random;
import java.util.TreeSet;
import javax.imageio.ImageIO;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraftforge.client.event.FOVUpdateEvent;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.PixelFormat;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.client.registry.RenderingRegistry;
import net.minecraft.client.Minecraft;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFluid;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraftforge.client.IItemRenderer.ItemRenderType;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.common.ForgeDummyContainer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.RenderBlockFluid;
import static net.minecraftforge.client.IItemRenderer.ItemRenderType.*;
import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.*;
public class ForgeHooksClient
{
private static final ResourceLocation ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png");
static TextureManager engine()
{
return FMLClientHandler.instance().getClient().renderEngine;
}
@Deprecated
public static String getArmorTexture(Entity entity, ItemStack armor, String _default, int slot, int layer, String type)
{
return getArmorTexture(entity, armor, _default, slot, type);
}
public static String getArmorTexture(Entity entity, ItemStack armor, String _default, int slot, String type)
{
String result = armor.getItem().getArmorTexture(armor, entity, slot, type);
return result != null ? result : _default;
}
public static boolean renderEntityItem(EntityItem entity, ItemStack item, float bobing, float rotation, Random random, TextureManager engine, RenderBlocks renderBlocks)
{
IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, ENTITY);
if (customRenderer == null)
{
return false;
}
if (customRenderer.shouldUseRenderHelper(ENTITY, item, ENTITY_ROTATION))
{
GL11.glRotatef(rotation, 0.0F, 1.0F, 0.0F);
}
if (!customRenderer.shouldUseRenderHelper(ENTITY, item, ENTITY_BOBBING))
{
GL11.glTranslatef(0.0F, -bobing, 0.0F);
}
boolean is3D = customRenderer.shouldUseRenderHelper(ENTITY, item, BLOCK_3D);
engine.bindTexture(item.getItemSpriteNumber() == 0 ? TextureMap.locationBlocksTexture : TextureMap.locationItemsTexture);
Block block = (item.itemID < Block.blocksList.length ? Block.blocksList[item.itemID] : null);
if (is3D || (block != null && RenderBlocks.renderItemIn3d(block.getRenderType())))
{
int renderType = (block != null ? block.getRenderType() : 1);
float scale = (renderType == 1 || renderType == 19 || renderType == 12 || renderType == 2 ? 0.5F : 0.25F);
if (RenderItem.renderInFrame)
{
GL11.glScalef(1.25F, 1.25F, 1.25F);
GL11.glTranslatef(0.0F, 0.05F, 0.0F);
GL11.glRotatef(-90.0F, 0.0F, 1.0F, 0.0F);
}
GL11.glScalef(scale, scale, scale);
int size = item.stackSize;
int count = (size > 40 ? 5 : (size > 20 ? 4 : (size > 5 ? 3 : (size > 1 ? 2 : 1))));
for(int j = 0; j < count; j++)
{
GL11.glPushMatrix();
if (j > 0)
{
GL11.glTranslatef(
((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / scale,
((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / scale,
((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / scale);
}
customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
GL11.glPopMatrix();
}
}
else
{
GL11.glScalef(0.5F, 0.5F, 0.5F);
customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
}
return true;
}
public static boolean renderInventoryItem(RenderBlocks renderBlocks, TextureManager engine, ItemStack item, boolean inColor, float zLevel, float x, float y)
{
IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, INVENTORY);
if (customRenderer == null)
{
return false;
}
engine.bindTexture(item.getItemSpriteNumber() == 0 ? TextureMap.locationBlocksTexture : TextureMap.locationItemsTexture);
if (customRenderer.shouldUseRenderHelper(INVENTORY, item, INVENTORY_BLOCK))
{
GL11.glPushMatrix();
GL11.glTranslatef(x - 2, y + 3, -3.0F + zLevel);
GL11.glScalef(10F, 10F, 10F);
GL11.glTranslatef(1.0F, 0.5F, 1.0F);
GL11.glScalef(1.0F, 1.0F, -1F);
GL11.glRotatef(210F, 1.0F, 0.0F, 0.0F);
GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
if(inColor)
{
int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
float r = (float)(color >> 16 & 0xff) / 255F;
float g = (float)(color >> 8 & 0xff) / 255F;
float b = (float)(color & 0xff) / 255F;
GL11.glColor4f(r, g, b, 1.0F);
}
GL11.glRotatef(-90F, 0.0F, 1.0F, 0.0F);
renderBlocks.useInventoryTint = inColor;
customRenderer.renderItem(INVENTORY, item, renderBlocks);
renderBlocks.useInventoryTint = true;
GL11.glPopMatrix();
}
else
{
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glPushMatrix();
GL11.glTranslatef(x, y, -3.0F + zLevel);
if (inColor)
{
int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
float r = (float)(color >> 16 & 255) / 255.0F;
float g = (float)(color >> 8 & 255) / 255.0F;
float b = (float)(color & 255) / 255.0F;
GL11.glColor4f(r, g, b, 1.0F);
}
customRenderer.renderItem(INVENTORY, item, renderBlocks);
GL11.glPopMatrix();
GL11.glEnable(GL11.GL_LIGHTING);
}
return true;
}
public static void renderEffectOverlay(TextureManager manager, RenderItem render)
{
}
public static void renderEquippedItem(ItemRenderType type, IItemRenderer customRenderer, RenderBlocks renderBlocks, EntityLivingBase entity, ItemStack item)
{
if (customRenderer.shouldUseRenderHelper(type, item, EQUIPPED_BLOCK))
{
GL11.glPushMatrix();
GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
customRenderer.renderItem(type, item, renderBlocks, entity);
GL11.glPopMatrix();
}
else
{
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
GL11.glTranslatef(0.0F, -0.3F, 0.0F);
GL11.glScalef(1.5F, 1.5F, 1.5F);
GL11.glRotatef(50.0F, 0.0F, 1.0F, 0.0F);
GL11.glRotatef(335.0F, 0.0F, 0.0F, 1.0F);
GL11.glTranslatef(-0.9375F, -0.0625F, 0.0F);
customRenderer.renderItem(type, item, renderBlocks, entity);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
}
}
//Optifine Helper Functions u.u, these are here specifically for Optifine
//Note: When using Optfine, these methods are invoked using reflection, which
//incurs a major performance penalty.
public static void orientBedCamera(Minecraft mc, EntityLivingBase entity)
{
int x = MathHelper.floor_double(entity.posX);
int y = MathHelper.floor_double(entity.posY);
int z = MathHelper.floor_double(entity.posZ);
Block block = Block.blocksList[mc.theWorld.getBlockId(x, y, z)];
if (block != null && block.isBed(mc.theWorld, x, y, z, entity))
{
int var12 = block.getBedDirection(mc.theWorld, x, y, z);
GL11.glRotatef((float)(var12 * 90), 0.0F, 1.0F, 0.0F);
}
}
public static boolean onDrawBlockHighlight(RenderGlobal context, EntityPlayer player, MovingObjectPosition target, int subID, ItemStack currentItem, float partialTicks)
{
return MinecraftForge.EVENT_BUS.post(new DrawBlockHighlightEvent(context, player, target, subID, currentItem, partialTicks));
}
public static void dispatchRenderLast(RenderGlobal context, float partialTicks)
{
MinecraftForge.EVENT_BUS.post(new RenderWorldLastEvent(context, partialTicks));
}
public static void onTextureStitchedPre(TextureMap map)
{
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Pre(map));
}
public static void onTextureStitchedPost(TextureMap map)
{
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Post(map));
FluidRegistry.WATER.setIcons(BlockFluid.getFluidIcon("water_still"), BlockFluid.getFluidIcon("water_flow"));
FluidRegistry.LAVA.setIcons(BlockFluid.getFluidIcon("lava_still"), BlockFluid.getFluidIcon("lava_flow"));
}
/**
* This is added for Optifine's convenience. And to explode if a ModMaker is developing.
* @param texture
*/
public static void onTextureLoadPre(String texture)
{
if (Tessellator.renderingWorldRenderer)
{
String msg = String.format("Warning: Texture %s not preloaded, will cause render glitches!", texture);
System.out.println(msg);
if (Tessellator.class.getPackage() != null)
{
if (Tessellator.class.getPackage().getName().startsWith("net.minecraft."))
{
Minecraft mc = FMLClientHandler.instance().getClient();
if (mc.ingameGUI != null)
{
mc.ingameGUI.getChatGUI().printChatMessage(msg);
}
}
}
}
}
static int renderPass = -1;
public static void setRenderPass(int pass)
{
renderPass = pass;
}
public static ModelBiped getArmorModel(EntityLivingBase entityLiving, ItemStack itemStack, int slotID, ModelBiped _default)
{
ModelBiped modelbiped = itemStack.getItem().getArmorModel(entityLiving, itemStack, slotID);
return modelbiped == null ? _default : modelbiped;
}
static int stencilBits = 0;
public static void createDisplay() throws LWJGLException
{
ImageIO.setUseCache(false); //Disable on-disc stream cache should speed up texture pack reloading.
PixelFormat format = new PixelFormat().withDepthBits(24);
try
{
//TODO: Figure out how to determine the max bits.
Display.create(format.withStencilBits(8));
stencilBits = 8;
}
catch(LWJGLException e)
{
Display.create(format);
stencilBits = 0;
}
}
//This properly moves the domain, if provided, to the front of the string before concatenating
public static String fixDomain(String base, String complex)
{
int idx = complex.indexOf(':');
if (idx == -1)
{
return base + complex;
}
String name = complex.substring(idx + 1, complex.length());
if (idx > 1)
{
String domain = complex.substring(0, idx);
return domain + ':' + base + name;
}
else
{
return base + name;
}
}
public static boolean postMouseEvent()
{
return MinecraftForge.EVENT_BUS.post(new MouseEvent());
}
public static float getOffsetFOV(EntityPlayerSP entity, float fov)
{
FOVUpdateEvent fovUpdateEvent = new FOVUpdateEvent(entity, fov);
MinecraftForge.EVENT_BUS.post(fovUpdateEvent);
return fovUpdateEvent.newfov;
}
private static int skyX, skyZ;
private static boolean skyInit;
private static int skyRGBMultiplier;
public static int getSkyBlendColour(World world, int playerX, int playerZ)
{
if (playerX == skyX && playerZ == skyZ && skyInit)
{
return skyRGBMultiplier;
}
skyInit = true;
int distance = Minecraft.getMinecraft().gameSettings.fancyGraphics ? ForgeDummyContainer.blendRanges[Minecraft.getMinecraft().gameSettings.renderDistance] : 0;
int r = 0;
int g = 0;
int b = 0;
int divider = 0;
for (int x = -distance; x <= distance; ++x)
{
for (int z = -distance; z <= distance; ++z)
{
BiomeGenBase biome = world.getBiomeGenForCoords(playerX + x, playerZ + z);
int colour = biome.getSkyColorByTemp(biome.getFloatTemperature());
r += (colour & 0xFF0000) >> 16;
g += (colour & 0x00FF00) >> 8;
b += colour & 0x0000FF;
divider++;
}
}
int multiplier = (r / divider & 255) << 16 | (g / divider & 255) << 8 | b / divider & 255;
skyX = playerX;
skyZ = playerZ;
skyRGBMultiplier = multiplier;
return skyRGBMultiplier;
}
/**
* Initialization of Forge Renderers.
*/
static
{
FluidRegistry.renderIdFluid = RenderingRegistry.getNextAvailableRenderId();
RenderingRegistry.registerBlockHandler(RenderBlockFluid.instance);
}
}
@@ -0,0 +1,128 @@
package net.minecraftforge.client;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.client.gui.GuiControls;
import net.minecraft.client.gui.GuiSlot;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
public class GuiControlsScrollPanel extends GuiSlot
{
protected static final ResourceLocation WIDGITS = new ResourceLocation("textures/gui/widgets.png");
private GuiControls controls;
private GameSettings options;
private Minecraft mc;
private String[] message;
private int _mouseX;
private int _mouseY;
private int selected = -1;
public GuiControlsScrollPanel(GuiControls controls, GameSettings options, Minecraft mc)
{
super(mc, controls.width, controls.height, 16, (controls.height - 32) + 4, 25);
this.controls = controls;
this.options = options;
this.mc = mc;
}
@Override
protected int getSize()
{
return options.keyBindings.length;
}
@Override
protected void elementClicked(int i, boolean flag)
{
if (!flag)
{
if (selected == -1)
{
selected = i;
}
else
{
options.setKeyBinding(selected, -100);
selected = -1;
KeyBinding.resetKeyBindingArrayAndHash();
}
}
}
@Override
protected boolean isSelected(int i)
{
return false;
}
@Override
protected void drawBackground() {}
@Override
public void drawScreen(int mX, int mY, float f)
{
_mouseX = mX;
_mouseY = mY;
if (selected != -1 && !Mouse.isButtonDown(0) && Mouse.getDWheel() == 0)
{
if (Mouse.next() && Mouse.getEventButtonState())
{
options.setKeyBinding(selected, -100 + Mouse.getEventButton());
selected = -1;
KeyBinding.resetKeyBindingArrayAndHash();
}
}
super.drawScreen(mX, mY, f);
}
@Override
protected void drawSlot(int index, int xPosition, int yPosition, int l, Tessellator tessellator)
{
int width = 70;
int height = 20;
xPosition -= 20;
boolean flag = _mouseX >= xPosition && _mouseY >= yPosition && _mouseX < xPosition + width && _mouseY < yPosition + height;
int k = (flag ? 2 : 1);
mc.renderEngine.bindTexture(WIDGITS);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
controls.drawTexturedModalRect(xPosition, yPosition, 0, 46 + k * 20, width / 2, height);
controls.drawTexturedModalRect(xPosition + width / 2, yPosition, 200 - width / 2, 46 + k * 20, width / 2, height);
controls.drawString(mc.fontRenderer, options.getKeyBindingDescription(index), xPosition + width + 4, yPosition + 6, 0xFFFFFFFF);
boolean conflict = false;
for (int x = 0; x < options.keyBindings.length; x++)
{
if (x != index && options.keyBindings[x].keyCode == options.keyBindings[index].keyCode)
{
conflict = true;
break;
}
}
String str = (conflict ? EnumChatFormatting.RED : "") + options.getOptionDisplayString(index);
str = (index == selected ? EnumChatFormatting.WHITE + "> " + EnumChatFormatting.YELLOW + "??? " + EnumChatFormatting.WHITE + "<" : str);
controls.drawCenteredString(mc.fontRenderer, str, xPosition + (width / 2), yPosition + (height - 8) / 2, 0xFFFFFFFF);
}
public boolean keyTyped(char c, int i)
{
if (selected != -1)
{
options.setKeyBinding(selected, i);
selected = -1;
KeyBinding.resetKeyBindingArrayAndHash();
return false;
}
return true;
}
}
@@ -0,0 +1,137 @@
package net.minecraftforge.client;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.EntityLiving;
import net.minecraft.item.ItemStack;
import net.minecraft.client.renderer.RenderBlocks;
public interface IItemRenderer
{
public enum ItemRenderType
{
/**
* Called to render an in-world item, e.g. one that has been thrown or
* dropped. The appropriate OpenGL transformations and scaling have already
* been applied, so Tessellator location (0,0,0) is the center of the
* EntityItem.
*
* Data parameters:
* RenderBlocks render - The RenderBlocks instance
* EntityItem entity - The in-world item to be rendered
*/
ENTITY,
/**
* Called to render an item currently held in-hand by a living entity. If
* rendering as a 3D block, the item will be rotated to a 45-degree angle.
* To render a 2D texture with some thickness (like default items), see
* net.minecraft.src.ItemRenderer. In either case, rendering should be done
* in local coordinates from (0,0,0)-(1,1,1).
*
* Data parameters:
* RenderBlocks render - The RenderBlocks instance
* EntityLiving entity - The entity holding this item
*/
EQUIPPED,
/**
* Called to render an item currently held in-hand by a living entity in
* first person. If rendering as a 3D block, the item will be rotated to a
* 45-degree angle. To render a 2D texture with some thickness, see
* net.minecraft.src.ItemRenderer. In either case, rendering should be done
* in local coordinates from (0,0,0)-(1,1,1).
*
* Data parameters:
* RenderBlocks render - The RenderBlocks instance
* EntityLiving entity - The entity holding this item
*/
EQUIPPED_FIRST_PERSON,
/**
* Called to render an item in a GUI inventory slot. If rendering as a 3D
* block, the appropriate OpenGL translations and scaling have already been
* applied, and the rendering should be done in local coordinates from
* (0,0,0)-(1,1,1). If rendering as a 2D texture, the rendering should be in
* GUI pixel coordinates from (0, 0, 0)-(16, 16, 0).
*
* Data parameters:
* RenderBlocks render - The RenderBlocks instance
*/
INVENTORY,
/**
* The render type used for when a ItemMap is rendered in first person,
* All appropriate rotations have been applied, and the player's hands,
* and the map BG are already rendered.
*
* Data Parameters:
* EntityPlayer player - The player holding the map
* RenderEngine engine - The RenderEngine instance
* MapData mapData - The map data
*/
FIRST_PERSON_MAP
}
public enum ItemRendererHelper
{
/**
* Determines if a rotation effect should be used when rendering an
* EntityItem, like most default blocks do.
*/
ENTITY_ROTATION,
/**
* Determines if an up-and-down bobbing effect should be used when
* rendering an EntityItem, like most default items do.
*/
ENTITY_BOBBING,
/**
* Determines if the currently equipped item should be rendered as a 3D
* block or as a 2D texture.
*/
EQUIPPED_BLOCK,
/**
* Determines if the item should equate to a block that has
* RenderBlocks.renderItemIn3d return true
*/
BLOCK_3D,
/**
* Determines if the item should be rendered in GUI inventory slots as a 3D
* block or as a 2D texture.
*/
INVENTORY_BLOCK
}
/**
* Checks if this renderer should handle a specific item's render type
* @param item The item we are trying to render
* @param type A render type to check if this renderer handles
* @return true if this renderer should handle the given render type,
* otherwise false
*/
public boolean handleRenderType(ItemStack item, ItemRenderType type);
/**
* Checks if certain helper functionality should be executed for this renderer.
* See ItemRendererHelper for more info
*
* @param type The render type
* @param item The ItemStack being rendered
* @param helper The type of helper functionality to be ran
* @return True to run the helper functionality, false to not.
*/
public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper);
/**
* Called to do the actual rendering, see ItemRenderType for details on when specific
* types are run, and what extra data is passed into the data parameter.
*
* @param type The render type
* @param item The ItemStack being rendered
* @param data Extra Type specific data
*/
public void renderItem(ItemRenderType type, ItemStack item, Object... data);
}
@@ -0,0 +1,17 @@
/*
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.client;
public interface IRenderContextHandler
{
/** Run before the specified rendering context.
*/
public void beforeRenderContext();
/** Run after the specified rendering context.
*/
public void afterRenderContext();
}
@@ -0,0 +1,12 @@
package net.minecraftforge.client;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.WorldClient;
public abstract class IRenderHandler
{
@SideOnly(Side.CLIENT)
public abstract void render(float partialTicks, WorldClient world, Minecraft mc);
}
@@ -0,0 +1,92 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.client;
import java.util.BitSet;
import org.lwjgl.opengl.Display;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.world.World;
import net.minecraftforge.client.IItemRenderer.ItemRenderType;
import net.minecraftforge.common.MinecraftForge;
public class MinecraftForgeClient
{
private static IItemRenderer[] customItemRenderers = new IItemRenderer[Item.itemsList.length];
/**
* Register a custom renderer for a specific item. This can be used to
* render the item in-world as an EntityItem, when the item is equipped, or
* when the item is in an inventory slot.
* @param itemID The item ID (shifted index) to handle rendering.
* @param renderer The IItemRenderer interface that handles rendering for
* this item.
*/
public static void registerItemRenderer(int itemID, IItemRenderer renderer)
{
customItemRenderers[itemID] = renderer;
}
public static IItemRenderer getItemRenderer(ItemStack item, ItemRenderType type)
{
IItemRenderer renderer = customItemRenderers[item.itemID];
if (renderer != null && renderer.handleRenderType(item, type))
{
return customItemRenderers[item.itemID];
}
return null;
}
public static int getRenderPass()
{
return ForgeHooksClient.renderPass;
}
public static int getStencilBits()
{
return ForgeHooksClient.stencilBits;
}
private static BitSet stencilBits = new BitSet(getStencilBits());
static
{
stencilBits.set(0,getStencilBits());
}
/**
* Reserve a stencil bit for use in rendering
*
* @return A bit or -1 if no further stencil bits are available
*/
public static int reserveStencilBit()
{
int bit = stencilBits.nextSetBit(0);
if (bit >= 0)
{
stencilBits.clear(bit);
}
return bit;
}
/**
* Release the stencil bit for other use
*
* @param bit The bit from {@link #reserveStencilBit()}
*/
public static void releaseStencilBit(int bit)
{
if (bit >= 0 && bit < getStencilBits())
{
stencilBits.set(bit);
}
}
}
@@ -0,0 +1,14 @@
package net.minecraftforge.client.event;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
@Cancelable
public class ClientChatReceivedEvent extends Event
{
public String message;
public ClientChatReceivedEvent(String message)
{
this.message = message;
}
}
@@ -0,0 +1,30 @@
package net.minecraftforge.client.event;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
@Cancelable
public class DrawBlockHighlightEvent extends Event
{
public final RenderGlobal context;
public final EntityPlayer player;
public final MovingObjectPosition target;
public final int subID;
public final ItemStack currentItem;
public final float partialTicks;
public DrawBlockHighlightEvent(RenderGlobal context, EntityPlayer player, MovingObjectPosition target, int subID, ItemStack currentItem, float partialTicks)
{
this.context = context;
this.player = player;
this.target = target;
this.subID = subID;
this.currentItem = currentItem;
this.partialTicks= partialTicks;
}
}
@@ -0,0 +1,23 @@
package net.minecraftforge.client.event;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraftforge.event.Event;
/**
* Author: MachineMuse (Claire Semple)
* Created: 6:07 PM, 9/5/13
*/
public class FOVUpdateEvent extends Event
{
public final EntityPlayerSP entity;
public final float fov;
public float newfov;
public FOVUpdateEvent(EntityPlayerSP entity, float fov)
{
this.entity = entity;
this.fov = fov;
this.newfov = fov;
}
}
@@ -0,0 +1,22 @@
package net.minecraftforge.client.event;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
/**
* This event is called before any Gui will open.
* If you don't want this to happen, cancel the event.
* If you want to override this Gui, simply set the gui variable to your own Gui.
*
* @author jk-5
*/
@Cancelable
public class GuiOpenEvent extends Event
{
public GuiScreen gui;
public GuiOpenEvent(GuiScreen gui)
{
this.gui = gui;
}
}
@@ -0,0 +1,34 @@
package net.minecraftforge.client.event;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
import org.lwjgl.input.Mouse;
/**
* Author: MachineMuse (Claire Semple)
* Created: 2:46 PM, 9/4/13
*/
@Cancelable
public class MouseEvent extends Event
{
public final int x;
public final int y;
public final int dx;
public final int dy;
public final int dwheel;
public final int button;
public final boolean buttonstate;
public final long nanoseconds;
public MouseEvent()
{
this.x = Mouse.getEventX();
this.y = Mouse.getEventY();
this.dx = Mouse.getEventDX();
this.dy = Mouse.getEventDY();
this.dwheel = Mouse.getEventDWheel();
this.button = Mouse.getEventButton();
this.buttonstate = Mouse.getEventButtonState();
this.nanoseconds = Mouse.getEventNanoseconds();
}
}
@@ -0,0 +1,97 @@
package net.minecraftforge.client.event;
import java.util.ArrayList;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
@Cancelable
public class RenderGameOverlayEvent extends Event
{
public static enum ElementType
{
ALL,
HELMET,
PORTAL,
CROSSHAIRS,
BOSSHEALTH,
ARMOR,
HEALTH,
FOOD,
AIR,
HOTBAR,
EXPERIENCE,
TEXT,
HEALTHMOUNT,
JUMPBAR,
CHAT,
PLAYER_LIST
}
public final float partialTicks;
public final ScaledResolution resolution;
public final int mouseX;
public final int mouseY;
public final ElementType type;
public RenderGameOverlayEvent(float partialTicks, ScaledResolution resolution, int mouseX, int mouseY)
{
this.partialTicks = partialTicks;
this.resolution = resolution;
this.mouseX = mouseX;
this.mouseY = mouseY;
this.type = null;
}
private RenderGameOverlayEvent(RenderGameOverlayEvent parent, ElementType type)
{
this.partialTicks = parent.partialTicks;
this.resolution = parent.resolution;
this.mouseX = parent.mouseX;
this.mouseY = parent.mouseY;
this.type = type;
}
public static class Pre extends RenderGameOverlayEvent
{
public Pre(RenderGameOverlayEvent parent, ElementType type)
{
super(parent, type);
}
}
public static class Post extends RenderGameOverlayEvent
{
public Post(RenderGameOverlayEvent parent, ElementType type)
{
super(parent, type);
}
@Override public boolean isCancelable(){ return false; }
}
public static class Text extends Pre
{
public final ArrayList<String> left;
public final ArrayList<String> right;
public Text(RenderGameOverlayEvent parent, ArrayList<String> left, ArrayList<String> right)
{
super(parent, ElementType.TEXT);
this.left = left;
this.right = right;
}
}
public static class Chat extends Pre
{
public int posX;
public int posY;
public Chat(RenderGameOverlayEvent parent, int posX, int posY)
{
super(parent, ElementType.CHAT);
this.posX = posX;
this.posY = posY;
}
}
}
@@ -0,0 +1,43 @@
package net.minecraftforge.client.event;
import net.minecraft.client.renderer.entity.RendererLivingEntity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
public abstract class RenderLivingEvent extends Event
{
public final EntityLivingBase entity;
public final RendererLivingEntity renderer;
public RenderLivingEvent(EntityLivingBase entity, RendererLivingEntity renderer)
{
this.entity = entity;
this.renderer = renderer;
}
@Cancelable
public static class Pre extends RenderLivingEvent
{
public Pre(EntityLivingBase entity, RendererLivingEntity renderer){ super(entity, renderer); }
}
public static class Post extends RenderLivingEvent
{
public Post(EntityLivingBase entity, RendererLivingEntity renderer){ super(entity, renderer); }
}
public abstract static class Specials extends RenderLivingEvent
{
public Specials(EntityLivingBase entity, RendererLivingEntity renderer){ super(entity, renderer); }
@Cancelable
public static class Pre extends Specials
{
public Pre(EntityLivingBase entity, RendererLivingEntity renderer){ super(entity, renderer); }
}
public static class Post extends Specials
{
public Post(EntityLivingBase entity, RendererLivingEntity renderer){ super(entity, renderer); }
}
}
}
@@ -0,0 +1,76 @@
package net.minecraftforge.client.event;
import net.minecraft.client.renderer.entity.RenderPlayer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.entity.player.PlayerEvent;
public abstract class RenderPlayerEvent extends PlayerEvent
{
public final RenderPlayer renderer;
public final float partialRenderTick;
public RenderPlayerEvent(EntityPlayer player, RenderPlayer renderer, float partialRenderTick)
{
super(player);
this.renderer = renderer;
this.partialRenderTick = partialRenderTick;
}
@Cancelable
public static class Pre extends RenderPlayerEvent
{
public Pre(EntityPlayer player, RenderPlayer renderer, float tick){ super(player, renderer, tick); }
}
public static class Post extends RenderPlayerEvent
{
public Post(EntityPlayer player, RenderPlayer renderer, float tick){ super(player, renderer, tick); }
}
public abstract static class Specials extends RenderPlayerEvent
{
@Deprecated
public final float partialTicks;
public Specials(EntityPlayer player, RenderPlayer renderer, float partialTicks)
{
super(player, renderer, partialTicks);
this.partialTicks = partialTicks;
}
@Cancelable
public static class Pre extends Specials
{
public boolean renderHelmet = true;
public boolean renderCape = true;
public boolean renderItem = true;
public Pre(EntityPlayer player, RenderPlayer renderer, float partialTicks){ super(player, renderer, partialTicks); }
}
public static class Post extends Specials
{
public Post(EntityPlayer player, RenderPlayer renderer, float partialTicks){ super(player, renderer, partialTicks); }
}
}
public static class SetArmorModel extends RenderPlayerEvent
{
/**
* Setting this to any value besides -1 will result in the function being
* Immediately exited with the return value specified.
*/
public int result = -1;
public final int slot;
@Deprecated
public final float partialTick;
public final ItemStack stack;
public SetArmorModel(EntityPlayer player, RenderPlayer renderer, int slot, float partialTick, ItemStack stack)
{
super(player, renderer, partialTick);
this.slot = slot;
this.partialTick = partialTick;
this.stack = stack;
}
}
}
@@ -0,0 +1,15 @@
package net.minecraftforge.client.event;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraftforge.event.Event;
public class RenderWorldLastEvent extends Event
{
public final RenderGlobal context;
public final float partialTicks;
public RenderWorldLastEvent(RenderGlobal context, float partialTicks)
{
this.context = context;
this.partialTicks = partialTicks;
}
}
@@ -0,0 +1,35 @@
package net.minecraftforge.client.event;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraftforge.event.Event;
public class TextureStitchEvent extends Event
{
public final TextureMap map;
public TextureStitchEvent(TextureMap map)
{
this.map = map;
}
/**
* Fired when the TextureMap is told to refresh it's stitched texture.
* Called after the Stitched list is cleared, but before any blocks or items
* add themselves to the list.
*/
public static class Pre extends TextureStitchEvent
{
public Pre(TextureMap map){ super(map); }
}
/**
* This event is fired once the texture map has loaded all textures and
* stitched them together. All Icons should have there locations defined
* by the time this is fired.
*/
public static class Post extends TextureStitchEvent
{
public Post(TextureMap map){ super(map); }
}
}
@@ -0,0 +1,15 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
/**
* Raised when the SoundManager tries to play a Background Music file,
* If you return null from this function it will prevent the sound from being played,
* you can return a different entry if you want to change the sound being played.
*/
public class PlayBackgroundMusicEvent extends SoundResultEvent
{
public PlayBackgroundMusicEvent(SoundManager manager, SoundPoolEntry entry)
{ super(manager, entry, null, 0.0f, 0.0f); }
}
@@ -0,0 +1,10 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
public class PlaySoundEffectEvent extends SoundResultEvent
{
public PlaySoundEffectEvent(SoundManager manager, SoundPoolEntry source, String name, float volume, float pitch)
{ super(manager, source, name, volume, pitch); }
}
@@ -0,0 +1,14 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
public class PlaySoundEffectSourceEvent extends SoundEvent
{
public final SoundManager manager;
public final String name;
public PlaySoundEffectSourceEvent(SoundManager manager, String name)
{
this.manager = manager;
this.name = name;
}
}
@@ -0,0 +1,25 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
/***
* Raised when the SoundManager tries to play a normal sound,
* dogs barking, footsteps, etc. THe majority of all sounds during normal game play.
*
* If you return null from this function it will prevent the sound from being played,
* you can return a different entry if you want to change the sound being played.
*/
public class PlaySoundEvent extends SoundResultEvent
{
public final float x;
public final float y;
public final float z;
public PlaySoundEvent(SoundManager manager, SoundPoolEntry source, String name, float x, float y, float z, float volume, float pitch)
{
super(manager, source, name, volume, pitch);
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -0,0 +1,20 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
public class PlaySoundSourceEvent extends SoundEvent
{
public final SoundManager manager;
public final String name;
public final float x;
public final float y;
public final float z;
public PlaySoundSourceEvent(SoundManager manager, String name, float x, float y, float z)
{
this.manager = manager;
this.name = name;
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -0,0 +1,26 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
/**
* Raised when the SoundManager tries to play a 'Streaming' file,
* in vanilla it is only the Jukebox that uses this function.
*
* If you return null from this function it will prevent the sound from being played,
* you can return a different entry if you want to change the sound being played.
*
*/
public class PlayStreamingEvent extends SoundResultEvent
{
public final float x;
public final float y;
public final float z;
public PlayStreamingEvent(SoundManager manager, SoundPoolEntry source, String name, float x, float y, float z)
{
super(manager, source, name, 0.0f, 0.0f);
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -0,0 +1,20 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
public class PlayStreamingSourceEvent extends SoundEvent
{
public final SoundManager manager;
public final String name;
public final float x;
public final float y;
public final float z;
public PlayStreamingSourceEvent(SoundManager manager, String name, float x, float y, float z)
{
this.manager = manager;
this.name = name;
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -0,0 +1,19 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.entity.Entity;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.Cancelable;
import net.minecraftforge.event.Event;
public class SoundEvent extends Event
{
public SoundEvent(){}
public static SoundPoolEntry getResult(SoundResultEvent event)
{
MinecraftForge.EVENT_BUS.post(event);
return event.result;
}
}
@@ -0,0 +1,16 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
/**
* Raised by the SoundManager.loadSoundSettings, this would be a good place for
* adding your custom sounds to the SoundPool.
*/
public class SoundLoadEvent extends SoundEvent
{
public final SoundManager manager;
public SoundLoadEvent(SoundManager manager)
{
this.manager = manager;
}
}
@@ -0,0 +1,24 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
import net.minecraft.client.audio.SoundPoolEntry;
public abstract class SoundResultEvent extends SoundEvent
{
public final SoundManager manager;
public final SoundPoolEntry source;
public final String name;
public final float volume;
public final float pitch;
public SoundPoolEntry result;
public SoundResultEvent(SoundManager manager, SoundPoolEntry source, String name, float volume, float pitch)
{
this.manager = manager;
this.source = source;
this.name = name;
this.volume = volume;
this.pitch = pitch;
this.result = source;
}
}
@@ -0,0 +1,16 @@
package net.minecraftforge.client.event.sound;
import net.minecraft.client.audio.SoundManager;
/**
* This event is raised by the SoundManager when it does its first setup of the
* SoundSystemConfig's codecs, use this function to add your own codecs.
*/
public class SoundSetupEvent extends SoundEvent
{
public final SoundManager manager;
public SoundSetupEvent(SoundManager manager)
{
this.manager = manager;
}
}
@@ -0,0 +1,84 @@
package net.minecraftforge.client.model;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Map;
import net.minecraftforge.client.model.obj.ObjModelLoader;
import net.minecraftforge.client.model.techne.TechneModelLoader;
import com.google.common.collect.Maps;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
/**
* Common interface for advanced model loading from files, based on file suffix
* Model support can be queried through the {@link #getSupportedSuffixes()} method.
* Instances can be created by calling {@link #loadModel(String)} with a class-loadable-path
*
* @author cpw
*
*/
@SideOnly(Side.CLIENT)
public class AdvancedModelLoader {
private static Map<String, IModelCustomLoader> instances = Maps.newHashMap();
/**
* Register a new model handler
* @param modelHandler The model handler to register
*/
public static void registerModelHandler(IModelCustomLoader modelHandler)
{
for (String suffix : modelHandler.getSuffixes())
{
instances.put(suffix, modelHandler);
}
}
/**
* Load the model from the supplied classpath resolvable resource name
* @param resourceName The resource name
* @return A model
* @throws IllegalArgumentException if the resource name cannot be understood
* @throws ModelFormatException if the underlying model handler cannot parse the model format
*/
public static IModelCustom loadModel(String resourceName) throws IllegalArgumentException, ModelFormatException
{
int i = resourceName.lastIndexOf('.');
if (i == -1)
{
FMLLog.severe("The resource name %s is not valid", resourceName);
throw new IllegalArgumentException("The resource name is not valid");
}
String suffix = resourceName.substring(i+1);
IModelCustomLoader loader = instances.get(suffix);
if (loader == null)
{
FMLLog.severe("The resource name %s is not supported", resourceName);
throw new IllegalArgumentException("The resource name is not supported");
}
URL resource = AdvancedModelLoader.class.getResource(resourceName);
if (resource == null)
{
FMLLog.severe("The resource name %s could not be found", resourceName);
throw new IllegalArgumentException("The resource name could not be found");
}
return loader.loadInstance(resourceName, resource);
}
public static Collection<String> getSupportedSuffixes()
{
return instances.keySet();
}
static
{
registerModelHandler(new ObjModelLoader());
registerModelHandler(new TechneModelLoader());
}
}
@@ -0,0 +1,11 @@
package net.minecraftforge.client.model;
public interface IModelCustom {
String getType();
void renderAll();
void renderOnly(String... groupNames);
void renderPart(String partName);
void renderAllExcept(String... excludedGroupNames);
}
@@ -0,0 +1,31 @@
package net.minecraftforge.client.model;
import java.io.InputStream;
import java.net.URL;
/**
* Instances of this class act as factories for their model type
*
* @author cpw
*
*/
public interface IModelCustomLoader {
/**
* Get the main type name for this loader
* @return the type name
*/
String getType();
/**
* Get resource suffixes this model loader recognizes
* @return a list of suffixes
*/
String[] getSuffixes();
/**
* Load a model instance from the supplied path
* @param resourceName The resource name to load
* @param resource The URL associated with the classloader resource
* @return A model instance
* @throws ModelFormatException if the model format is not correct
*/
IModelCustom loadInstance(String resourceName, URL resource) throws ModelFormatException;
}
@@ -0,0 +1,31 @@
package net.minecraftforge.client.model;
/**
* Thrown if there is a problem parsing the model
*
* @author cpw
*
*/
public class ModelFormatException extends RuntimeException {
public ModelFormatException()
{
super();
}
public ModelFormatException(String message, Throwable cause)
{
super(message, cause);
}
public ModelFormatException(String message)
{
super(message);
}
public ModelFormatException(Throwable cause)
{
super(cause);
}
}
@@ -0,0 +1,84 @@
package net.minecraftforge.client.model.obj;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.Vec3;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class Face
{
public Vertex[] vertices;
public Vertex[] vertexNormals;
public Vertex faceNormal;
public TextureCoordinate[] textureCoordinates;
public void addFaceForRender(Tessellator tessellator)
{
addFaceForRender(tessellator, 0.0005F);
}
public void addFaceForRender(Tessellator tessellator, float textureOffset)
{
if (faceNormal == null)
{
faceNormal = this.calculateFaceNormal();
}
tessellator.setNormal(faceNormal.x, faceNormal.y, faceNormal.z);
float averageU = 0F;
float averageV = 0F;
if ((textureCoordinates != null) && (textureCoordinates.length > 0))
{
for (int i = 0; i < textureCoordinates.length; ++i)
{
averageU += textureCoordinates[i].u;
averageV += textureCoordinates[i].v;
}
averageU = averageU / textureCoordinates.length;
averageV = averageV / textureCoordinates.length;
}
float offsetU, offsetV;
for (int i = 0; i < vertices.length; ++i)
{
if ((textureCoordinates != null) && (textureCoordinates.length > 0))
{
offsetU = textureOffset;
offsetV = textureOffset;
if (textureCoordinates[i].u > averageU)
{
offsetU = -offsetU;
}
if (textureCoordinates[i].v > averageV)
{
offsetV = -offsetV;
}
tessellator.addVertexWithUV(vertices[i].x, vertices[i].y, vertices[i].z, textureCoordinates[i].u + offsetU, textureCoordinates[i].v + offsetV);
}
else
{
tessellator.addVertex(vertices[i].x, vertices[i].y, vertices[i].z);
}
}
}
public Vertex calculateFaceNormal()
{
Vec3 v1 = Vec3.createVectorHelper(vertices[1].x - vertices[0].x, vertices[1].y - vertices[0].y, vertices[1].z - vertices[0].z);
Vec3 v2 = Vec3.createVectorHelper(vertices[2].x - vertices[0].x, vertices[2].y - vertices[0].y, vertices[2].z - vertices[0].z);
Vec3 normalVector = null;
normalVector = v1.crossProduct(v2).normalize();
return new Vertex((float) normalVector.xCoord, (float) normalVector.yCoord, (float) normalVector.zCoord);
}
}
@@ -0,0 +1,54 @@
package net.minecraftforge.client.model.obj;
import java.util.ArrayList;
import net.minecraft.client.renderer.Tessellator;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class GroupObject
{
public String name;
public ArrayList<Face> faces = new ArrayList<Face>();
public int glDrawingMode;
public GroupObject()
{
this("");
}
public GroupObject(String name)
{
this(name, -1);
}
public GroupObject(String name, int glDrawingMode)
{
this.name = name;
this.glDrawingMode = glDrawingMode;
}
public void render()
{
if (faces.size() > 0)
{
Tessellator tessellator = Tessellator.instance;
tessellator.startDrawing(glDrawingMode);
render(tessellator);
tessellator.draw();
}
}
public void render(Tessellator tessellator)
{
if (faces.size() > 0)
{
for (Face face : faces)
{
face.addFaceForRender(tessellator);
}
}
}
}
@@ -0,0 +1,31 @@
package net.minecraftforge.client.model.obj;
import java.io.InputStream;
import java.net.URL;
import net.minecraftforge.client.model.IModelCustom;
import net.minecraftforge.client.model.IModelCustomLoader;
import net.minecraftforge.client.model.ModelFormatException;
public class ObjModelLoader implements IModelCustomLoader {
@Override
public String getType()
{
return "OBJ model";
}
private static final String[] types = { "obj" };
@Override
public String[] getSuffixes()
{
return types;
}
@Override
public IModelCustom loadInstance(String resourceName, URL resource) throws ModelFormatException
{
return new WavefrontObject(resourceName, resource);
}
}
@@ -0,0 +1,23 @@
package net.minecraftforge.client.model.obj;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class TextureCoordinate
{
public float u, v, w;
public TextureCoordinate(float u, float v)
{
this(u, v, 0F);
}
public TextureCoordinate(float u, float v, float w)
{
this.u = u;
this.v = v;
this.w = w;
}
}
@@ -0,0 +1,23 @@
package net.minecraftforge.client.model.obj;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class Vertex
{
public float x, y, z;
public Vertex(float x, float y)
{
this(x, y, 0F);
}
public Vertex(float x, float y, float z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
@@ -0,0 +1,650 @@
package net.minecraftforge.client.model.obj;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.client.renderer.Tessellator;
import net.minecraftforge.client.model.IModelCustom;
import net.minecraftforge.client.model.ModelFormatException;
import org.lwjgl.opengl.GL11;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
/**
* Wavefront Object importer
* Based heavily off of the specifications found at http://en.wikipedia.org/wiki/Wavefront_.obj_file
*/
@SideOnly(Side.CLIENT)
public class WavefrontObject implements IModelCustom
{
private static Pattern vertexPattern = Pattern.compile("(v( (\\-){0,1}\\d+\\.\\d+){3,4} *\\n)|(v( (\\-){0,1}\\d+\\.\\d+){3,4} *$)");
private static Pattern vertexNormalPattern = Pattern.compile("(vn( (\\-){0,1}\\d+\\.\\d+){3,4} *\\n)|(vn( (\\-){0,1}\\d+\\.\\d+){3,4} *$)");
private static Pattern textureCoordinatePattern = Pattern.compile("(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *\\n)|(vt( (\\-){0,1}\\d+\\.\\d+){2,3} *$)");
private static Pattern face_V_VT_VN_Pattern = Pattern.compile("(f( \\d+/\\d+/\\d+){3,4} *\\n)|(f( \\d+/\\d+/\\d+){3,4} *$)");
private static Pattern face_V_VT_Pattern = Pattern.compile("(f( \\d+/\\d+){3,4} *\\n)|(f( \\d+/\\d+){3,4} *$)");
private static Pattern face_V_VN_Pattern = Pattern.compile("(f( \\d+//\\d+){3,4} *\\n)|(f( \\d+//\\d+){3,4} *$)");
private static Pattern face_V_Pattern = Pattern.compile("(f( \\d+){3,4} *\\n)|(f( \\d+){3,4} *$)");
private static Pattern groupObjectPattern = Pattern.compile("([go]( [\\w\\d]+) *\\n)|([go]( [\\w\\d]+) *$)");
private static Matcher vertexMatcher, vertexNormalMatcher, textureCoordinateMatcher;
private static Matcher face_V_VT_VN_Matcher, face_V_VT_Matcher, face_V_VN_Matcher, face_V_Matcher;
private static Matcher groupObjectMatcher;
public ArrayList<Vertex> vertices = new ArrayList<Vertex>();
public ArrayList<Vertex> vertexNormals = new ArrayList<Vertex>();
public ArrayList<TextureCoordinate> textureCoordinates = new ArrayList<TextureCoordinate>();
public ArrayList<GroupObject> groupObjects = new ArrayList<GroupObject>();
private GroupObject currentGroupObject;
private String fileName;
public WavefrontObject(String fileName, URL resource) throws ModelFormatException
{
this.fileName = fileName;
try
{
loadObjModel(resource.openStream());
}
catch (IOException e)
{
throw new ModelFormatException("IO Exception reading model format", e);
}
}
public WavefrontObject(String filename, InputStream inputStream) throws ModelFormatException
{
this.fileName = filename;
loadObjModel(inputStream);
}
private void loadObjModel(InputStream inputStream) throws ModelFormatException
{
BufferedReader reader = null;
String currentLine = null;
int lineCount = 0;
try
{
reader = new BufferedReader(new InputStreamReader(inputStream));
while ((currentLine = reader.readLine()) != null)
{
lineCount++;
currentLine = currentLine.replaceAll("\\s+", " ").trim();
if (currentLine.startsWith("#") || currentLine.length() == 0)
{
continue;
}
else if (currentLine.startsWith("v "))
{
Vertex vertex = parseVertex(currentLine, lineCount);
if (vertex != null)
{
vertices.add(vertex);
}
}
else if (currentLine.startsWith("vn "))
{
Vertex vertex = parseVertexNormal(currentLine, lineCount);
if (vertex != null)
{
vertexNormals.add(vertex);
}
}
else if (currentLine.startsWith("vt "))
{
TextureCoordinate textureCoordinate = parseTextureCoordinate(currentLine, lineCount);
if (textureCoordinate != null)
{
textureCoordinates.add(textureCoordinate);
}
}
else if (currentLine.startsWith("f "))
{
if (currentGroupObject == null)
{
currentGroupObject = new GroupObject("Default");
}
Face face = parseFace(currentLine, lineCount);
if (face != null)
{
currentGroupObject.faces.add(face);
}
}
else if (currentLine.startsWith("g ") | currentLine.startsWith("o "))
{
GroupObject group = parseGroupObject(currentLine, lineCount);
if (group != null)
{
if (currentGroupObject != null)
{
groupObjects.add(currentGroupObject);
}
}
currentGroupObject = group;
}
}
groupObjects.add(currentGroupObject);
}
catch (IOException e)
{
throw new ModelFormatException("IO Exception reading model format", e);
}
finally
{
try
{
reader.close();
}
catch (IOException e)
{
// hush
}
try
{
inputStream.close();
}
catch (IOException e)
{
// hush
}
}
}
@Override
public void renderAll()
{
Tessellator tessellator = Tessellator.instance;
if (currentGroupObject != null)
{
tessellator.startDrawing(currentGroupObject.glDrawingMode);
}
else
{
tessellator.startDrawing(GL11.GL_TRIANGLES);
}
tessellateAll(tessellator);
tessellator.draw();
}
public void tessellateAll(Tessellator tessellator)
{
for (GroupObject groupObject : groupObjects)
{
groupObject.render(tessellator);
}
}
@Override
public void renderOnly(String... groupNames)
{
for (GroupObject groupObject : groupObjects)
{
for (String groupName : groupNames)
{
if (groupName.equalsIgnoreCase(groupObject.name))
{
groupObject.render();
}
}
}
}
public void tessellateOnly(Tessellator tessellator, String... groupNames) {
for (GroupObject groupObject : groupObjects)
{
for (String groupName : groupNames)
{
if (groupName.equalsIgnoreCase(groupObject.name))
{
groupObject.render(tessellator);
}
}
}
}
@Override
public void renderPart(String partName)
{
for (GroupObject groupObject : groupObjects)
{
if (partName.equalsIgnoreCase(groupObject.name))
{
groupObject.render();
}
}
}
public void tessellatePart(Tessellator tessellator, String partName) {
for (GroupObject groupObject : groupObjects)
{
if (partName.equalsIgnoreCase(groupObject.name))
{
groupObject.render(tessellator);
}
}
}
public void renderAllExcept(String... excludedGroupNames)
{
for (GroupObject groupObject : groupObjects)
{
boolean skipPart=false;
for (String excludedGroupName : excludedGroupNames)
{
if (excludedGroupName.equalsIgnoreCase(groupObject.name))
{
skipPart=true;
}
}
if(!skipPart)
{
groupObject.render();
}
}
}
public void tessellateAllExcept(Tessellator tessellator, String... excludedGroupNames)
{
boolean exclude;
for (GroupObject groupObject : groupObjects)
{
exclude=false;
for (String excludedGroupName : excludedGroupNames)
{
if (excludedGroupName.equalsIgnoreCase(groupObject.name))
{
exclude=true;
}
}
if(!exclude)
{
groupObject.render(tessellator);
}
}
}
private Vertex parseVertex(String line, int lineCount) throws ModelFormatException
{
Vertex vertex = null;
if (isValidVertexLine(line))
{
line = line.substring(line.indexOf(" ") + 1);
String[] tokens = line.split(" ");
try
{
if (tokens.length == 2)
{
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]));
}
else if (tokens.length == 3)
{
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
}
}
catch (NumberFormatException e)
{
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return vertex;
}
private Vertex parseVertexNormal(String line, int lineCount) throws ModelFormatException
{
Vertex vertexNormal = null;
if (isValidVertexNormalLine(line))
{
line = line.substring(line.indexOf(" ") + 1);
String[] tokens = line.split(" ");
try
{
if (tokens.length == 3)
return new Vertex(Float.parseFloat(tokens[0]), Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
}
catch (NumberFormatException e)
{
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return vertexNormal;
}
private TextureCoordinate parseTextureCoordinate(String line, int lineCount) throws ModelFormatException
{
TextureCoordinate textureCoordinate = null;
if (isValidTextureCoordinateLine(line))
{
line = line.substring(line.indexOf(" ") + 1);
String[] tokens = line.split(" ");
try
{
if (tokens.length == 2)
return new TextureCoordinate(Float.parseFloat(tokens[0]), 1 - Float.parseFloat(tokens[1]));
else if (tokens.length == 3)
return new TextureCoordinate(Float.parseFloat(tokens[0]), 1 - Float.parseFloat(tokens[1]), Float.parseFloat(tokens[2]));
}
catch (NumberFormatException e)
{
throw new ModelFormatException(String.format("Number formatting error at line %d",lineCount), e);
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return textureCoordinate;
}
private Face parseFace(String line, int lineCount) throws ModelFormatException
{
Face face = null;
if (isValidFaceLine(line))
{
face = new Face();
String trimmedLine = line.substring(line.indexOf(" ") + 1);
String[] tokens = trimmedLine.split(" ");
String[] subTokens = null;
if (tokens.length == 3)
{
if (currentGroupObject.glDrawingMode == -1)
{
currentGroupObject.glDrawingMode = GL11.GL_TRIANGLES;
}
else if (currentGroupObject.glDrawingMode != GL11.GL_TRIANGLES)
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 4, found " + tokens.length + ")");
}
}
else if (tokens.length == 4)
{
if (currentGroupObject.glDrawingMode == -1)
{
currentGroupObject.glDrawingMode = GL11.GL_QUADS;
}
else if (currentGroupObject.glDrawingMode != GL11.GL_QUADS)
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Invalid number of points for face (expected 3, found " + tokens.length + ")");
}
}
// f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...
if (isValidFace_V_VT_VN_Line(line))
{
face.vertices = new Vertex[tokens.length];
face.textureCoordinates = new TextureCoordinate[tokens.length];
face.vertexNormals = new Vertex[tokens.length];
for (int i = 0; i < tokens.length; ++i)
{
subTokens = tokens[i].split("/");
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
face.textureCoordinates[i] = textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1);
face.vertexNormals[i] = vertexNormals.get(Integer.parseInt(subTokens[2]) - 1);
}
face.faceNormal = face.calculateFaceNormal();
}
// f v1/vt1 v2/vt2 v3/vt3 ...
else if (isValidFace_V_VT_Line(line))
{
face.vertices = new Vertex[tokens.length];
face.textureCoordinates = new TextureCoordinate[tokens.length];
for (int i = 0; i < tokens.length; ++i)
{
subTokens = tokens[i].split("/");
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
face.textureCoordinates[i] = textureCoordinates.get(Integer.parseInt(subTokens[1]) - 1);
}
face.faceNormal = face.calculateFaceNormal();
}
// f v1//vn1 v2//vn2 v3//vn3 ...
else if (isValidFace_V_VN_Line(line))
{
face.vertices = new Vertex[tokens.length];
face.vertexNormals = new Vertex[tokens.length];
for (int i = 0; i < tokens.length; ++i)
{
subTokens = tokens[i].split("//");
face.vertices[i] = vertices.get(Integer.parseInt(subTokens[0]) - 1);
face.vertexNormals[i] = vertexNormals.get(Integer.parseInt(subTokens[1]) - 1);
}
face.faceNormal = face.calculateFaceNormal();
}
// f v1 v2 v3 ...
else if (isValidFace_V_Line(line))
{
face.vertices = new Vertex[tokens.length];
for (int i = 0; i < tokens.length; ++i)
{
face.vertices[i] = vertices.get(Integer.parseInt(tokens[i]) - 1);
}
face.faceNormal = face.calculateFaceNormal();
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return face;
}
private GroupObject parseGroupObject(String line, int lineCount) throws ModelFormatException
{
GroupObject group = null;
if (isValidGroupObjectLine(line))
{
String trimmedLine = line.substring(line.indexOf(" ") + 1);
if (trimmedLine.length() > 0)
{
group = new GroupObject(trimmedLine);
}
}
else
{
throw new ModelFormatException("Error parsing entry ('" + line + "'" + ", line " + lineCount + ") in file '" + fileName + "' - Incorrect format");
}
return group;
}
/***
* Verifies that the given line from the model file is a valid vertex
* @param line the line being validated
* @return true if the line is a valid vertex, false otherwise
*/
private static boolean isValidVertexLine(String line)
{
if (vertexMatcher != null)
{
vertexMatcher.reset();
}
vertexMatcher = vertexPattern.matcher(line);
return vertexMatcher.matches();
}
/***
* Verifies that the given line from the model file is a valid vertex normal
* @param line the line being validated
* @return true if the line is a valid vertex normal, false otherwise
*/
private static boolean isValidVertexNormalLine(String line)
{
if (vertexNormalMatcher != null)
{
vertexNormalMatcher.reset();
}
vertexNormalMatcher = vertexNormalPattern.matcher(line);
return vertexNormalMatcher.matches();
}
/***
* Verifies that the given line from the model file is a valid texture coordinate
* @param line the line being validated
* @return true if the line is a valid texture coordinate, false otherwise
*/
private static boolean isValidTextureCoordinateLine(String line)
{
if (textureCoordinateMatcher != null)
{
textureCoordinateMatcher.reset();
}
textureCoordinateMatcher = textureCoordinatePattern.matcher(line);
return textureCoordinateMatcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face that is described by vertices, texture coordinates, and vertex normals
* @param line the line being validated
* @return true if the line is a valid face that matches the format "f v1/vt1/vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
*/
private static boolean isValidFace_V_VT_VN_Line(String line)
{
if (face_V_VT_VN_Matcher != null)
{
face_V_VT_VN_Matcher.reset();
}
face_V_VT_VN_Matcher = face_V_VT_VN_Pattern.matcher(line);
return face_V_VT_VN_Matcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face that is described by vertices and texture coordinates
* @param line the line being validated
* @return true if the line is a valid face that matches the format "f v1/vt1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
*/
private static boolean isValidFace_V_VT_Line(String line)
{
if (face_V_VT_Matcher != null)
{
face_V_VT_Matcher.reset();
}
face_V_VT_Matcher = face_V_VT_Pattern.matcher(line);
return face_V_VT_Matcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face that is described by vertices and vertex normals
* @param line the line being validated
* @return true if the line is a valid face that matches the format "f v1//vn1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
*/
private static boolean isValidFace_V_VN_Line(String line)
{
if (face_V_VN_Matcher != null)
{
face_V_VN_Matcher.reset();
}
face_V_VN_Matcher = face_V_VN_Pattern.matcher(line);
return face_V_VN_Matcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face that is described by only vertices
* @param line the line being validated
* @return true if the line is a valid face that matches the format "f v1 ..." (with a minimum of 3 points in the face, and a maximum of 4), false otherwise
*/
private static boolean isValidFace_V_Line(String line)
{
if (face_V_Matcher != null)
{
face_V_Matcher.reset();
}
face_V_Matcher = face_V_Pattern.matcher(line);
return face_V_Matcher.matches();
}
/***
* Verifies that the given line from the model file is a valid face of any of the possible face formats
* @param line the line being validated
* @return true if the line is a valid face that matches any of the valid face formats, false otherwise
*/
private static boolean isValidFaceLine(String line)
{
return isValidFace_V_VT_VN_Line(line) || isValidFace_V_VT_Line(line) || isValidFace_V_VN_Line(line) || isValidFace_V_Line(line);
}
/***
* Verifies that the given line from the model file is a valid group (or object)
* @param line the line being validated
* @return true if the line is a valid group (or object), false otherwise
*/
private static boolean isValidGroupObjectLine(String line)
{
if (groupObjectMatcher != null)
{
groupObjectMatcher.reset();
}
groupObjectMatcher = groupObjectPattern.matcher(line);
return groupObjectMatcher.matches();
}
@Override
public String getType()
{
return "obj";
}
}
@@ -0,0 +1,338 @@
package net.minecraftforge.client.model.techne;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.lwjgl.opengl.GL11;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraftforge.client.model.IModelCustom;
import net.minecraftforge.client.model.ModelFormatException;
import net.minecraftforge.client.model.obj.GroupObject;
/**
* Techne model importer, based on iChun's Hats importer
*/
@SideOnly(Side.CLIENT)
public class TechneModel extends ModelBase implements IModelCustom {
public static final List<String> cubeTypes = Arrays.asList(
"d9e621f7-957f-4b77-b1ae-20dcd0da7751",
"de81aa14-bd60-4228-8d8d-5238bcd3caaa"
);
private String fileName;
private Map<String, byte[]> zipContents = new HashMap<String, byte[]>();
private Map<String, ModelRenderer> parts = new LinkedHashMap<String, ModelRenderer>();
private String texture = null;
private int textureName;
private boolean textureNameSet = false;
public TechneModel(String fileName, URL resource) throws ModelFormatException
{
this.fileName = fileName;
loadTechneModel(resource);
}
private void loadTechneModel(URL fileURL) throws ModelFormatException
{
try
{
ZipInputStream zipInput = new ZipInputStream(fileURL.openStream());
ZipEntry entry;
while ((entry = zipInput.getNextEntry()) != null)
{
byte[] data = new byte[(int) entry.getSize()];
// For some reason, using read(byte[]) makes reading stall upon reaching a 0x1E byte
int i = 0;
while (zipInput.available() > 0 && i < data.length)
{
data[i++] = (byte)zipInput.read();
}
zipContents.put(entry.getName(), data);
}
byte[] modelXml = zipContents.get("model.xml");
if (modelXml == null)
{
throw new ModelFormatException("Model " + fileName + " contains no model.xml file");
}
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(new ByteArrayInputStream(modelXml));
NodeList nodeListTechne = document.getElementsByTagName("Techne");
if (nodeListTechne.getLength() < 1)
{
throw new ModelFormatException("Model " + fileName + " contains no Techne tag");
}
NodeList nodeListModel = document.getElementsByTagName("Model");
if (nodeListModel.getLength() < 1)
{
throw new ModelFormatException("Model " + fileName + " contains no Model tag");
}
NamedNodeMap modelAttributes = nodeListModel.item(0).getAttributes();
if (modelAttributes == null)
{
throw new ModelFormatException("Model " + fileName + " contains a Model tag with no attributes");
}
Node modelTexture = modelAttributes.getNamedItem("texture");
if (modelTexture != null)
{
texture = modelTexture.getTextContent();
}
NodeList shapes = document.getElementsByTagName("Shape");
for (int i = 0; i < shapes.getLength(); i++)
{
Node shape = shapes.item(i);
NamedNodeMap shapeAttributes = shape.getAttributes();
if (shapeAttributes == null)
{
throw new ModelFormatException("Shape #" + (i + 1) + " in " + fileName + " has no attributes");
}
Node name = shapeAttributes.getNamedItem("name");
String shapeName = null;
if (name != null)
{
shapeName = name.getNodeValue();
}
if (shapeName == null)
{
shapeName = "Shape #" + (i + 1);
}
String shapeType = null;
Node type = shapeAttributes.getNamedItem("type");
if (type != null)
{
shapeType = type.getNodeValue();
}
if (shapeType != null && !cubeTypes.contains(shapeType))
{
FMLLog.warning("Model shape [" + shapeName + "] in " + fileName + " is not a cube, ignoring");
continue;
}
try
{
boolean mirrored = false;
String[] offset = new String[3];
String[] position = new String[3];
String[] rotation = new String[3];
String[] size = new String[3];
String[] textureOffset = new String[2];
NodeList shapeChildren = shape.getChildNodes();
for (int j = 0; j < shapeChildren.getLength(); j++)
{
Node shapeChild = shapeChildren.item(j);
String shapeChildName = shapeChild.getNodeName();
String shapeChildValue = shapeChild.getTextContent();
if (shapeChildValue != null)
{
shapeChildValue = shapeChildValue.trim();
if (shapeChildName.equals("IsMirrored"))
{
mirrored = !shapeChildValue.equals("False");
}
else if (shapeChildName.equals("Offset"))
{
offset = shapeChildValue.split(",");
}
else if (shapeChildName.equals("Position"))
{
position = shapeChildValue.split(",");
}
else if (shapeChildName.equals("Rotation"))
{
rotation = shapeChildValue.split(",");
}
else if (shapeChildName.equals("Size"))
{
size = shapeChildValue.split(",");
}
else if (shapeChildName.equals("TextureOffset"))
{
textureOffset = shapeChildValue.split(",");
}
}
}
// That's what the ModelBase subclassing is needed for
ModelRenderer cube = new ModelRenderer(this, Integer.parseInt(textureOffset[0]), Integer.parseInt(textureOffset[1]));
cube.mirror = mirrored;
cube.addBox(Float.parseFloat(offset[0]), Float.parseFloat(offset[1]), Float.parseFloat(offset[2]), Integer.parseInt(size[0]), Integer.parseInt(size[1]), Integer.parseInt(size[2]));
cube.setRotationPoint(Float.parseFloat(position[0]), Float.parseFloat(position[1]) - 23.4F, Float.parseFloat(position[2]));
cube.rotateAngleX = (float)Math.toRadians(Float.parseFloat(rotation[0]));
cube.rotateAngleY = (float)Math.toRadians(Float.parseFloat(rotation[1]));
cube.rotateAngleZ = (float)Math.toRadians(Float.parseFloat(rotation[2]));
parts.put(shapeName, cube);
}
catch (NumberFormatException e)
{
FMLLog.warning("Model shape [" + shapeName + "] in " + fileName + " contains malformed integers within its data, ignoring");
e.printStackTrace();
}
}
}
catch (ZipException e)
{
throw new ModelFormatException("Model " + fileName + " is not a valid zip file");
}
catch (IOException e)
{
throw new ModelFormatException("Model " + fileName + " could not be read", e);
}
catch (ParserConfigurationException e)
{
// hush
}
catch (SAXException e)
{
throw new ModelFormatException("Model " + fileName + " contains invalid XML", e);
}
}
private void bindTexture()
{
/* TODO: Update to 1.6
if (texture != null)
{
if (!textureNameSet)
{
try
{
byte[] textureEntry = zipContents.get(texture);
if (textureEntry == null)
{
throw new ModelFormatException("Model " + fileName + " has no such texture " + texture);
}
BufferedImage image = ImageIO.read(new ByteArrayInputStream(textureEntry));
textureName = Minecraft.getMinecraft().renderEngine.allocateAndSetupTexture(image);
textureNameSet = true;
}
catch (ZipException e)
{
throw new ModelFormatException("Model " + fileName + " is not a valid zip file");
}
catch (IOException e)
{
throw new ModelFormatException("Texture for model " + fileName + " could not be read", e);
}
}
if (textureNameSet)
{
GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureName);
Minecraft.getMinecraft().renderEngine.resetBoundTexture();
}
}
*/
}
@Override
public String getType()
{
return "tcn";
}
@Override
public void renderAll()
{
bindTexture();
for (ModelRenderer part : parts.values())
{
part.renderWithRotation(1.0F);
}
}
@Override
public void renderPart(String partName)
{
ModelRenderer part = parts.get(partName);
if (part != null)
{
bindTexture();
part.renderWithRotation(1.0F);
}
}
@Override
public void renderOnly(String... groupNames)
{
bindTexture();
for (ModelRenderer part : parts.values())
{
for (String groupName : groupNames)
{
if (groupName.equalsIgnoreCase(part.boxName))
{
part.render(1.0f);
}
}
}
}
@Override
public void renderAllExcept(String... excludedGroupNames)
{
for (ModelRenderer part : parts.values())
{
boolean skipPart=false;
for (String excludedGroupName : excludedGroupNames)
{
if (excludedGroupName.equalsIgnoreCase(part.boxName))
{
skipPart=true;
}
}
if(!skipPart)
{
part.render(1.0f);
}
}
}
}
@@ -0,0 +1,33 @@
package net.minecraftforge.client.model.techne;
import java.net.URL;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraftforge.client.model.IModelCustom;
import net.minecraftforge.client.model.IModelCustomLoader;
import net.minecraftforge.client.model.ModelFormatException;
public class TechneModelLoader implements IModelCustomLoader {
@Override
public String getType()
{
return "Techne model";
}
private static final String[] types = { "tcn" };
@Override
public String[] getSuffixes()
{
return types;
}
@Override
public IModelCustom loadInstance(String resourceName, URL resource) throws ModelFormatException
{
return new TechneModel(resourceName, resource);
}
}
@@ -7,13 +7,13 @@ import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import javax.sound.sampled.AudioFormat;
import paulscode.sound.ICodec;
import paulscode.sound.SoundBuffer;
import paulscode.sound.SoundSystemConfig;
import paulscode.sound.SoundSystemLogger;
import ibxm.FastTracker2;
import ibxm.IBXM;
import ibxm.Module;
@@ -170,7 +170,6 @@ public class CodecIBXM implements ICodec
* will call the reverseByteOrder() method.
* @param b True if the calling audio library requires byte-reversal.
*/
@Override
public void reverseByteOrder( boolean b )
{
reverseBytes = b;
@@ -182,7 +181,6 @@ public class CodecIBXM implements ICodec
* @param url URL to an audio file to stream from.
* @return False if an error occurred or if end of stream was reached.
*/
@Override
public boolean initialize( URL url )
{
initialized( SET, false );
@@ -267,7 +265,6 @@ public class CodecIBXM implements ICodec
* Returns false if the stream is busy initializing.
* @return True if steam is initialized.
*/
@Override
public boolean initialized()
{
return initialized( GET, XXX );
@@ -279,7 +276,6 @@ public class CodecIBXM implements ICodec
* information about accessing and changing default settings.
* @return The audio data wrapped into a SoundBuffer context.
*/
@Override
public SoundBuffer read()
{
if( endOfStream( GET, XXX ) )
@@ -337,7 +333,6 @@ public class CodecIBXM implements ICodec
* information about accessing and changing default settings.
* @return the audio data wrapped into a SoundBuffer context.
*/
@Override
public SoundBuffer readAll()
{
if( module == null )
@@ -398,7 +393,6 @@ public class CodecIBXM implements ICodec
* Returns false if there is still more data available to be read in.
* @return True if end of stream was reached.
*/
@Override
public boolean endOfStream()
{
return endOfStream( GET, XXX );
@@ -407,7 +401,6 @@ public class CodecIBXM implements ICodec
/**
* Closes the audio stream and remove references to all instantiated objects.
*/
@Override
public void cleanup()
{
// if( ibxm != null )
@@ -420,7 +413,6 @@ public class CodecIBXM implements ICodec
* readAll() methods.
* @return Information wrapped into an AudioFormat context.
*/
@Override
public AudioFormat getAudioFormat()
{
return myAudioFormat;
@@ -501,7 +493,6 @@ public class CodecIBXM implements ICodec
* @param maxLength Maximum size this array may be.
* @return New array.
*/
@SuppressWarnings("unused") //Forge
private static byte[] trimArray( byte[] array, int maxLength )
{
byte[] trimmedArray = null;
@@ -546,7 +537,6 @@ public class CodecIBXM implements ICodec
* @param two_bytes_data For stereo sounds.
* @return byte array containing the converted data.
*/
@SuppressWarnings("unused") //Forge
private static byte[] convertAudioBytes( byte[] audio_bytes,
boolean two_bytes_data )
{
+5
View File
@@ -0,0 +1,5 @@
commands.forge.usage=Use /forge <subcommand>. Subcommands are tps, track
commands.forge.usage.tracking=Use /forge track <type> <duration>. Valid types are te (Tile Entities). Duration is < 60.
commands.forge.tps.summary=%s : Mean tick time: %d ms. Mean TPS: %d
commands.forge.tracking.te.enabled=Tile Entity tracking enabled for %d seconds.
+5
View File
@@ -0,0 +1,5 @@
commands.forge.usage=Usa /forge <subcomando>. Los subcomandos son tps, track
commands.forge.usage.tracking=Usa /forge track <tipo> <duración>. Los tipos válidos te (Tile Entities). La duración es < 60.
commands.forge.tps.summary=%s : Tiempo de tick medio: %d ms. TPS medio: %d
commands.forge.tracking.te.enabled=Rastreo de Tile Entity activado durante %d segundos.
+5
View File
@@ -0,0 +1,5 @@
commands.forge.usage=Utilisez /forge <sous-commande>. Les sous-commandes sont tps, track
commands.forge.usage.tracking=Utilisez /forge track <type> <durée>. Les types valides sont te (Tile Entities). La durée doit être inférieur à 60.
commands.forge.tps.summary=%s : Duré de tick : %d ms. TPS moyen : %d
commands.forge.tracking.te.enabled=Trackage des Tile Entity activé pour %d secondes.
+160
View File
@@ -0,0 +1,160 @@
#Main Forge Access Transformer configuration file
# Tessellator
public-f bfq.a #FD:Tessellator/field_78398_a #instance
public bfq.u #FD:Tessellator/field_78409_u #drawMode
public bfq.v #FD:Tessellator/field_78408_v #xOffset
public bfq.w #FD:Tessellator/field_78407_w #yOffset
public bfq.x #FD:Tessellator/field_78417_x #zOffset
public bfq.z #FD:Tessellator/field_78415_z #isDrawing
# ItemPickaxe
public yn.<init>(ILyd;)V #MD:ItemPickaxe/<init>(ILnet/minecraft/src/EnumToolMaterial;) #constructor
public+f yn.c #FD:ItemPickaxe/field_77867_c #blocksEffectiveAgainst
# ItemAxe
public ya.<init>(ILyd;)V #MD:ItemAxe/<init>(ILnet/minecraft/src/EnumToolMaterial;) #constructor
public+f ya.c #FD:ItemAxe/field_77868_c #blocksEffectiveAgainst
# ItemSpade
public yy.<init>(ILyd;)V #MD:ItemSpade/<init>(ILnet/minecraft/src/EnumToolMaterial;) #constructor
public+f yy.c #FD:ItemSpade/field_77866_c #blocksEffectiveAgainst
# ItemTool
public xj.a #FD:ItemTool/field_77864_a #efficiencyOnProperMaterial
public xj.d #FD:ItemTool/field_77865_bY #damageVsEntity
# EntityEnderman
public tg.br #FD:EntityEnderman/field_70827_d #carriableBlocks
# RenderGlobal
public bfl.k #FD:RenderGlobal/field_72769_h #theWorld
public bfl.l #FD:RenderGlobal/field_72770_i #renderEngine
public bfl.t #FD:RenderGlobal/field_72777_q #mc
public bfl.u #FD:RenderGlobal/field_72776_r #globalRenderBlocks
public bfl.H #FD:RenderGlobal/field_72738_E #damagedBlocks
# SoundManager
public bln.b #FD:SoundManager/field_77381_a #sndSystem
public bln.d #FD:SoundManager/field_77379_b #soundPoolSounds
public bln.e #FD:SoundManager/field_77380_c #soundPoolStreaming
public bln.f #FD:SoundManager/field_77377_d #soundPoolMusic
# EntityMinecart
protected st.* #FD:EntityMinecart/* # All private -> protected
# Block
public aqz.<init>(ILakc;)V #MD:Block/<init>(ILnet/minecraft/src/Material;) #Constructor
public aqz.<init>(IILakc;)V #MD:Block/<init>(IILnet/minecraft/src/Material;) #Constructor
public aqz.cH #FD:Block/field_72029_cc #blockResistance
public aqz.cG #FD:Block/field_71989_cb #blockHardness
public aqz.d(Ljava/lang/String;)Laqz; #MD:Block/func_111022_d #setIconName
public aqz.a(Lard;)Laqz; #MD:Block/func_71884_a #setStepSound
public aqz.b(F)Laqz; #MD:Block/func_71894_b #setResistance
public aqz.c(F)Laqz; #MD:Block/func_71848_c #setHardness
public aqz.k(I)Laqz; #MD:Block/func_71868_h #setLightOpacity
public aqz.a(F)Laqz; #MD:Block/func_71900_a #setLightValue
public aqz.r()Laqz; #MD:Block/func_71875_q #setBlockUnbreakable
public aqz.b(Z)Laqz; #MD:Block/func_71907_b #setTickRandomly
public aqz.a(FFFFFF)V #MD:Block/func_71905_a #setBlockBounds
public aqz.j(Labw;IIII)V #MD:Block/func_71923_g #dropXpOnBlockBreak
# NetServerHandler
public ka.f #FD:NetServerHandler/field_72572_g #playerInAirTime
# TileEntity
public asp.k #FD:TileEntity/field_70331_k #worldObj
# BlockLeavesBase
public arh.d #FD:BlockLeavesBase/field_72131_c #graphicsLevel
# Item
public yc.<init>(I)V #MD:Item/<init>(I) #Constructor
public yc.e(I)Lyc; #MD:Item/func_77656_e #setMaxDamage
public-f yc.h(Lye;)Lms; #MD:Item/func_77650_f #getIconIndex
public yc.c(Ljava/lang/String;)Lyc; #MD:Item/func_77631_c #setPotionEffect
public yc.d(Ljava/lang/String;)Lyc; #MD:Item/func_111206_d #setIconName
# RailLogic
public amz #CL:BlockBaseRailLogic
public amz.a()I #MD:BlockBaseRailLogic/func_94505_a #getNAdjacentTiles
# EntityPlayer
public uf.a(Lss;)V #MD:EntityPlayer/func_71012_a #joinEntityItemWithWorld
public uf.i()V #MD:EntityPlayer/func_71053_j #closeScreen
public uf.b #FD:EntityPlayer/field_71076_b #sleepTimer
# EntityPlayerMP
public bdi.a(Lss;)V #MD:EntityClientPlayerMP/func_71012_a #joinEntityItemWithWorld
# World Gen Chests Related
public mk.* #FD:WeightedRandomChestContent/* #all
public js.T #FD:WorldServer/field_73069_S #bonusChestContent
public agh.a #FD:StructureMineshaftPieces/field_78818_a #mineshaftChestContents
public ahl.i #FD:ComponentScatteredFeatureDesertPyramid/field_74941_i #itemsToGenerateInTemple
public ahm.l #FD:ComponentScatteredFeatureJunglePyramid/field_74943_l #junglePyramidsChestContents
public ahm.m #FD:ComponentScatteredFeatureJunglePyramid/field_74944_m #junglePyramidsDispenserContents
public ahw.a #FD:ComponentStrongholdChestCorridor/field_75003_a #strongholdChestContents
public aia.a #FD:ComponentStrongholdLibrary/field_75007_b #strongholdLibraryChestContents
public aif.b #FD:ComponentStrongholdRoomCrossing/field_75014_c #strongholdCorridorChestContents
public aji.a #FD:ComponentVillageHouse2/field_74918_a #villageBlacksmithChestContents
public afp.a #FD:WorldGenDungeons/field_111189_a #chestContents
# AnvilChunkLoader.chunkSaveLocation
public aee.d #FD:AnvilChunkLoader/field_75825_d
# ChunkProviderServer.currentChunkLoader
public jr.e #FD:ChunkProviderServer/field_73247_e
# PlayerManager
public jp.a(IIZ)Ljq; #MD:PlayerManager/func_72690_a #getOrCreateChunkWatcher
# PlayerInstance
public jq #CL:PlayerInstance
# World
public-f abw.A #FD:World/field_72982_D #villageCollectionObj
public abw.G #FD:World/field_72993_I #activeChunkSet
# EntityLiving
public og.b #FD:EntityLiving/field_70728_aV #experienceValue
public og.d #FD:EntityLiving/field_70715_bh #targetTasks
# GuiFlatPresets
public avz.a(Ljava/lang/String;ILacq;Ljava/util/List;[Lagd;)V #MD:GuiFlatPresets/func_82294_a
public avz.a(Ljava/lang/String;ILacq;[Lagd;)V #MD:GuiFlatPresets/func_82297_a
# BiomeGenBase
public acq.*() #MD:BiomeGenBase/* #Everything protected->public
# MapGenVillage
public-f aiw.e #FD:MapGenVillage/field_75055_e #villageSpawnBiomes
# ShapedRecipes
public+f aai.d #FD:ShapedRecipes/field_77574_d #recipeItems
public+f aai.b #FD:ShapedRecipes/field_77576_b #recipeWidth
public+f aai.c #FD:ShapedRecipes/field_77577_c #recipeHeight
# ShapelessRecipes
public aaj.b #FD:ShapelessRecipes/field_77579_b #recipeItems
# GuiContainer
protected awy.a(Lwe;)V #MD:GuiContainer/func_74192_a #drawSlotInventory
# ContainerPlayer
protected vv.h #FD:ContainerPlayer/field_82862_h #player
# BlockButton
protected anf.n(Labw;III)V #MD:BlockButton/func_82535_o #checkActivation
protected-f anf.a #FD:BlockButton/field_82537_a #sensible
# BiomeDecorator
public acu.* #FD:BiomeDecorator/* # All private -> protected
# CreativeTabs
public-f ww.a #FD:CreativeTabs/field_78032_a # creativeTabArray non-final
# Packet
public ey.a(IZZLjava/lang/Class;)V #MD:Packet/func_73285_a #addIdClassMapping
# SaveHandler
public alq.b()Ljava/io/File; #MD:SaveHandler/func_75765_b
# World stuff
public abw.b(Lnn;)V #MD:World/func_72847_b #releaseEntitySkin
public abw.m #FD:World/field_73003_n #prevRainingStrength
public abw.n #FD:World/field_73004_o #rainingStrength
public abw.p #FD:World/field_73017_q #thunderingStrength
public abw.o #FD:World/field_73018_p #prevThunderingStrength
#WorldClient
public bdd.b(Lnn;)V #MD:WorldClient/func_72847_b #releaseEntitySkin
#WorldServer
public js.b(Lnn;)V #MD:WorldServer/func_72847_b #releaseEntitySkin
public js.N #FD:WorldServer/field_73068_P #allPlayersSleeping
#TextureMap
public bik.g #FD:TextureMap/field_94255_a
public bik.h #FD:TextureMap/field_94254_c
#Potion
public ni.b(II)Lni; #MD:Potion/func_76399_b #setIconIndex
#PotionHelper
public zp.m #FD:PotionHelper/field_77927_l #potionRequirements
public zp.n #FD:PotionHelper/field_77928_m #potionAmplifiers
#PotionEffect
public nj.b #FD:PotionEffect/field_76460_b #duration
#BlockFluid
protected apc.a #FD:BlockFluid/field_94425_a #theIcon
#GuiIngame
protected avj.* #FD:GuiIngame/* # All private -> protected
protected avj.*() #MD:GuiIngame/* # All private -> protected
#ItemStack
default ye.f #FD:ItemStack/field_77991_e # make default access for itemDamage
#GuiSlot
protected awg.b(IIII)V #MD:GuiSlot/func_77206_b #overlayBackground
#EntityPlayer
public uf.bu #FD:EntityPlayer/field_71092_bJ #username
#MapGenStructureIO
public air.b(Ljava/lang/Class;Ljava/lang/String;)V #MD:MapGenStructureIO/func_143034_b #registerStart
public air.a(Ljava/lang/Class;Ljava/lang/String;)V #MD:MapGenStructureIO/func_143031_a #registerPiece
@@ -0,0 +1,46 @@
package net.minecraftforge.classloading;
import java.io.File;
import java.util.Map;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
public class FMLForgePlugin implements IFMLLoadingPlugin
{
public static boolean RUNTIME_DEOBF = false;
public static File forgeLocation;
@Override
public String[] getLibraryRequestClass()
{
return null;
}
@Override
public String[] getASMTransformerClass()
{
return new String[]{
"net.minecraftforge.transformers.ForgeAccessTransformer",
"net.minecraftforge.transformers.EventTransformer"
};
}
@Override
public String getModContainerClass()
{
return "net.minecraftforge.common.ForgeDummyContainer";
}
@Override
public String getSetupClass()
{
return null;
}
@Override
public void injectData(Map<String, Object> data)
{
RUNTIME_DEOBF = (Boolean)data.get("runtimeDeobfuscationEnabled");
forgeLocation = (File)data.get("coremodLocation");
}
}
@@ -1,22 +1,3 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
@@ -0,0 +1,319 @@
package net.minecraftforge.common;
import java.util.*;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.world.biome.*;
import net.minecraftforge.event.terraingen.DeferredBiomeDecorator;
import static net.minecraft.world.biome.BiomeGenBase.*;
import static net.minecraftforge.common.BiomeDictionary.Type.*;
public class BiomeDictionary
{
public enum Type
{
FOREST,
PLAINS,
MOUNTAIN,
HILLS,
SWAMP,
WATER,
DESERT,
FROZEN,
JUNGLE,
WASTELAND,
BEACH,
NETHER,
END,
MUSHROOM,
MAGICAL;
}
private static final int BIOME_LIST_SIZE = 256;
private static BiomeInfo[] biomeList = new BiomeInfo[BIOME_LIST_SIZE];
private static ArrayList<BiomeGenBase>[] typeInfoList = new ArrayList[Type.values().length];
private static class BiomeInfo
{
public EnumSet<Type> typeList;
public BiomeInfo(Type[] types)
{
typeList = EnumSet.noneOf(Type.class);
for(Type t : types)
{
typeList.add(t);
}
}
}
static
{
registerVanillaBiomes();
}
/**
* Registers a biome with a specific biome type
*
* @param biome the biome to be registered
* @param type the type to register the biome as
* @return returns true if the biome was registered successfully
*/
public static boolean registerBiomeType(BiomeGenBase biome, Type ... types)
{
if(BiomeGenBase.biomeList[biome.biomeID] != null)
{
for(Type type : types)
{
if(typeInfoList[type.ordinal()] == null)
{
typeInfoList[type.ordinal()] = new ArrayList<BiomeGenBase>();
}
typeInfoList[type.ordinal()].add(biome);
}
if(biomeList[biome.biomeID] == null)
{
biomeList[biome.biomeID] = new BiomeInfo(types);
}
else
{
for(Type type : types)
{
biomeList[biome.biomeID].typeList.add(type);
}
}
return true;
}
return false;
}
/**
* Returns a list of biomes registered with a specific type
*
* @param type the Type to look for
* @return a list of biomes of the specified type, null if there are none
*/
public static BiomeGenBase[] getBiomesForType(Type type)
{
if(typeInfoList[type.ordinal()] != null)
{
return (BiomeGenBase[])typeInfoList[type.ordinal()].toArray(new BiomeGenBase[0]);
}
return new BiomeGenBase[0];
}
/**
* Gets a list of Types that a specific biome is registered with
*
* @param biome the biome to check
* @return the list of types, null if there are none
*/
public static Type[] getTypesForBiome(BiomeGenBase biome)
{
checkRegistration(biome);
if(biomeList[biome.biomeID] != null)
{
return (Type[])biomeList[biome.biomeID].typeList.toArray(new Type[0]);
}
return new Type[0];
}
/**
* Checks to see if two biomes are registered as having the same type
*
* @param biomeA
* @param biomeB
* @return returns true if a common type is found, false otherwise
*/
public static boolean areBiomesEquivalent(BiomeGenBase biomeA, BiomeGenBase biomeB)
{
int a = biomeA.biomeID;
int b = biomeB.biomeID;
checkRegistration(biomeA);
checkRegistration(biomeB);
if(biomeList[a] != null && biomeList[b] != null)
{
for(Type type : biomeList[a].typeList)
{
if(containsType(biomeList[b], type))
{
return true;
}
}
}
return false;
}
/**
* Checks to see if the given biome is registered as being a specific type
*
* @param biome the biome to be considered
* @param type the type to check for
* @return returns true if the biome is registered as being of type type, false otherwise
*/
public static boolean isBiomeOfType(BiomeGenBase biome, Type type)
{
checkRegistration(biome);
if(biomeList[biome.biomeID] != null)
{
return containsType(biomeList[biome.biomeID], type);
}
return false;
}
/**
* Checks to see if the given biome has been registered as being of any type
* @param biome the biome to consider
* @return returns true if the biome has been registered, false otherwise
*/
public static boolean isBiomeRegistered(BiomeGenBase biome)
{
return biomeList[biome.biomeID] != null;
}
public static boolean isBiomeRegistered(int biomeID)
{
return biomeList[biomeID] != null;
}
public static void registerAllBiomes()
{
FMLLog.warning("Redundant call to BiomeDictionary.registerAllBiomes ignored");
}
/**
* Loops through the biome list and automatically adds tags to any biome that does not have any
* This is called by Forge at postinit time. It will additionally dispatch any deferred decorator
* creation events.
*
* DO NOT call this during world generation
*/
public static void registerAllBiomesAndGenerateEvents()
{
for(int i = 0; i < BiomeGenBase.biomeList.length; i++)
{
BiomeGenBase biome = BiomeGenBase.biomeList[i];
if(biome == null)
{
continue;
}
if (biome.theBiomeDecorator instanceof DeferredBiomeDecorator)
{
DeferredBiomeDecorator decorator = (DeferredBiomeDecorator) biome.theBiomeDecorator;
decorator.fireCreateEventAndReplace();
}
checkRegistration(biome);
}
}
/**
* Automatically looks for and registers a given biome with appropriate tags
* This method is called automatically if a biome has not been registered with any tags,
* And another method requests information about it
*
* NOTE: You can opt out of having your biome registered by registering it as type NULL
*
* @param biome the biome to be considered
*/
public static void makeBestGuess(BiomeGenBase biome)
{
if(biome.theBiomeDecorator.treesPerChunk >= 3)
{
if(biome.isHighHumidity() && biome.temperature >= 1.0F)
{
BiomeDictionary.registerBiomeType(biome, JUNGLE);
}
else if(!biome.isHighHumidity())
{
BiomeDictionary.registerBiomeType(biome, FOREST);
}
}
else if(biome.maxHeight <= 0.3F && biome.maxHeight >= 0.0F)
{
if(!biome.isHighHumidity() || biome.minHeight >= 0.0F)
{
BiomeDictionary.registerBiomeType(biome, PLAINS);
}
}
if(biome.isHighHumidity() && biome.minHeight < 0.0F && (biome.maxHeight <= 0.3F && biome.maxHeight >= 0.0F))
{
BiomeDictionary.registerBiomeType(biome, SWAMP);
}
if(biome.minHeight <= -0.5F)
{
BiomeDictionary.registerBiomeType(biome, WATER);
}
if(biome.maxHeight >= 1.5F)
{
BiomeDictionary.registerBiomeType(biome, MOUNTAIN);
}
if(biome.getEnableSnow() || biome.temperature < 0.2F)
{
BiomeDictionary.registerBiomeType(biome, FROZEN);
}
if(!biome.isHighHumidity() && biome.temperature >= 1.0F)
{
BiomeDictionary.registerBiomeType(biome, DESERT);
}
}
//Internal implementation
private static void checkRegistration(BiomeGenBase biome)
{
if(!isBiomeRegistered(biome))
{
makeBestGuess(biome);
}
}
private static boolean containsType(BiomeInfo info, Type type)
{
return info.typeList.contains(type);
}
private static void registerVanillaBiomes()
{
registerBiomeType(ocean, WATER );
registerBiomeType(plains, PLAINS );
registerBiomeType(desert, DESERT );
registerBiomeType(extremeHills, MOUNTAIN );
registerBiomeType(forest, FOREST );
registerBiomeType(taiga, FOREST, FROZEN);
registerBiomeType(taigaHills, FOREST, FROZEN);
registerBiomeType(swampland, SWAMP );
registerBiomeType(river, WATER );
registerBiomeType(frozenOcean, WATER, FROZEN);
registerBiomeType(frozenRiver, WATER, FROZEN);
registerBiomeType(icePlains, FROZEN );
registerBiomeType(iceMountains, FROZEN );
registerBiomeType(beach, BEACH );
registerBiomeType(desertHills, DESERT );
registerBiomeType(jungle, JUNGLE );
registerBiomeType(jungleHills, JUNGLE );
registerBiomeType(forestHills, FOREST );
registerBiomeType(sky, END );
registerBiomeType(hell, NETHER );
registerBiomeType(mushroomIsland, MUSHROOM );
registerBiomeType(extremeHillsEdge, MOUNTAIN );
registerBiomeType(mushroomIslandShore, MUSHROOM, BEACH);
}
}
@@ -0,0 +1,70 @@
package net.minecraftforge.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.world.biome.BiomeGenBase;
import net.minecraft.world.gen.ChunkProviderGenerate;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.structure.MapGenStronghold;
import net.minecraft.world.gen.structure.MapGenVillage;
import net.minecraft.world.biome.WorldChunkManager;
import com.google.common.collect.Lists;
public class BiomeManager
{
public static void addVillageBiome(BiomeGenBase biome, boolean canSpawn)
{
if (!MapGenVillage.villageSpawnBiomes.contains(biome))
{
ArrayList<BiomeGenBase> biomes = new ArrayList<BiomeGenBase>(MapGenVillage.villageSpawnBiomes);
biomes.add(biome);
MapGenVillage.villageSpawnBiomes = biomes;
}
}
public static void removeVillageBiome(BiomeGenBase biome)
{
if (MapGenVillage.villageSpawnBiomes.contains(biome))
{
ArrayList<BiomeGenBase> biomes = new ArrayList<BiomeGenBase>(MapGenVillage.villageSpawnBiomes);
biomes.remove(biome);
MapGenVillage.villageSpawnBiomes = biomes;
}
}
public static void addStrongholdBiome(BiomeGenBase biome)
{
if (!MapGenStronghold.allowedBiomes.contains(biome))
{
MapGenStronghold.allowedBiomes.add(biome);
}
}
public static void removeStrongholdBiome(BiomeGenBase biome)
{
if (MapGenStronghold.allowedBiomes.contains(biome))
{
MapGenStronghold.allowedBiomes.remove(biome);
}
}
public static void addSpawnBiome(BiomeGenBase biome)
{
if (!WorldChunkManager.allowedBiomes.contains(biome))
{
WorldChunkManager.allowedBiomes.add(biome);
}
}
public static void removeSpawnBiome(BiomeGenBase biome)
{
if (WorldChunkManager.allowedBiomes.contains(biome))
{
WorldChunkManager.allowedBiomes.remove(biome);
}
}
}
@@ -0,0 +1,244 @@
package net.minecraftforge.common;
import java.util.*;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraft.world.WorldServer;
import net.minecraft.world.gen.feature.WorldGenDungeons;
import net.minecraft.world.gen.structure.*;
import net.minecraftforge.oredict.OreDictionary;
public class ChestGenHooks
{
//Currently implemented categories for chests/dispensers, Dungeon loot is still in DungeonHooks
public static final String MINESHAFT_CORRIDOR = "mineshaftCorridor";
public static final String PYRAMID_DESERT_CHEST = "pyramidDesertyChest";
public static final String PYRAMID_JUNGLE_CHEST = "pyramidJungleChest";
public static final String PYRAMID_JUNGLE_DISPENSER = "pyramidJungleDispenser";
public static final String STRONGHOLD_CORRIDOR = "strongholdCorridor";
public static final String STRONGHOLD_LIBRARY = "strongholdLibrary";
public static final String STRONGHOLD_CROSSING = "strongholdCrossing";
public static final String VILLAGE_BLACKSMITH = "villageBlacksmith";
public static final String BONUS_CHEST = "bonusChest";
public static final String DUNGEON_CHEST = "dungeonChest";
private static final HashMap<String, ChestGenHooks> chestInfo = new HashMap<String, ChestGenHooks>();
private static boolean hasInit = false;
static
{
init();
}
private static void init()
{
if (hasInit)
{
return;
}
hasInit = true;
addInfo(MINESHAFT_CORRIDOR, StructureMineshaftPieces.mineshaftChestContents, 3, 7);
addInfo(PYRAMID_DESERT_CHEST, ComponentScatteredFeatureDesertPyramid.itemsToGenerateInTemple, 2, 7);
addInfo(PYRAMID_JUNGLE_CHEST, ComponentScatteredFeatureJunglePyramid.junglePyramidsChestContents, 2, 7);
addInfo(PYRAMID_JUNGLE_DISPENSER, ComponentScatteredFeatureJunglePyramid.junglePyramidsDispenserContents, 2, 2);
addInfo(STRONGHOLD_CORRIDOR, ComponentStrongholdChestCorridor.strongholdChestContents, 2, 4);
addInfo(STRONGHOLD_LIBRARY, ComponentStrongholdLibrary.strongholdLibraryChestContents, 1, 5);
addInfo(STRONGHOLD_CROSSING, ComponentStrongholdRoomCrossing.strongholdRoomCrossingChestContents, 1, 5);
addInfo(VILLAGE_BLACKSMITH, ComponentVillageHouse2.villageBlacksmithChestContents, 3, 9);
addInfo(BONUS_CHEST, WorldServer.bonusChestContent, 10, 10);
addInfo(DUNGEON_CHEST, WorldGenDungeons.field_111189_a, 8, 8);
ItemStack book = new ItemStack(Item.enchantedBook, 1, 0);
WeightedRandomChestContent tmp = new WeightedRandomChestContent(book, 1, 1, 1);
getInfo(MINESHAFT_CORRIDOR ).addItem(tmp);
getInfo(PYRAMID_DESERT_CHEST).addItem(tmp);
getInfo(PYRAMID_JUNGLE_CHEST).addItem(tmp);
getInfo(STRONGHOLD_CORRIDOR ).addItem(tmp);
getInfo(STRONGHOLD_LIBRARY ).addItem(new WeightedRandomChestContent(book, 1, 5, 2));
getInfo(STRONGHOLD_CROSSING ).addItem(tmp);
getInfo(DUNGEON_CHEST ).addItem(tmp);
}
static void addDungeonLoot(ChestGenHooks dungeon, ItemStack item, int weight, int min, int max)
{
dungeon.addItem(new WeightedRandomChestContent(item, min, max, weight));
}
private static void addInfo(String category, WeightedRandomChestContent[] items, int min, int max)
{
chestInfo.put(category, new ChestGenHooks(category, items, min, max));
}
/**
* Retrieves, or creates the info class for the specified category.
*
* @param category The category name
* @return A instance of ChestGenHooks for the specified category.
*/
public static ChestGenHooks getInfo(String category)
{
if (!chestInfo.containsKey(category))
{
chestInfo.put(category, new ChestGenHooks(category));
}
return chestInfo.get(category);
}
/**
* Generates an array of items based on the input min/max count.
* If the stack can not hold the total amount, it will be split into
* stacks of size 1.
*
* @param rand A random number generator
* @param source Source item stack
* @param min Minimum number of items
* @param max Maximum number of items
* @return An array containing the generated item stacks
*/
public static ItemStack[] generateStacks(Random rand, ItemStack source, int min, int max)
{
int count = min + (rand.nextInt(max - min + 1));
ItemStack[] ret;
if (source.getItem() == null)
{
ret = new ItemStack[0];
}
else if (count > source.getMaxStackSize())
{
ret = new ItemStack[count];
for (int x = 0; x < count; x++)
{
ret[x] = source.copy();
ret[x].stackSize = 1;
}
}
else
{
ret = new ItemStack[1];
ret[0] = source.copy();
ret[0].stackSize = count;
}
return ret;
}
//shortcut functions, See the non-static versions below
public static WeightedRandomChestContent[] getItems(String category, Random rnd){ return getInfo(category).getItems(rnd); }
public static int getCount(String category, Random rand){ return getInfo(category).getCount(rand); }
public static void addItem(String category, WeightedRandomChestContent item){ getInfo(category).addItem(item); }
public static void removeItem(String category, ItemStack item){ getInfo(category).removeItem(item); }
public static ItemStack getOneItem(String category, Random rand){ return getInfo(category).getOneItem(rand); }
private String category;
private int countMin = 0;
private int countMax = 0;
//TO-DO: Privatize this once again when we remove the Deprecated stuff in DungeonHooks
ArrayList<WeightedRandomChestContent> contents = new ArrayList<WeightedRandomChestContent>();
public ChestGenHooks(String category)
{
this.category = category;
}
public ChestGenHooks(String category, WeightedRandomChestContent[] items, int min, int max)
{
this(category);
for (WeightedRandomChestContent item : items)
{
contents.add(item);
}
countMin = min;
countMax = max;
}
/**
* Adds a new entry into the possible items to generate.
*
* @param item The item to add.
*/
public void addItem(WeightedRandomChestContent item)
{
contents.add(item);
}
/**
* Removes all items that match the input item stack, Only metadata and item ID are checked.
* If the input item has a metadata of -1, all metadatas will match.
*
* @param item The item to check
*/
public void removeItem(ItemStack item)
{
Iterator<WeightedRandomChestContent> itr = contents.iterator();
while(itr.hasNext())
{
WeightedRandomChestContent cont = itr.next();
if (item.isItemEqual(cont.theItemId) || (item.getItemDamage() == OreDictionary.WILDCARD_VALUE && item.itemID == cont.theItemId.itemID))
{
itr.remove();
}
}
}
/**
* Gets an array of all random objects that are associated with this category.
*
* @return The random objects
*/
public WeightedRandomChestContent[] getItems(Random rnd)
{
ArrayList<WeightedRandomChestContent> ret = new ArrayList<WeightedRandomChestContent>();
for (WeightedRandomChestContent orig : contents)
{
Item item = orig.theItemId.getItem();
if (item != null)
{
WeightedRandomChestContent n = item.getChestGenBase(this, rnd, orig);
if (n != null)
{
ret.add(n);
}
}
}
return ret.toArray(new WeightedRandomChestContent[ret.size()]);
}
/**
* Gets a random number between countMin and countMax.
*
* @param rand A RNG
* @return A random number where countMin <= num <= countMax
*/
public int getCount(Random rand)
{
return countMin < countMax ? countMin + rand.nextInt(countMax - countMin) : countMin;
}
/**
* Returns a single ItemStack from the possible items in this registry,
* Useful if you just want a quick and dirty random Item.
*
* @param rand A Random Number gen
* @return A single ItemStack, or null if it could not get one.
*/
public ItemStack getOneItem(Random rand)
{
WeightedRandomChestContent[] items = getItems(rand);
WeightedRandomChestContent item = (WeightedRandomChestContent)WeightedRandom.getRandomItem(rand, items);
ItemStack[] stacks = ChestGenHooks.generateStacks(rand, item.theItemId, item.theMinimumChanceToGenerateItem, item.theMaximumChanceToGenerateItem);
return (stacks.length > 0 ? stacks[0] : null);
}
//Accessors
public int getMin(){ return countMin; }
public int getMax(){ return countMax; }
public void setMin(int value){ countMin = value; }
public void setMax(int value){ countMax = value; }
}
@@ -1,65 +1,27 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common;
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common.config;
import static net.minecraftforge.common.config.Configuration.COMMENT_SEPARATOR;
import static net.minecraftforge.common.config.Configuration.NEW_LINE;
import static net.minecraftforge.common.config.Configuration.allowedProperties;
import static net.minecraftforge.common.Configuration.NEW_LINE;
import static net.minecraftforge.common.Configuration.allowedProperties;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import net.minecraftforge.fml.client.config.GuiConfigEntries.IConfigEntry;
import com.google.common.base.Splitter;
public class ConfigCategory implements Map<String, Property>
{
private String name;
private String comment;
private String languagekey;
private ArrayList<ConfigCategory> children = new ArrayList<ConfigCategory>();
private Map<String, Property> properties = new TreeMap<String, Property>();
@SuppressWarnings("unused")
private int propNumber = 0;
public final ConfigCategory parent;
private boolean changed = false;
private boolean requiresWorldRestart = false;
private boolean showInGui = true;
private boolean requiresMcRestart = false;
private Class<? extends IConfigEntry> customEntryClass = null;
private List<String> propertyOrder = null;
public ConfigCategory(String name)
{
@@ -76,23 +38,17 @@ public class ConfigCategory implements Map<String, Property>
}
}
@Override
public boolean equals(Object obj)
{
if (obj instanceof ConfigCategory)
{
ConfigCategory cat = (ConfigCategory)obj;
return name.equals(cat.name) && children.equals(cat.children);
return name.equals(cat.name) && children.equals(cat.children);
}
return false;
}
public String getName()
{
return name;
}
public String getQualifiedName()
{
return getQualifiedName(name, parent);
@@ -118,133 +74,11 @@ public class ConfigCategory implements Map<String, Property>
return ImmutableMap.copyOf(properties);
}
public List<Property> getOrderedValues()
{
if (this.propertyOrder != null)
{
ArrayList<Property> set = new ArrayList<Property>();
for (String key : this.propertyOrder)
if (properties.containsKey(key))
set.add(properties.get(key));
return ImmutableList.copyOf(set);
}
else
return ImmutableList.copyOf(properties.values());
}
public ConfigCategory setConfigEntryClass(Class<? extends IConfigEntry> clazz)
{
this.customEntryClass = clazz;
return this;
}
public Class<? extends IConfigEntry> getConfigEntryClass()
{
return this.customEntryClass;
}
public ConfigCategory setLanguageKey(String languagekey)
{
this.languagekey = languagekey;
return this;
}
public String getLanguagekey()
{
if (this.languagekey != null)
return this.languagekey;
else
return getQualifiedName();
}
public void setComment(String comment)
{
this.comment = comment;
}
public String getComment()
{
return this.comment;
}
/**
* Sets the flag for whether or not this category can be edited while a world is running. Care should be taken to ensure
* that only properties that are truly dynamic can be changed from the in-game options menu. Only set this flag to
* true if all child properties/categories are unable to be modified while a world is running.
*/
public ConfigCategory setRequiresWorldRestart(boolean requiresWorldRestart)
{
this.requiresWorldRestart = requiresWorldRestart;
return this;
}
/**
* Returns whether or not this category is able to be edited while a world is running using the in-game Mod Options screen
* as well as the Mods list screen, or only from the Mods list screen.
*/
public boolean requiresWorldRestart()
{
return this.requiresWorldRestart;
}
/**
* Sets whether or not this ConfigCategory should be allowed to show on config GUIs.
* Defaults to true.
*/
public ConfigCategory setShowInGui(boolean showInGui)
{
this.showInGui = showInGui;
return this;
}
/**
* Gets whether or not this ConfigCategory should be allowed to show on config GUIs.
* Defaults to true unless set to false.
*/
public boolean showInGui()
{
return showInGui;
}
/**
* Sets whether or not this ConfigCategory requires Minecraft to be restarted when changed.
* Defaults to false. Only set this flag to true if ALL child properties/categories require
* Minecraft to be restarted when changed. Setting this flag will also prevent modification
* of the child properties/categories while a world is running.
*/
public ConfigCategory setRequiresMcRestart(boolean requiresMcRestart)
{
this.requiresMcRestart = this.requiresWorldRestart = requiresMcRestart;
return this;
}
/**
* Gets whether or not this ConfigCategory requires Minecraft to be restarted when changed.
* Defaults to false unless set to true.
*/
public boolean requiresMcRestart()
{
return this.requiresMcRestart;
}
public ConfigCategory setPropertyOrder(List<String> propertyOrder)
{
this.propertyOrder = propertyOrder;
for (String s : properties.keySet())
if (!propertyOrder.contains(s))
propertyOrder.add(s);
return this;
}
public List<String> getPropertyOrder()
{
if (this.propertyOrder != null)
return ImmutableList.copyOf(this.propertyOrder);
else
return ImmutableList.copyOf(properties.keySet());
}
public boolean containsKey(String key)
{
return properties.containsKey(key);
@@ -275,37 +109,36 @@ public class ConfigCategory implements Map<String, Property>
String pad1 = getIndent(indent + 1);
String pad2 = getIndent(indent + 2);
if (comment != null && !comment.isEmpty())
write(out, pad0, "####################");
write(out, pad0, "# ", name);
if (comment != null)
{
write(out, pad0, COMMENT_SEPARATOR);
write(out, pad0, "# ", name);
write(out, pad0, "#--------------------------------------------------------------------------------------------------------#");
write(out, pad0, "#===================");
Splitter splitter = Splitter.onPattern("\r?\n");
for (String line : splitter.split(comment))
{
write(out, pad0, "# ", line);
}
write(out, pad0, COMMENT_SEPARATOR, NEW_LINE);
}
String displayName = name;
write(out, pad0, "####################", NEW_LINE);
if (!allowedProperties.matchesAllOf(name))
{
displayName = '"' + name + '"';
name = '"' + name + '"';
}
write(out, pad0, displayName, " {");
write(out, pad0, name, " {");
Property[] props = getOrderedValues().toArray(new Property[] {});
Property[] props = properties.values().toArray(new Property[properties.size()]);
for (int x = 0; x < props.length; x++)
{
Property prop = props[x];
if (prop.getComment() != null && !prop.getComment().isEmpty())
if (prop.comment != null)
{
if (x != 0)
{
@@ -313,7 +146,7 @@ public class ConfigCategory implements Map<String, Property>
}
Splitter splitter = Splitter.onPattern("\r?\n");
for (String commentLine : splitter.split(prop.getComment()))
for (String commentLine : splitter.split(prop.comment))
{
write(out, pad1, "# ", commentLine);
}
@@ -329,7 +162,7 @@ public class ConfigCategory implements Map<String, Property>
if (prop.isList())
{
char type = prop.getType().getID();
write(out, pad1, String.valueOf(type), ":", propName, " <");
for (String line : prop.getStringList())
@@ -350,9 +183,6 @@ public class ConfigCategory implements Map<String, Property>
}
}
if (children.size() > 0)
out.newLine();
for (ConfigCategory child : children)
{
child.write(out, indent + 1);
@@ -400,8 +230,6 @@ public class ConfigCategory implements Map<String, Property>
@Override public Property put(String key, Property value)
{
changed = true;
if (this.propertyOrder != null && !this.propertyOrder.contains(key))
this.propertyOrder.add(key);
return properties.put(key, value);
}
@Override public Property remove(Object key)
@@ -412,10 +240,6 @@ public class ConfigCategory implements Map<String, Property>
@Override public void putAll(Map<? extends String, ? extends Property> m)
{
changed = true;
if (this.propertyOrder != null)
for (String key : m.keySet())
if (!this.propertyOrder.contains(key))
this.propertyOrder.add(key);
properties.putAll(m);
}
@Override public void clear()
@@ -433,7 +257,7 @@ public class ConfigCategory implements Map<String, Property>
}
public Set<ConfigCategory> getChildren(){ return ImmutableSet.copyOf(children); }
public void removeChild(ConfigCategory child)
{
if (children.contains(child))
@@ -0,0 +1,927 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
import static net.minecraftforge.common.Property.Type.BOOLEAN;
import static net.minecraftforge.common.Property.Type.DOUBLE;
import static net.minecraftforge.common.Property.Type.INTEGER;
import static net.minecraftforge.common.Property.Type.STRING;
import java.io.BufferedReader;
import java.io.BufferedWriter;
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.PushbackInputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableSet;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.relauncher.FMLInjectionData;
/**
* This class offers advanced configurations capabilities, allowing to provide
* various categories for configuration variables.
*/
public class Configuration
{
private static boolean[] configMarkers = new boolean[Item.itemsList.length];
private static final int ITEM_SHIFT = 256;
private static final int MAX_BLOCKS = 4096;
public static final String CATEGORY_GENERAL = "general";
public static final String CATEGORY_BLOCK = "block";
public static final String CATEGORY_ITEM = "item";
public static final String ALLOWED_CHARS = "._-";
public static final String DEFAULT_ENCODING = "UTF-8";
public static final String CATEGORY_SPLITTER = ".";
public static final String NEW_LINE;
private static final Pattern CONFIG_START = Pattern.compile("START: \"([^\\\"]+)\"");
private static final Pattern CONFIG_END = Pattern.compile("END: \"([^\\\"]+)\"");
public static final CharMatcher allowedProperties = CharMatcher.JAVA_LETTER_OR_DIGIT.or(CharMatcher.anyOf(ALLOWED_CHARS));
private static Configuration PARENT = null;
File file;
private Map<String, ConfigCategory> categories = new TreeMap<String, ConfigCategory>();
private Map<String, Configuration> children = new TreeMap<String, Configuration>();
private boolean caseSensitiveCustomCategories;
public String defaultEncoding = DEFAULT_ENCODING;
private String fileName = null;
public boolean isChild = false;
private boolean changed = false;
static
{
Arrays.fill(configMarkers, false);
NEW_LINE = System.getProperty("line.separator");
}
public Configuration(){}
/**
* Create a configuration file for the file given in parameter.
*/
public Configuration(File file)
{
this.file = file;
String basePath = ((File)(FMLInjectionData.data()[6])).getAbsolutePath().replace(File.separatorChar, '/').replace("/.", "");
String path = file.getAbsolutePath().replace(File.separatorChar, '/').replace("/./", "/").replace(basePath, "");
if (PARENT != null)
{
PARENT.setChild(path, this);
isChild = true;
}
else
{
fileName = path;
load();
}
}
public Configuration(File file, boolean caseSensitiveCustomCategories)
{
this(file);
this.caseSensitiveCustomCategories = caseSensitiveCustomCategories;
}
/**
* Gets or create a block id property. If the block id property key is
* already in the configuration, then it will be used. Otherwise,
* defaultId will be used, except if already taken, in which case this
* will try to determine a free default id.
*/
public Property getBlock(String key, int defaultID) { return getBlock(CATEGORY_BLOCK, key, defaultID, null); }
public Property getBlock(String key, int defaultID, String comment) { return getBlock(CATEGORY_BLOCK, key, defaultID, comment); }
public Property getBlock(String category, String key, int defaultID) { return getBlockInternal(category, key, defaultID, null, 256, Block.blocksList.length); }
public Property getBlock(String category, String key, int defaultID, String comment) { return getBlockInternal(category, key, defaultID, comment, 256, Block.blocksList.length); }
/**
* Special version of getBlock to be used when you want to garentee the ID you get is below 256
* This should ONLY be used by mods who do low level terrain generation, or ones that add new
* biomes.
* EXA: ExtraBiomesXL
*
* Specifically, if your block is used BEFORE the Chunk is created, and placed in the terrain byte array directly.
* If you add a new biome and you set the top/filler block, they need to be <256, nothing else.
*
* If you're adding a new ore, DON'T call this function.
*
* Normal mods such as '50 new ores' do not need to be below 256 so should use the normal getBlock
*/
public Property getTerrainBlock(String category, String key, int defaultID, String comment)
{
return getBlockInternal(category, key, defaultID, comment, 0, 256);
}
private Property getBlockInternal(String category, String key, int defaultID, String comment, int lower, int upper)
{
Property prop = get(category, key, -1, comment);
if (prop.getInt() != -1)
{
configMarkers[prop.getInt()] = true;
return prop;
}
else
{
if (defaultID < lower)
{
FMLLog.warning(
"Mod attempted to get a block ID with a default in the Terrain Generation section, " +
"mod authors should make sure there defaults are above 256 unless explicitly needed " +
"for terrain generation. Most ores do not need to be below 256.");
FMLLog.warning("Config \"%s\" Category: \"%s\" Key: \"%s\" Default: %d", fileName, category, key, defaultID);
defaultID = upper - 1;
}
if (Block.blocksList[defaultID] == null && !configMarkers[defaultID])
{
prop.set(defaultID);
configMarkers[defaultID] = true;
return prop;
}
else
{
for (int j = upper - 1; j > 0; j--)
{
if (Block.blocksList[j] == null && !configMarkers[j])
{
prop.set(j);
configMarkers[j] = true;
return prop;
}
}
throw new RuntimeException("No more block ids available for " + key);
}
}
}
public Property getItem(String key, int defaultID) { return getItem(CATEGORY_ITEM, key, defaultID, null); }
public Property getItem(String key, int defaultID, String comment) { return getItem(CATEGORY_ITEM, key, defaultID, comment); }
public Property getItem(String category, String key, int defaultID) { return getItem(category, key, defaultID, null); }
public Property getItem(String category, String key, int defaultID, String comment)
{
Property prop = get(category, key, -1, comment);
int defaultShift = defaultID + ITEM_SHIFT;
if (prop.getInt() != -1)
{
configMarkers[prop.getInt() + ITEM_SHIFT] = true;
return prop;
}
else
{
if (defaultID < MAX_BLOCKS - ITEM_SHIFT)
{
FMLLog.warning(
"Mod attempted to get a item ID with a default value in the block ID section, " +
"mod authors should make sure there defaults are above %d unless explicitly needed " +
"so that all block ids are free to store blocks.", MAX_BLOCKS - ITEM_SHIFT);
FMLLog.warning("Config \"%s\" Category: \"%s\" Key: \"%s\" Default: %d", fileName, category, key, defaultID);
}
if (Item.itemsList[defaultShift] == null && !configMarkers[defaultShift] && defaultShift >= Block.blocksList.length)
{
prop.set(defaultID);
configMarkers[defaultShift] = true;
return prop;
}
else
{
for (int x = Item.itemsList.length - 1; x >= ITEM_SHIFT; x--)
{
if (Item.itemsList[x] == null && !configMarkers[x])
{
prop.set(x - ITEM_SHIFT);
configMarkers[x] = true;
return prop;
}
}
throw new RuntimeException("No more item ids available for " + key);
}
}
}
public Property get(String category, String key, int defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, int defaultValue, String comment)
{
Property prop = get(category, key, Integer.toString(defaultValue), comment, INTEGER);
if (!prop.isIntValue())
{
prop.set(defaultValue);
}
return prop;
}
public Property get(String category, String key, boolean defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, boolean defaultValue, String comment)
{
Property prop = get(category, key, Boolean.toString(defaultValue), comment, BOOLEAN);
if (!prop.isBooleanValue())
{
prop.set(defaultValue);
}
return prop;
}
public Property get(String category, String key, double defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, double defaultValue, String comment)
{
Property prop = get(category, key, Double.toString(defaultValue), comment, DOUBLE);
if (!prop.isDoubleValue())
{
prop.set(defaultValue);
}
return prop;
}
public Property get(String category, String key, String defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, String defaultValue, String comment)
{
return get(category, key, defaultValue, comment, STRING);
}
public Property get(String category, String key, String[] defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, String[] defaultValue, String comment)
{
return get(category, key, defaultValue, comment, STRING);
}
public Property get(String category, String key, int[] defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, int[] defaultValue, String comment)
{
String[] values = new String[defaultValue.length];
for (int i = 0; i < defaultValue.length; i++)
{
values[i] = Integer.toString(defaultValue[i]);
}
Property prop = get(category, key, values, comment, INTEGER);
if (!prop.isIntList())
{
prop.set(values);
}
return prop;
}
public Property get(String category, String key, double[] defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, double[] defaultValue, String comment)
{
String[] values = new String[defaultValue.length];
for (int i = 0; i < defaultValue.length; i++)
{
values[i] = Double.toString(defaultValue[i]);
}
Property prop = get(category, key, values, comment, DOUBLE);
if (!prop.isDoubleList())
{
prop.set(values);
}
return prop;
}
public Property get(String category, String key, boolean[] defaultValue)
{
return get(category, key, defaultValue, null);
}
public Property get(String category, String key, boolean[] defaultValue, String comment)
{
String[] values = new String[defaultValue.length];
for (int i = 0; i < defaultValue.length; i++)
{
values[i] = Boolean.toString(defaultValue[i]);
}
Property prop = get(category, key, values, comment, BOOLEAN);
if (!prop.isBooleanList())
{
prop.set(values);
}
return prop;
}
public Property get(String category, String key, String defaultValue, String comment, Property.Type type)
{
if (!caseSensitiveCustomCategories)
{
category = category.toLowerCase(Locale.ENGLISH);
}
ConfigCategory cat = getCategory(category);
if (cat.containsKey(key))
{
Property prop = cat.get(key);
if (prop.getType() == null)
{
prop = new Property(prop.getName(), prop.getString(), type);
cat.put(key, prop);
}
prop.comment = comment;
return prop;
}
else if (defaultValue != null)
{
Property prop = new Property(key, defaultValue, type);
prop.set(defaultValue); //Set and mark as dirty to signify it should save
cat.put(key, prop);
prop.comment = comment;
return prop;
}
else
{
return null;
}
}
public Property get(String category, String key, String[] defaultValue, String comment, Property.Type type)
{
if (!caseSensitiveCustomCategories)
{
category = category.toLowerCase(Locale.ENGLISH);
}
ConfigCategory cat = getCategory(category);
if (cat.containsKey(key))
{
Property prop = cat.get(key);
if (prop.getType() == null)
{
prop = new Property(prop.getName(), prop.getString(), type);
cat.put(key, prop);
}
prop.comment = comment;
return prop;
}
else if (defaultValue != null)
{
Property prop = new Property(key, defaultValue, type);
prop.comment = comment;
cat.put(key, prop);
return prop;
}
else
{
return null;
}
}
public boolean hasCategory(String category)
{
return categories.get(category) != null;
}
public boolean hasKey(String category, String key)
{
ConfigCategory cat = categories.get(category);
return cat != null && cat.containsKey(key);
}
public void load()
{
if (PARENT != null && PARENT != this)
{
return;
}
BufferedReader buffer = null;
UnicodeInputStreamReader input = null;
try
{
if (file.getParentFile() != null)
{
file.getParentFile().mkdirs();
}
if (!file.exists() && !file.createNewFile())
{
return;
}
if (file.canRead())
{
input = new UnicodeInputStreamReader(new FileInputStream(file), defaultEncoding);
defaultEncoding = input.getEncoding();
buffer = new BufferedReader(input);
String line;
ConfigCategory currentCat = null;
Property.Type type = null;
ArrayList<String> tmpList = null;
int lineNum = 0;
String name = null;
while (true)
{
lineNum++;
line = buffer.readLine();
if (line == null)
{
break;
}
Matcher start = CONFIG_START.matcher(line);
Matcher end = CONFIG_END.matcher(line);
if (start.matches())
{
fileName = start.group(1);
categories = new TreeMap<String, ConfigCategory>();
continue;
}
else if (end.matches())
{
fileName = end.group(1);
Configuration child = new Configuration();
child.categories = categories;
this.children.put(fileName, child);
continue;
}
int nameStart = -1, nameEnd = -1;
boolean skip = false;
boolean quoted = false;
for (int i = 0; i < line.length() && !skip; ++i)
{
if (Character.isLetterOrDigit(line.charAt(i)) || ALLOWED_CHARS.indexOf(line.charAt(i)) != -1 || (quoted && line.charAt(i) != '"'))
{
if (nameStart == -1)
{
nameStart = i;
}
nameEnd = i;
}
else if (Character.isWhitespace(line.charAt(i)))
{
// ignore space charaters
}
else
{
switch (line.charAt(i))
{
case '#':
skip = true;
continue;
case '"':
if (quoted)
{
quoted = false;
}
if (!quoted && nameStart == -1)
{
quoted = true;
}
break;
case '{':
name = line.substring(nameStart, nameEnd + 1);
String qualifiedName = ConfigCategory.getQualifiedName(name, currentCat);
ConfigCategory cat = categories.get(qualifiedName);
if (cat == null)
{
currentCat = new ConfigCategory(name, currentCat);
categories.put(qualifiedName, currentCat);
}
else
{
currentCat = cat;
}
name = null;
break;
case '}':
if (currentCat == null)
{
throw new RuntimeException(String.format("Config file corrupt, attepted to close to many categories '%s:%d'", fileName, lineNum));
}
currentCat = currentCat.parent;
break;
case '=':
name = line.substring(nameStart, nameEnd + 1);
if (currentCat == null)
{
throw new RuntimeException(String.format("'%s' has no scope in '%s:%d'", name, fileName, lineNum));
}
Property prop = new Property(name, line.substring(i + 1), type, true);
i = line.length();
currentCat.put(name, prop);
break;
case ':':
type = Property.Type.tryParse(line.substring(nameStart, nameEnd + 1).charAt(0));
nameStart = nameEnd = -1;
break;
case '<':
if (tmpList != null)
{
throw new RuntimeException(String.format("Malformed list property \"%s:%d\"", fileName, lineNum));
}
name = line.substring(nameStart, nameEnd + 1);
if (currentCat == null)
{
throw new RuntimeException(String.format("'%s' has no scope in '%s:%d'", name, fileName, lineNum));
}
tmpList = new ArrayList<String>();
skip = true;
break;
case '>':
if (tmpList == null)
{
throw new RuntimeException(String.format("Malformed list property \"%s:%d\"", fileName, lineNum));
}
currentCat.put(name, new Property(name, tmpList.toArray(new String[tmpList.size()]), type));
name = null;
tmpList = null;
type = null;
break;
default:
throw new RuntimeException(String.format("Unknown character '%s' in '%s:%d'", line.charAt(i), fileName, lineNum));
}
}
}
if (quoted)
{
throw new RuntimeException(String.format("Unmatched quote in '%s:%d'", fileName, lineNum));
}
else if (tmpList != null && !skip)
{
tmpList.add(line.trim());
}
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (buffer != null)
{
try
{
buffer.close();
} catch (IOException e){}
}
if (input != null)
{
try
{
input.close();
} catch (IOException e){}
}
}
resetChangedState();
}
public void save()
{
if (PARENT != null && PARENT != this)
{
PARENT.save();
return;
}
try
{
if (file.getParentFile() != null)
{
file.getParentFile().mkdirs();
}
if (!file.exists() && !file.createNewFile())
{
return;
}
if (file.canWrite())
{
FileOutputStream fos = new FileOutputStream(file);
BufferedWriter buffer = new BufferedWriter(new OutputStreamWriter(fos, defaultEncoding));
buffer.write("# Configuration file" + NEW_LINE + NEW_LINE);
if (children.isEmpty())
{
save(buffer);
}
else
{
for (Map.Entry<String, Configuration> entry : children.entrySet())
{
buffer.write("START: \"" + entry.getKey() + "\"" + NEW_LINE);
entry.getValue().save(buffer);
buffer.write("END: \"" + entry.getKey() + "\"" + NEW_LINE + NEW_LINE);
}
}
buffer.close();
fos.close();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
private void save(BufferedWriter out) throws IOException
{
for (ConfigCategory cat : categories.values())
{
if (!cat.isChild())
{
cat.write(out, 0);
out.newLine();
}
}
}
public ConfigCategory getCategory(String category)
{
ConfigCategory ret = categories.get(category);
if (ret == null)
{
if (category.contains(CATEGORY_SPLITTER))
{
String[] hierarchy = category.split("\\"+CATEGORY_SPLITTER);
ConfigCategory parent = categories.get(hierarchy[0]);
if (parent == null)
{
parent = new ConfigCategory(hierarchy[0]);
categories.put(parent.getQualifiedName(), parent);
changed = true;
}
for (int i = 1; i < hierarchy.length; i++)
{
String name = ConfigCategory.getQualifiedName(hierarchy[i], parent);
ConfigCategory child = categories.get(name);
if (child == null)
{
child = new ConfigCategory(hierarchy[i], parent);
categories.put(name, child);
changed = true;
}
ret = child;
parent = child;
}
}
else
{
ret = new ConfigCategory(category);
categories.put(category, ret);
changed = true;
}
}
return ret;
}
public void removeCategory(ConfigCategory category)
{
for (ConfigCategory child : category.getChildren())
{
removeCategory(child);
}
if (categories.containsKey(category.getQualifiedName()))
{
categories.remove(category.getQualifiedName());
if (category.parent != null)
{
category.parent.removeChild(category);
}
changed = true;
}
}
public void addCustomCategoryComment(String category, String comment)
{
if (!caseSensitiveCustomCategories)
category = category.toLowerCase(Locale.ENGLISH);
getCategory(category).setComment(comment);
}
private void setChild(String name, Configuration child)
{
if (!children.containsKey(name))
{
children.put(name, child);
changed = true;
}
else
{
Configuration old = children.get(name);
child.categories = old.categories;
child.fileName = old.fileName;
old.changed = true;
}
}
public static void enableGlobalConfig()
{
PARENT = new Configuration(new File(Loader.instance().getConfigDir(), "global.cfg"));
PARENT.load();
}
public static class UnicodeInputStreamReader extends Reader
{
private final InputStreamReader input;
private final String defaultEnc;
public UnicodeInputStreamReader(InputStream source, String encoding) throws IOException
{
defaultEnc = encoding;
String enc = encoding;
byte[] data = new byte[4];
PushbackInputStream pbStream = new PushbackInputStream(source, data.length);
int read = pbStream.read(data, 0, data.length);
int size = 0;
int bom16 = (data[0] & 0xFF) << 8 | (data[1] & 0xFF);
int bom24 = bom16 << 8 | (data[2] & 0xFF);
int bom32 = bom24 << 8 | (data[3] & 0xFF);
if (bom24 == 0xEFBBBF)
{
enc = "UTF-8";
size = 3;
}
else if (bom16 == 0xFEFF)
{
enc = "UTF-16BE";
size = 2;
}
else if (bom16 == 0xFFFE)
{
enc = "UTF-16LE";
size = 2;
}
else if (bom32 == 0x0000FEFF)
{
enc = "UTF-32BE";
size = 4;
}
else if (bom32 == 0xFFFE0000) //This will never happen as it'll be caught by UTF-16LE,
{ //but if anyone ever runs across a 32LE file, i'd like to disect it.
enc = "UTF-32LE";
size = 4;
}
if (size < read)
{
pbStream.unread(data, size, read - size);
}
this.input = new InputStreamReader(pbStream, enc);
}
public String getEncoding()
{
return input.getEncoding();
}
@Override
public int read(char[] cbuf, int off, int len) throws IOException
{
return input.read(cbuf, off, len);
}
@Override
public void close() throws IOException
{
input.close();
}
}
public boolean hasChanged()
{
if (changed) return true;
for (ConfigCategory cat : categories.values())
{
if (cat.hasChanged()) return true;
}
for (Configuration child : children.values())
{
if (child.hasChanged()) return true;
}
return false;
}
private void resetChangedState()
{
changed = false;
for (ConfigCategory cat : categories.values())
{
cat.resetChangedState();
}
for (Configuration child : children.values())
{
child.resetChangedState();
}
}
public Set<String> getCategoryNames()
{
return ImmutableSet.copyOf(categories.keySet());
}
}
@@ -1,77 +1,96 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import org.apache.logging.log4j.Level;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.DimensionType;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.MinecraftException;
import net.minecraft.world.World;
import net.minecraft.world.ServerWorldEventHandler;
import net.minecraft.world.WorldManager;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.WorldProviderEnd;
import net.minecraft.world.WorldProviderHell;
import net.minecraft.world.WorldProviderSurface;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldServerMulti;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.SaveHandler;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLLog;
public class DimensionManager
{
private static Hashtable<Integer, Class<? extends WorldProvider>> providers = new Hashtable<Integer, Class<? extends WorldProvider>>();
private static Hashtable<Integer, Boolean> spawnSettings = new Hashtable<Integer, Boolean>();
private static Hashtable<Integer, WorldServer> worlds = new Hashtable<Integer, WorldServer>();
private static boolean hasInit = false;
private static Hashtable<Integer, DimensionType> dimensions = new Hashtable<Integer, DimensionType>();
private static Hashtable<Integer, Integer> dimensions = new Hashtable<Integer, Integer>();
private static ArrayList<Integer> unloadQueue = new ArrayList<Integer>();
private static BitSet dimensionMap = new BitSet(Long.SIZE << 4);
private static ConcurrentMap<World, World> weakWorldMap = new MapMaker().weakKeys().weakValues().<World,World>makeMap();
private static Multiset<Integer> leakedWorlds = HashMultiset.create();
/**
* Returns a list of dimensions associated with this DimensionType.
*/
public static int[] getDimensions(DimensionType type)
public static boolean registerProviderType(int id, Class<? extends WorldProvider> provider, boolean keepLoaded)
{
if (providers.containsKey(id))
{
return false;
}
providers.put(id, provider);
spawnSettings.put(id, keepLoaded);
return true;
}
/**
* Unregisters a Provider type, and returns a array of all dimensions that are
* registered to this provider type.
* If the return size is greater then 0, it is required that the caller either
* change those dimensions's registered type, or replace this type before the
* world is attempted to load, else the loader will throw an exception.
*
* @param id The provider type ID to unreigster
* @return An array containing all dimension IDs still registered to this provider type.
*/
public static int[] unregisterProviderType(int id)
{
if (!providers.containsKey(id))
{
return new int[0];
}
providers.remove(id);
spawnSettings.remove(id);
int[] ret = new int[dimensions.size()];
int x = 0;
for (Map.Entry<Integer, DimensionType> ent : dimensions.entrySet())
for (Map.Entry<Integer, Integer> ent : dimensions.entrySet())
{
if (ent.getValue() == type)
if (ent.getValue() == id)
{
ret[x++] = ent.getKey();
}
@@ -89,19 +108,25 @@ public class DimensionManager
hasInit = true;
registerDimension( 0, DimensionType.OVERWORLD);
registerDimension(-1, DimensionType.NETHER);
registerDimension( 1, DimensionType.THE_END);
registerProviderType( 0, WorldProviderSurface.class, true);
registerProviderType(-1, WorldProviderHell.class, true);
registerProviderType( 1, WorldProviderEnd.class, false);
registerDimension( 0, 0);
registerDimension(-1, -1);
registerDimension( 1, 1);
}
public static void registerDimension(int id, DimensionType type)
public static void registerDimension(int id, int providerType)
{
DimensionType.getById(type.getId()); //Check if type is invalid {will throw an error} No clue how it would be invalid tho...
if (!providers.containsKey(providerType))
{
throw new IllegalArgumentException(String.format("Failed to register dimension for id %d, provider type %d does not exist", id, providerType));
}
if (dimensions.containsKey(id))
{
throw new IllegalArgumentException(String.format("Failed to register dimension for id %d, One is already registered", id));
}
dimensions.put(id, type);
dimensions.put(id, providerType);
if (id >= 0)
{
dimensionMap.set(id);
@@ -125,7 +150,7 @@ public class DimensionManager
return dimensions.containsKey(dim);
}
public static DimensionType getProviderType(int dim)
public static int getProviderType(int dim)
{
if (!dimensions.containsKey(dim))
{
@@ -155,7 +180,7 @@ public class DimensionManager
int leakCount = leakedWorlds.count(System.identityHashCode(w));
if (leakCount == 5)
{
FMLLog.fine("The world %x (%s) may have leaked: first encounter (5 occurrences).\n", System.identityHashCode(w), w.getWorldInfo().getWorldName());
FMLLog.fine("The world %x (%s) may have leaked: first encounter (5 occurences).\n", System.identityHashCode(w), w.getWorldInfo().getWorldName());
}
else if (leakCount % 5 == 0)
{
@@ -170,19 +195,19 @@ public class DimensionManager
return worlds.keySet().toArray(new Integer[worlds.size()]); //Only loaded dims, since usually used to cycle through loaded worlds
}
public static void setWorld(int id, WorldServer world, MinecraftServer server)
public static void setWorld(int id, WorldServer world)
{
if (world != null)
{
worlds.put(id, world);
weakWorldMap.put(world, world);
server.worldTickTimes.put(id, new long[100]);
MinecraftServer.getServer().worldTickTimes.put(id, new long[100]);
FMLLog.info("Loading dimension %d (%s) (%s)", id, world.getWorldInfo().getWorldName(), world.getMinecraftServer());
}
else
{
worlds.remove(id);
server.worldTickTimes.remove(id);
MinecraftServer.getServer().worldTickTimes.remove(id);
FMLLog.info("Unloading dimension %d", id);
}
@@ -204,11 +229,10 @@ public class DimensionManager
tmp.add(entry.getValue());
}
server.worldServers = tmp.toArray(new WorldServer[tmp.size()]);
MinecraftServer.getServer().worldServers = tmp.toArray(new WorldServer[tmp.size()]);
}
public static void initDimension(int dim)
{
public static void initDimension(int dim) {
WorldServer overworld = getWorld(0);
if (overworld == null)
{
@@ -225,10 +249,10 @@ public class DimensionManager
}
MinecraftServer mcServer = overworld.getMinecraftServer();
ISaveHandler savehandler = overworld.getSaveHandler();
//WorldSettings worldSettings = new WorldSettings(overworld.getWorldInfo());
WorldSettings worldSettings = new WorldSettings(overworld.getWorldInfo());
WorldServer world = (dim == 0 ? overworld : (WorldServer)(new WorldServerMulti(mcServer, savehandler, dim, overworld, mcServer.theProfiler).init()));
world.addEventListener(new ServerWorldEventHandler(mcServer, world));
WorldServer world = (dim == 0 ? overworld : new WorldServerMulti(mcServer, savehandler, overworld.getWorldInfo().getWorldName(), dim, worldSettings, overworld, mcServer.theProfiler, overworld.getWorldLogAgent()));
world.addWorldAccess(new WorldManager(mcServer, world));
MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world));
if (!mcServer.isSinglePlayer())
{
@@ -248,6 +272,12 @@ public class DimensionManager
return worlds.values().toArray(new WorldServer[worlds.size()]);
}
public static boolean shouldLoadSpawn(int dim)
{
int id = getProviderType(dim);
return spawnSettings.containsKey(id) && spawnSettings.get(id);
}
static
{
init();
@@ -267,9 +297,9 @@ public class DimensionManager
{
if (dimensions.containsKey(dim))
{
WorldProvider ret = getProviderType(dim).createDimension();
ret.setDimension(dim);
return ret;
WorldProvider provider = providers.get(getProviderType(dim)).newInstance();
provider.setDimension(dim);
return provider;
}
else
{
@@ -278,8 +308,8 @@ public class DimensionManager
}
catch (Exception e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.ERROR, String.format("An error occurred trying to create an instance of WorldProvider %d (%s)",
dim, getProviderType(dim)),e);
FMLCommonHandler.instance().getFMLLogger().log(Level.SEVERE,String.format("An error occured trying to create an instance of WorldProvider %d (%s)",
dim, providers.get(getProviderType(dim)).getSimpleName()),e);
throw new RuntimeException(e);
}
}
@@ -312,7 +342,7 @@ public class DimensionManager
{
MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(w));
w.flush();
setWorld(id, null, w.getMinecraftServer());
setWorld(id, null);
}
}
}
@@ -359,9 +389,9 @@ public class DimensionManager
public static void loadDimensionDataMap(NBTTagCompound compoundTag)
{
dimensionMap.clear();
if (compoundTag == null)
{
dimensionMap.clear();
for (Integer id : dimensions.keySet())
{
if (id >= 0)
@@ -391,14 +421,14 @@ public class DimensionManager
{
if (DimensionManager.getWorld(0) != null)
{
return DimensionManager.getWorld(0).getSaveHandler().getWorldDirectory();
}/*
return ((SaveHandler)DimensionManager.getWorld(0).getSaveHandler()).getWorldDirectory();
}
else if (MinecraftServer.getServer() != null)
{
MinecraftServer srv = MinecraftServer.getServer();
SaveHandler saveHandler = (SaveHandler) srv.getActiveAnvilConverter().getSaveLoader(srv.getFolderName(), false);
return saveHandler.getWorldDirectory();
}*/
}
else
{
return null;
@@ -1,28 +1,18 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common;
import java.util.ArrayList;
import java.util.Random;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedRandomChestContent;
import net.minecraft.util.WeightedRandomItem;
import static net.minecraftforge.common.ChestGenHooks.DUNGEON_CHEST;
public class DungeonHooks
{
@@ -87,7 +77,7 @@ public class DungeonHooks
*/
public static String getRandomDungeonMob(Random rand)
{
DungeonMob mob = WeightedRandom.getRandomItem(rand, dungeonMobs);
DungeonMob mob = (DungeonMob)WeightedRandom.getRandomItem(rand, dungeonMobs);
if (mob == null)
{
return "";
@@ -96,7 +86,7 @@ public class DungeonHooks
}
public static class DungeonMob extends WeightedRandom.Item
public static class DungeonMob extends WeightedRandomItem
{
public String type;
public DungeonMob(int weight, String type)
@@ -1,47 +1,25 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.util;
package net.minecraftforge.common;
import java.lang.reflect.*;
import java.util.*;
import com.google.common.collect.Lists;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLLog;
import net.minecraftforge.fml.common.EnhancedRuntimeException;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraft.block.BlockPressurePlate.Sensitivity;
import net.minecraft.block.EnumMobType;
import net.minecraft.block.material.Material;
import net.minecraft.enchantment.EnumEnchantmentType;
import net.minecraft.entity.EnumCreatureAttribute;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.entity.item.EntityPainting.EnumArt;
import net.minecraft.entity.player.EntityPlayer.SleepResult;
import net.minecraft.entity.EnumEntitySize;
import net.minecraft.entity.player.EnumStatus;
import net.minecraft.item.EnumAction;
import net.minecraft.item.EnumRarity;
import net.minecraft.item.Item.ToolMaterial;
import net.minecraft.item.ItemArmor.ArmorMaterial;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.item.EnumArmorMaterial;
import net.minecraft.item.EnumToolMaterial;
import net.minecraft.util.EnumArt;
import net.minecraft.util.EnumMovingObjectType;
import net.minecraft.world.EnumSkyBlock;
import net.minecraft.world.gen.structure.StructureStrongholdPieces.Stronghold.Door;
import net.minecraft.world.gen.structure.EnumDoor;
import net.minecraftforge.classloading.FMLForgePlugin;
public class EnumHelper
@@ -54,30 +32,30 @@ public class EnumHelper
private static boolean isSetup = false;
//Some enums are decompiled with extra arguments, so lets check for that
private static Class<?>[][] commonTypes =
private static Class[][] commonTypes =
{
{EnumAction.class},
{ArmorMaterial.class, String.class, int.class, int[].class, int.class, SoundEvent.class, float.class},
{EnumArmorMaterial.class, int.class, int[].class, int.class},
{EnumArt.class, String.class, int.class, int.class, int.class, int.class},
{EnumCreatureAttribute.class},
{EnumCreatureType.class, Class.class, int.class, Material.class, boolean.class, boolean.class},
{Door.class},
{EnumCreatureType.class, Class.class, int.class, Material.class, boolean.class},
{EnumDoor.class},
{EnumEnchantmentType.class},
{Sensitivity.class},
{RayTraceResult.Type.class},
{EnumEntitySize.class},
{EnumMobType.class},
{EnumMovingObjectType.class},
{EnumSkyBlock.class, int.class},
{SleepResult.class},
{ToolMaterial.class, int.class, int.class, float.class, float.class, int.class},
{EnumRarity.class, TextFormatting.class, String.class}
};
{EnumStatus.class},
{EnumToolMaterial.class, int.class, int.class, float.class, float.class, int.class}
};
public static EnumAction addAction(String name)
{
return addEnum(EnumAction.class, name);
}
public static ArmorMaterial addArmorMaterial(String name, String textureName, int durability, int[] reductionAmounts, int enchantability, SoundEvent soundOnEquip, float toughness)
public static EnumArmorMaterial addArmorMaterial(String name, int durability, int[] reductionAmounts, int enchantability)
{
return addEnum(ArmorMaterial.class, name, textureName, durability, reductionAmounts, enchantability, soundOnEquip, toughness);
return addEnum(EnumArmorMaterial.class, name, durability, reductionAmounts, enchantability);
}
public static EnumArt addArt(String name, String tile, int sizeX, int sizeY, int offsetX, int offsetY)
{
@@ -87,41 +65,46 @@ public class EnumHelper
{
return addEnum(EnumCreatureAttribute.class, name);
}
public static EnumCreatureType addCreatureType(String name, Class<?> typeClass, int maxNumber, Material material, boolean peaceful, boolean animal)
public static EnumCreatureType addCreatureType(String name, Class typeClass, int maxNumber, Material material, boolean peaceful)
{
return addEnum(EnumCreatureType.class, name, typeClass, maxNumber, material, peaceful, animal);
return addEnum(EnumCreatureType.class, name, typeClass, maxNumber, material, peaceful);
}
public static Door addDoor(String name)
public static EnumDoor addDoor(String name)
{
return addEnum(Door.class, name);
return addEnum(EnumDoor.class, name);
}
public static EnumEnchantmentType addEnchantmentType(String name)
{
return addEnum(EnumEnchantmentType.class, name);
}
public static Sensitivity addSensitivity(String name)
public static EnumEntitySize addEntitySize(String name)
{
return addEnum(Sensitivity.class, name);
return addEnum(EnumEntitySize.class, name);
}
public static RayTraceResult.Type addMovingObjectType(String name)
public static EnumMobType addMobType(String name)
{
return addEnum(RayTraceResult.Type.class, name);
return addEnum(EnumMobType.class, name);
}
public static EnumMovingObjectType addMovingObjectType(String name)
{
if (!isSetup)
{
setup();
}
return addEnum(EnumMovingObjectType.class, name);
}
public static EnumSkyBlock addSkyBlock(String name, int lightValue)
{
return addEnum(EnumSkyBlock.class, name, lightValue);
}
public static SleepResult addStatus(String name)
public static EnumStatus addStatus(String name)
{
return addEnum(SleepResult.class, name);
return addEnum(EnumStatus.class, name);
}
public static ToolMaterial addToolMaterial(String name, int harvestLevel, int maxUses, float efficiency, float damage, int enchantability)
public static EnumToolMaterial addToolMaterial(String name, int harvestLevel, int maxUses, float efficiency, float damage, int enchantability)
{
return addEnum(ToolMaterial.class, name, harvestLevel, maxUses, efficiency, damage, enchantability);
}
public static EnumRarity addRarity(String name, TextFormatting color, String displayName)
{
return addEnum(EnumRarity.class, name, color, displayName);
return addEnum(EnumToolMaterial.class, name, harvestLevel, maxUses, efficiency, damage, enchantability);
}
private static void setup()
@@ -164,11 +147,11 @@ public class EnumHelper
private static < T extends Enum<? >> T makeEnum(Class<T> enumClass, String value, int ordinal, Class<?>[] additionalTypes, Object[] additionalValues) throws Exception
{
Object[] params = new Object[additionalValues.length + 2];
params[0] = value;
params[1] = ordinal;
System.arraycopy(additionalValues, 0, params, 2, additionalValues.length);
return enumClass.cast(newInstance.invoke(getConstructorAccessor(enumClass, additionalTypes), new Object[] {params}));
Object[] parms = new Object[additionalValues.length + 2];
parms[0] = value;
parms[1] = Integer.valueOf(ordinal);
System.arraycopy(additionalValues, 0, parms, 2, additionalValues.length);
return enumClass.cast(newInstance.invoke(getConstructorAccessor(enumClass, additionalTypes), new Object[] {parms}));
}
public static void setFailsafeFieldValue(Field field, Object target, Object value) throws Exception
@@ -200,15 +183,14 @@ public class EnumHelper
blankField(enumClass, "enumConstants");
}
private static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Object... paramValues)
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Object... paramValues)
{
setup();
return addEnum(commonTypes, enumType, enumName, paramValues);
}
protected static <T extends Enum<? >> T addEnum(Class<?>[][] map, Class<T> enumType, String enumName, Object... paramValues)
public static <T extends Enum<? >> T addEnum(Class[][] map, Class<T> enumType, String enumName, Object... paramValues)
{
for (Class<?>[] lookup : map)
for (Class[] lookup : map)
{
if (lookup[0] == enumType)
{
@@ -223,19 +205,8 @@ public class EnumHelper
return null;
}
//Tests an enum is compatible with these args, throws an error if not.
public static void testEnum(Class<? extends Enum<?>> enumType, Class<?>[] paramTypes)
{
addEnum(true, enumType, null, paramTypes, (Object[])null);
}
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Class<?>[] paramTypes, Object... paramValues)
{
return addEnum(false, enumType, enumName, paramTypes, paramValues);
}
@SuppressWarnings({ "unchecked", "serial" })
private static <T extends Enum<? >> T addEnum(boolean test, final Class<T> enumType, String enumName, final Class<?>[] paramTypes, Object[] paramValues)
@SuppressWarnings("unchecked")
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Class<?>[] paramTypes, Object[] paramValues)
{
if (!isSetup)
{
@@ -244,7 +215,7 @@ public class EnumHelper
Field valuesField = null;
Field[] fields = enumType.getDeclaredFields();
for (Field field : fields)
{
String name = field.getName();
@@ -259,7 +230,7 @@ public class EnumHelper
if (valuesField == null)
{
String valueType = String.format("[L%s;", enumType.getName().replace('.', '/'));
for (Field field : fields)
{
if ((field.getModifiers() & flags) == flags &&
@@ -273,74 +244,14 @@ public class EnumHelper
if (valuesField == null)
{
final List<String> lines = Lists.newArrayList();
lines.add(String.format("Could not find $VALUES field for enum: %s", enumType.getName()));
lines.add(String.format("Runtime Deobf: %s", FMLForgePlugin.RUNTIME_DEOBF));
lines.add(String.format("Flags: %s", String.format("%16s", Integer.toBinaryString(flags)).replace(' ', '0')));
lines.add( "Fields:");
FMLLog.severe("Could not find $VALUES field for enum: %s", enumType.getName());
FMLLog.severe("Runtime Deobf: %s", FMLForgePlugin.RUNTIME_DEOBF);
FMLLog.severe("Flags: %s", String.format("%16s", Integer.toBinaryString(flags)).replace(' ', '0'));
FMLLog.severe("Fields:");
for (Field field : fields)
{
String mods = String.format("%16s", Integer.toBinaryString(field.getModifiers())).replace(' ', '0');
lines.add(String.format(" %s %s: %s", mods, field.getName(), field.getType().getName()));
}
for (String line : lines)
FMLLog.severe(line);
if (test)
{
throw new EnhancedRuntimeException("Could not find $VALUES field for enum: " + enumType.getName())
{
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
for (String line : lines)
stream.println(line);
}
};
}
return null;
}
if (test)
{
Object ctr = null;
Exception ex = null;
try
{
ctr = getConstructorAccessor(enumType, paramTypes);
}
catch (Exception e)
{
ex = e;
}
if (ctr == null || ex != null)
{
throw new EnhancedRuntimeException(String.format("Could not find constructor for Enum %s", enumType.getName()), ex)
{
private String toString(Class<?>[] cls)
{
StringBuilder b = new StringBuilder();
for (int x = 0; x < cls.length; x++)
{
b.append(cls[x].getName());
if (x != cls.length - 1)
b.append(", ");
}
return b.toString();
}
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
stream.println("Target Arguments:");
stream.println(" java.lang.String, int, " + toString(paramTypes));
stream.println("Found Constructors:");
for (Constructor<?> ctr : enumType.getDeclaredConstructors())
{
stream.println(" " + toString(ctr.getParameterTypes()));
}
}
};
FMLLog.severe(" %s %s: %s", mods, field.getName(), field.getType().getName());
}
return null;
}
@@ -351,7 +262,7 @@ public class EnumHelper
{
T[] previousValues = (T[])valuesField.get(enumType);
List<T> values = new ArrayList<T>(Arrays.asList(previousValues));
T newValue = makeEnum(enumType, enumName, values.size(), paramTypes, paramValues);
T newValue = (T)makeEnum(enumType, enumName, values.size(), paramTypes, paramValues);
values.add(newValue);
setFailsafeFieldValue(valuesField, null, values.toArray((T[]) Array.newInstance(enumType, 0)));
cleanEnumCache(enumType);
@@ -0,0 +1,12 @@
package net.minecraftforge.common;
public enum EnumPlantType
{
Plains,
Desert,
Beach,
Cave,
Water,
Nether,
Crop
}
@@ -0,0 +1,48 @@
package net.minecraftforge.common;
import cpw.mods.fml.common.FMLCommonHandler;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemInWorldManager;
import net.minecraft.network.packet.Packet204ClientInfo;
import net.minecraft.server.MinecraftServer;
import net.minecraft.stats.StatBase;
import net.minecraft.util.ChatMessageComponent;
import net.minecraft.util.ChunkCoordinates;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;
//Preliminary, simple Fake Player class
public class FakePlayer extends EntityPlayerMP
{
public FakePlayer(World world, String name)
{
super(FMLCommonHandler.instance().getMinecraftServerInstance(), world, name, new ItemInWorldManager(world));
}
public void sendChatToPlayer(String s){}
public boolean canCommandSenderUseCommand(int i, String s){ return false; }
public ChunkCoordinates getPlayerCoordinates()
{
return new ChunkCoordinates(0,0,0);
}
@Override
public void sendChatToPlayer(ChatMessageComponent chatmessagecomponent){}
@Override
public void addStat(StatBase par1StatBase, int par2){}
@Override
public void openGui(Object mod, int modGuiId, World world, int x, int y, int z){}
@Override
public boolean isEntityInvulnerable(){ return true; }
@Override
public boolean canAttackPlayer(EntityPlayer player){ return false; }
@Override
public void onDeath(DamageSource source){ return; }
@Override
public void onUpdate(){ return; }
@Override
public void travelToDimension(int dim){ return; }
@Override
public void updateClientInfo(Packet204ClientInfo pkt){ return; }
}
@@ -0,0 +1,34 @@
package net.minecraftforge.common;
import net.minecraft.world.World;
//To be expanded for generic Mod fake players?
public class FakePlayerFactory
{
// Map of all active fake player usernames to their entities
private static java.util.Map<String, FakePlayer> fakePlayers = new java.util.HashMap<String, FakePlayer>();
private static FakePlayer MINECRAFT_PLAYER = null;
public static FakePlayer getMinecraft(World world)
{
if (MINECRAFT_PLAYER == null)
{
MINECRAFT_PLAYER = FakePlayerFactory.get(world, "[Minecraft]");
}
return MINECRAFT_PLAYER;
}
/**
* Get a fake player with a given username
*/
public static FakePlayer get(World world, String username)
{
if (!fakePlayers.containsKey(username))
{
FakePlayer fakePlayer = new FakePlayer(world, username);
fakePlayers.put(username, fakePlayer);
}
return fakePlayers.get(username);
}
}
@@ -1,82 +1,64 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import javax.annotation.Nullable;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ClassInheritanceMultiMap;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.common.config.ConfigCategory;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.eventhandler.Event;
import org.apache.logging.log4j.Level;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import com.google.common.collect.ForwardingSet;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterators;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Multiset;
import com.google.common.collect.Multisets;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultiset;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.MathHelper;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.ForgeChunkManager.Ticket;
import net.minecraftforge.event.Event;
/**
* Manages chunkloading for mods.
@@ -109,7 +91,7 @@ public class ForgeChunkManager
private static Map<String, LoadingCallback> callbacks = Maps.newHashMap();
private static Map<World, ImmutableSetMultimap<ChunkPos,Ticket>> forcedChunks = new MapMaker().weakKeys().makeMap();
private static Map<World, ImmutableSetMultimap<ChunkCoordIntPair,Ticket>> forcedChunks = new MapMaker().weakKeys().makeMap();
private static BiMap<UUID,Ticket> pendingEntities = HashBiMap.create();
private static Map<World,Cache<Long, Chunk>> dormantChunkCache = new MapMaker().weakKeys().makeMap();
@@ -119,35 +101,7 @@ public class ForgeChunkManager
private static int playerTicketLength;
private static int dormantChunkCacheSize;
public static final List<String> MOD_PROP_ORDER = new ArrayList<String>(2);
private static Set<String> warnedMods = Sets.newHashSet();
static
{
MOD_PROP_ORDER.add("maximumTicketCount");
MOD_PROP_ORDER.add("maximumChunksPerTicket");
}
public static Iterator<Chunk> getPersistentChunksIterableFor(final World world, Iterator<Chunk> chunkIterator)
{
final ImmutableSetMultimap<ChunkPos, Ticket> persistentChunksFor = getPersistentChunksFor(world);
final ImmutableSet.Builder<Chunk> builder = ImmutableSet.builder();
world.theProfiler.startSection("forcedChunkLoading");
builder.addAll(Iterators.transform(persistentChunksFor.keys().iterator(), new Function<ChunkPos, Chunk>() {
@Nullable
@Override
public Chunk apply(@Nullable ChunkPos input)
{
return world.getChunkFromChunkCoords(input.chunkXPos, input.chunkZPos);
}
}));
world.theProfiler.endStartSection("regularChunkLoading");
builder.addAll(chunkIterator);
world.theProfiler.endSection();
return builder.build().iterator();
}
/**
* All mods requiring chunkloading need to implement this to handle the
* re-registration of chunk tickets at world loading time
@@ -235,11 +189,11 @@ public class ForgeChunkManager
{
private String modId;
private Type ticketType;
private LinkedHashSet<ChunkPos> requestedChunks;
private LinkedHashSet<ChunkCoordIntPair> requestedChunks;
private NBTTagCompound modData;
public final World world;
private int maxDepth;
//private String entityClazz;
private String entityClazz;
private int entityChunkX;
private int entityChunkZ;
private Entity entity;
@@ -263,7 +217,7 @@ public class ForgeChunkManager
}
else
{
FMLLog.log(Level.ERROR, "Attempt to create a player ticket without a valid player");
FMLLog.log(Level.SEVERE, "Attempt to create a player ticket without a valid player");
throw new RuntimeException();
}
}
@@ -382,52 +336,32 @@ public class ForgeChunkManager
/**
* Gets a list of requested chunks for this ticket.
*/
public ImmutableSet<ChunkPos> getChunkList()
public ImmutableSet getChunkList()
{
return ImmutableSet.copyOf(requestedChunks);
}
}
public static class ForceChunkEvent extends Event {
private final Ticket ticket;
private final ChunkPos location;
public final Ticket ticket;
public final ChunkCoordIntPair location;
public ForceChunkEvent(Ticket ticket, ChunkPos location)
public ForceChunkEvent(Ticket ticket, ChunkCoordIntPair location)
{
this.ticket = ticket;
this.location = location;
}
public Ticket getTicket()
{
return ticket;
}
public ChunkPos getLocation()
{
return location;
}
}
public static class UnforceChunkEvent extends Event {
private final Ticket ticket;
private final ChunkPos location;
public final Ticket ticket;
public final ChunkCoordIntPair location;
public UnforceChunkEvent(Ticket ticket, ChunkPos location)
public UnforceChunkEvent(Ticket ticket, ChunkCoordIntPair location)
{
this.ticket = ticket;
this.location = location;
}
public Ticket getTicket()
{
return ticket;
}
public ChunkPos getLocation()
{
return location;
}
}
@@ -449,7 +383,7 @@ public class ForgeChunkManager
try
{
NBTTagCompound forcedChunkData = CompressedStreamTools.read(chunkLoaderData);
return forcedChunkData.getTagList("TicketList", Constants.NBT.TAG_COMPOUND).tagCount() > 0;
return forcedChunkData.getTagList("TicketList").tagCount() > 0;
}
catch (IOException e)
{
@@ -460,10 +394,10 @@ public class ForgeChunkManager
static void loadWorld(World world)
{
ArrayListMultimap<String, Ticket> newTickets = ArrayListMultimap.create();
ArrayListMultimap<String, Ticket> newTickets = ArrayListMultimap.<String, Ticket>create();
tickets.put(world, newTickets);
forcedChunks.put(world, ImmutableSetMultimap.<ChunkPos,Ticket>of());
forcedChunks.put(world, ImmutableSetMultimap.<ChunkCoordIntPair,Ticket>of());
if (!(world instanceof WorldServer))
{
@@ -477,7 +411,7 @@ public class ForgeChunkManager
if (chunkLoaderData.exists() && chunkLoaderData.isFile())
{
ArrayListMultimap<String, Ticket> loadedTickets = ArrayListMultimap.create();
ArrayListMultimap<String, Ticket> loadedTickets = ArrayListMultimap.<String, Ticket>create();
Map<String,ListMultimap<String,Ticket>> playerLoadedTickets = Maps.newHashMap();
NBTTagCompound forcedChunkData;
try
@@ -486,13 +420,13 @@ public class ForgeChunkManager
}
catch (IOException e)
{
FMLLog.log(Level.WARN, e, "Unable to read forced chunk data at %s - it will be ignored", chunkLoaderData.getAbsolutePath());
FMLLog.log(Level.WARNING, e, "Unable to read forced chunk data at %s - it will be ignored", chunkLoaderData.getAbsolutePath());
return;
}
NBTTagList ticketList = forcedChunkData.getTagList("TicketList", Constants.NBT.TAG_COMPOUND);
NBTTagList ticketList = forcedChunkData.getTagList("TicketList");
for (int i = 0; i < ticketList.tagCount(); i++)
{
NBTTagCompound ticketHolder = ticketList.getCompoundTagAt(i);
NBTTagCompound ticketHolder = (NBTTagCompound) ticketList.tagAt(i);
String modId = ticketHolder.getString("Owner");
boolean isPlayer = "Forge".equals(modId);
@@ -508,13 +442,13 @@ public class ForgeChunkManager
continue;
}
NBTTagList tickets = ticketHolder.getTagList("Tickets", Constants.NBT.TAG_COMPOUND);
NBTTagList tickets = ticketHolder.getTagList("Tickets");
for (int j = 0; j < tickets.tagCount(); j++)
{
NBTTagCompound ticket = tickets.getCompoundTagAt(j);
NBTTagCompound ticket = (NBTTagCompound) tickets.tagAt(j);
modId = ticket.hasKey("ModId") ? ticket.getString("ModId") : modId;
Type type = Type.values()[ticket.getByte("Type")];
//byte ticketChunkDepth = ticket.getByte("ChunkListDepth");
byte ticketChunkDepth = ticket.getByte("ChunkListDepth");
Ticket tick = new Ticket(modId, type, world);
if (ticket.hasKey("ModData"))
{
@@ -616,8 +550,8 @@ public class ForgeChunkManager
forcedChunks.remove(world);
dormantChunkCache.remove(world);
// integrated server is shutting down
if (!FMLCommonHandler.instance().getMinecraftServerInstance().isServerRunning())
// integrated server is shutting down
if (!MinecraftServer.getServer().isServerRunning())
{
playerTickets.clear();
tickets.clear();
@@ -692,7 +626,7 @@ public class ForgeChunkManager
ModContainer mc = getContainer(mod);
if (mc == null)
{
FMLLog.log(Level.ERROR, "Failed to locate the container for mod instance %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
FMLLog.log(Level.SEVERE, "Failed to locate the container for mod instance %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
return null;
}
if (playerTickets.get(player).size()>playerTicketLength)
@@ -718,7 +652,7 @@ public class ForgeChunkManager
ModContainer container = getContainer(mod);
if (container == null)
{
FMLLog.log(Level.ERROR, "Failed to locate the container for mod instance %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
FMLLog.log(Level.SEVERE, "Failed to locate the container for mod instance %s (%s : %x)", mod, mod.getClass().getName(), System.identityHashCode(mod));
return null;
}
String modId = container.getModId();
@@ -728,7 +662,7 @@ public class ForgeChunkManager
throw new RuntimeException("Invalid ticket request");
}
int allowedCount = getMaxTicketLengthFor(modId);
int allowedCount = ticketConstraints.containsKey(modId) ? ticketConstraints.get(modId) : defaultMaxCount;
if (tickets.get(world).get(modId).size() >= allowedCount)
{
@@ -762,7 +696,7 @@ public class ForgeChunkManager
}
if (ticket.requestedChunks!=null)
{
for (ChunkPos chunk : ImmutableSet.copyOf(ticket.requestedChunks))
for (ChunkCoordIntPair chunk : ImmutableSet.copyOf(ticket.requestedChunks))
{
unforceChunk(ticket, chunk);
}
@@ -786,7 +720,7 @@ public class ForgeChunkManager
* @param ticket The ticket registering the chunk
* @param chunk The chunk to force
*/
public static void forceChunk(Ticket ticket, ChunkPos chunk)
public static void forceChunk(Ticket ticket, ChunkCoordIntPair chunk)
{
if (ticket == null || chunk == null)
{
@@ -804,11 +738,11 @@ public class ForgeChunkManager
ticket.requestedChunks.add(chunk);
MinecraftForge.EVENT_BUS.post(new ForceChunkEvent(ticket, chunk));
ImmutableSetMultimap<ChunkPos, Ticket> newMap = ImmutableSetMultimap.<ChunkPos,Ticket>builder().putAll(forcedChunks.get(ticket.world)).put(chunk, ticket).build();
ImmutableSetMultimap<ChunkCoordIntPair, Ticket> newMap = ImmutableSetMultimap.<ChunkCoordIntPair,Ticket>builder().putAll(forcedChunks.get(ticket.world)).put(chunk, ticket).build();
forcedChunks.put(ticket.world, newMap);
if (ticket.maxDepth > 0 && ticket.requestedChunks.size() > ticket.maxDepth)
{
ChunkPos removed = ticket.requestedChunks.iterator().next();
ChunkCoordIntPair removed = ticket.requestedChunks.iterator().next();
unforceChunk(ticket,removed);
}
}
@@ -821,7 +755,7 @@ public class ForgeChunkManager
* @param ticket The ticket holding the chunk list
* @param chunk The chunk you wish to push to the end (so that it would be unloaded last)
*/
public static void reorderChunk(Ticket ticket, ChunkPos chunk)
public static void reorderChunk(Ticket ticket, ChunkCoordIntPair chunk)
{
if (ticket == null || chunk == null || !ticket.requestedChunks.contains(chunk))
{
@@ -836,7 +770,7 @@ public class ForgeChunkManager
* @param ticket The ticket holding the chunk
* @param chunk The chunk to unforce
*/
public static void unforceChunk(Ticket ticket, ChunkPos chunk)
public static void unforceChunk(Ticket ticket, ChunkCoordIntPair chunk)
{
if (ticket == null || chunk == null)
{
@@ -844,16 +778,14 @@ public class ForgeChunkManager
}
ticket.requestedChunks.remove(chunk);
MinecraftForge.EVENT_BUS.post(new UnforceChunkEvent(ticket, chunk));
LinkedHashMultimap<ChunkPos, Ticket> copy = LinkedHashMultimap.create(forcedChunks.get(ticket.world));
LinkedHashMultimap<ChunkCoordIntPair, Ticket> copy = LinkedHashMultimap.create(forcedChunks.get(ticket.world));
copy.remove(chunk, ticket);
ImmutableSetMultimap<ChunkPos, Ticket> newMap = ImmutableSetMultimap.copyOf(copy);
ImmutableSetMultimap<ChunkCoordIntPair, Ticket> newMap = ImmutableSetMultimap.copyOf(copy);
forcedChunks.put(ticket.world,newMap);
}
static void loadConfiguration()
{
ticketConstraints.clear();
chunkConstraints.clear();
for (String mod : config.getCategoryNames())
{
if (mod.equals("Forge") || mod.equals("defaults"))
@@ -876,9 +808,9 @@ public class ForgeChunkManager
* @param world
* @return the list of persistent chunks in the world
*/
public static ImmutableSetMultimap<ChunkPos, Ticket> getPersistentChunksFor(World world)
public static ImmutableSetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunksFor(World world)
{
return forcedChunks.containsKey(world) ? forcedChunks.get(world) : ImmutableSetMultimap.<ChunkPos,Ticket>of();
return forcedChunks.containsKey(world) ? forcedChunks.get(world) : ImmutableSetMultimap.<ChunkCoordIntPair,Ticket>of();
}
static void saveWorld(World world)
@@ -897,7 +829,6 @@ public class ForgeChunkManager
forcedChunkData.setTag("TicketList", ticketList);
Multimap<String, Ticket> ticketSet = tickets.get(worldServer);
if (ticketSet == null) return;
for (String modId : ticketSet.keySet())
{
NBTTagCompound ticketHolder = new NBTTagCompound();
@@ -919,7 +850,7 @@ public class ForgeChunkManager
}
if (tick.modData != null)
{
ticket.setTag("ModData", tick.modData);
ticket.setCompoundTag("ModData", tick.modData);
}
if (tick.ticketType == Type.ENTITY && tick.entity != null && tick.entity.writeToNBTOptional(new NBTTagCompound()))
{
@@ -941,7 +872,7 @@ public class ForgeChunkManager
}
catch (IOException e)
{
FMLLog.log(Level.WARN, e, "Unable to write forced chunk data to %s - chunkloading won't work", chunkLoaderData.getAbsolutePath());
FMLLog.log(Level.WARNING, e, "Unable to write forced chunk data to %s - chunkloading won't work", chunkLoaderData.getAbsolutePath());
return;
}
}
@@ -959,7 +890,7 @@ public class ForgeChunkManager
public static void putDormantChunk(long coords, Chunk chunk)
{
Cache<Long, Chunk> cache = dormantChunkCache.get(chunk.getWorld());
Cache<Long, Chunk> cache = dormantChunkCache.get(chunk.worldObj);
if (cache != null)
{
cache.put(coords, chunk);
@@ -976,12 +907,11 @@ public class ForgeChunkManager
Chunk chunk = cache.getIfPresent(coords);
if (chunk != null)
{
for (ClassInheritanceMultiMap<Entity> eList : chunk.getEntityLists())
for (List<Entity> eList : chunk.entityLists)
{
Iterator<Entity> itr = eList.iterator();
while (itr.hasNext())
for (Entity e: eList)
{
(itr.next()).resetEntityId();
e.resetEntityId();
}
}
}
@@ -1004,111 +934,53 @@ public class ForgeChunkManager
dest.delete();
}
cfgFile.renameTo(dest);
FMLLog.log(Level.ERROR, e, "A critical error occurred reading the forgeChunkLoading.cfg file, defaults will be used - the invalid file is backed up at forgeChunkLoading.cfg.bak");
FMLLog.log(Level.SEVERE, e, "A critical error occured reading the forgeChunkLoading.cfg file, defaults will be used - the invalid file is backed up at forgeChunkLoading.cfg.bak");
}
syncConfigDefaults();
}
config.addCustomCategoryComment("defaults", "Default configuration for forge chunk loading control");
Property maxTicketCount = config.get("defaults", "maximumTicketCount", 200);
maxTicketCount.comment = "The default maximum ticket count for a mod which does not have an override\n" +
"in this file. This is the number of chunk loading requests a mod is allowed to make.";
defaultMaxCount = maxTicketCount.getInt(200);
/**
* Synchronizes the local fields with the values in the Configuration object.
*/
public static void syncConfigDefaults()
{
// By adding a property order list we are defining the order that the properties will appear both in the config file and on the GUIs.
// Property order lists are defined per-ConfigCategory.
List<String> propOrder = new ArrayList<String>();
Property maxChunks = config.get("defaults", "maximumChunksPerTicket", 25);
maxChunks.comment = "The default maximum number of chunks a mod can force, per ticket, \n" +
"for a mod without an override. This is the maximum number of chunks a single ticket can force.";
defaultMaxChunks = maxChunks.getInt(25);
config.setCategoryComment("defaults", "Default configuration for forge chunk loading control")
.setCategoryRequiresWorldRestart("defaults", true);
Property playerTicketCount = config.get("defaults", "playerTicketCount", 500);
playerTicketCount.comment = "The number of tickets a player can be assigned instead of a mod. This is shared across all mods and it is up to the mods to use it.";
playerTicketLength = playerTicketCount.getInt(500);
Property temp = config.get("defaults", "enabled", true);
temp.setComment("Are mod overrides enabled?");
temp.setLanguageKey("forge.configgui.enableModOverrides");
overridesEnabled = temp.getBoolean(true);
propOrder.add("enabled");
Property dormantChunkCacheSizeProperty = config.get("defaults", "dormantChunkCacheSize", 0);
dormantChunkCacheSizeProperty.comment = "Unloaded chunks can first be kept in a dormant cache for quicker\n" +
"loading times. Specify the size (in chunks) of that cache here";
dormantChunkCacheSize = dormantChunkCacheSizeProperty.getInt(0);
FMLLog.info("Configured a dormant chunk cache size of %d", dormantChunkCacheSizeProperty.getInt(0));
temp = config.get("defaults", "maximumChunksPerTicket", 25);
temp.setComment("The default maximum number of chunks a mod can force, per ticket, \n" +
"for a mod without an override. This is the maximum number of chunks a single ticket can force.");
temp.setLanguageKey("forge.configgui.maximumChunksPerTicket");
temp.setMinValue(0);
defaultMaxChunks = temp.getInt(25);
propOrder.add("maximumChunksPerTicket");
temp = config.get("defaults", "maximumTicketCount", 200);
temp.setComment("The default maximum ticket count for a mod which does not have an override\n" +
"in this file. This is the number of chunk loading requests a mod is allowed to make.");
temp.setLanguageKey("forge.configgui.maximumTicketCount");
temp.setMinValue(0);
defaultMaxCount = temp.getInt(200);
propOrder.add("maximumTicketCount");
temp = config.get("defaults", "playerTicketCount", 500);
temp.setComment("The number of tickets a player can be assigned instead of a mod. This is shared across all mods and it is up to the mods to use it.");
temp.setLanguageKey("forge.configgui.playerTicketCount");
temp.setMinValue(0);
playerTicketLength = temp.getInt(500);
propOrder.add("playerTicketCount");
temp = config.get("defaults", "dormantChunkCacheSize", 0);
temp.setComment("Unloaded chunks can first be kept in a dormant cache for quicker\n" +
"loading times. Specify the size (in chunks) of that cache here");
temp.setLanguageKey("forge.configgui.dormantChunkCacheSize");
temp.setMinValue(0);
dormantChunkCacheSize = temp.getInt(0);
propOrder.add("dormantChunkCacheSize");
FMLLog.info("Configured a dormant chunk cache size of %d", temp.getInt(0));
config.setCategoryPropertyOrder("defaults", propOrder);
Property modOverridesEnabled = config.get("defaults", "enabled", true);
modOverridesEnabled.comment = "Are mod overrides enabled?";
overridesEnabled = modOverridesEnabled.getBoolean(true);
config.addCustomCategoryComment("Forge", "Sample mod specific control section.\n" +
"Copy this section and rename the with the modid for the mod you wish to override.\n" +
"A value of zero in either entry effectively disables any chunkloading capabilities\n" +
"for that mod");
temp = config.get("Forge", "maximumTicketCount", 200);
temp.setComment("Maximum ticket count for the mod. Zero disables chunkloading capabilities.");
temp = config.get("Forge", "maximumChunksPerTicket", 25);
temp.setComment("Maximum chunks per ticket for the mod.");
Property sampleTC = config.get("Forge", "maximumTicketCount", 200);
sampleTC.comment = "Maximum ticket count for the mod. Zero disables chunkloading capabilities.";
sampleTC = config.get("Forge", "maximumChunksPerTicket", 25);
sampleTC.comment = "Maximum chunks per ticket for the mod.";
for (String mod : config.getCategoryNames())
{
if (mod.equals("Forge") || mod.equals("defaults"))
{
continue;
}
config.get(mod, "maximumTicketCount", 200).setLanguageKey("forge.configgui.maximumTicketCount").setMinValue(0);
config.get(mod, "maximumChunksPerTicket", 25).setLanguageKey("forge.configgui.maximumChunksPerTicket").setMinValue(0);
}
if (config.hasChanged())
{
config.save();
Property modTC = config.get(mod, "maximumTicketCount", 200);
Property modCPT = config.get(mod, "maximumChunksPerTicket", 25);
}
}
public static Configuration getConfig()
{
return config;
}
public static ConfigCategory getDefaultsCategory()
{
return config.getCategory("defaults");
}
public static List<ConfigCategory> getModCategories()
{
List<ConfigCategory> list = new ArrayList<ConfigCategory>();
for (String mod : config.getCategoryNames())
{
if (mod.equals("Forge") || mod.equals("defaults"))
{
continue;
}
list.add(config.getCategory(mod));
}
return list;
}
public static ConfigCategory getConfigFor(Object mod)
{
@@ -1127,12 +999,7 @@ public class ForgeChunkManager
if (container != null)
{
ConfigCategory cat = config.getCategory(container.getModId());
Property prop = new Property(propertyName, value, type).setLanguageKey("forge.configgui." + propertyName);
if (type == Property.Type.INTEGER)
{
prop.setMinValue(0);
}
cat.put(propertyName, prop);
cat.put(propertyName, new Property(propertyName, value, type));
}
}
}
@@ -0,0 +1,71 @@
package net.minecraftforge.common;
public enum ForgeDirection
{
/** -Y */
DOWN(0, -1, 0),
/** +Y */
UP(0, 1, 0),
/** -Z */
NORTH(0, 0, -1),
/** +Z */
SOUTH(0, 0, 1),
/** -X */
WEST(-1, 0, 0),
/** +X */
EAST(1, 0, 0),
/**
* Used only by getOrientation, for invalid inputs
*/
UNKNOWN(0, 0, 0);
public final int offsetX;
public final int offsetY;
public final int offsetZ;
public final int flag;
public static final ForgeDirection[] VALID_DIRECTIONS = {DOWN, UP, NORTH, SOUTH, WEST, EAST};
public static final int[] OPPOSITES = {1, 0, 3, 2, 5, 4, 6};
// Left hand rule rotation matrix for all possible axes of rotation
public static final int[][] ROTATION_MATRIX = {
{0, 1, 4, 5, 3, 2, 6},
{0, 1, 5, 4, 2, 3, 6},
{5, 4, 2, 3, 0, 1, 6},
{4, 5, 2, 3, 1, 0, 6},
{2, 3, 1, 0, 4, 5, 6},
{3, 2, 0, 1, 4, 5, 6},
{0, 1, 2, 3, 4, 5, 6},
};
private ForgeDirection(int x, int y, int z)
{
offsetX = x;
offsetY = y;
offsetZ = z;
flag = 1 << ordinal();
}
public static ForgeDirection getOrientation(int id)
{
if (id >= 0 && id < VALID_DIRECTIONS.length)
{
return VALID_DIRECTIONS[id];
}
return UNKNOWN;
}
public ForgeDirection getOpposite()
{
return getOrientation(OPPOSITES[ordinal()]);
}
public ForgeDirection getRotation(ForgeDirection axis)
{
return getOrientation(ROTATION_MATRIX[axis.ordinal()][ordinal()]);
}
}
@@ -0,0 +1,254 @@
package net.minecraftforge.common;
import java.io.File;
import java.util.Arrays;
import java.util.Map;
import java.util.logging.Level;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.management.PlayerInstance;
import net.minecraft.world.storage.SaveHandler;
import net.minecraft.world.storage.WorldInfo;
import net.minecraftforge.classloading.FMLForgePlugin;
import net.minecraftforge.common.network.ForgeConnectionHandler;
import net.minecraftforge.common.network.ForgeNetworkHandler;
import net.minecraftforge.common.network.ForgePacketHandler;
import net.minecraftforge.common.network.ForgeTinyPacketHandler;
import net.minecraftforge.oredict.RecipeSorter;
import net.minecraftforge.server.command.ForgeCommand;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import cpw.mods.fml.client.FMLFileResourcePack;
import cpw.mods.fml.client.FMLFolderResourcePack;
import cpw.mods.fml.common.DummyModContainer;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.LoadController;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModMetadata;
import cpw.mods.fml.common.WorldAccessContainer;
import cpw.mods.fml.common.event.FMLConstructionEvent;
import cpw.mods.fml.common.event.FMLLoadCompleteEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
import cpw.mods.fml.common.network.FMLNetworkHandler;
import cpw.mods.fml.common.network.NetworkMod;
import static net.minecraftforge.common.ForgeVersion.*;
import static net.minecraftforge.common.Configuration.*;
@NetworkMod(
channels = "FORGE",
connectionHandler = ForgeConnectionHandler.class,
packetHandler = ForgePacketHandler.class,
tinyPacketHandler = ForgeTinyPacketHandler.class
)
public class ForgeDummyContainer extends DummyModContainer implements WorldAccessContainer
{
public static int clumpingThreshold = 64;
public static boolean removeErroringEntities = false;
public static boolean removeErroringTileEntities = false;
public static boolean disableStitchedFileSaving = false;
public static boolean forceDuplicateFluidBlockCrash = true;
public static boolean fullBoundingBoxLadders = false;
public static double zombieSummonBaseChance = 0.1;
public static int[] blendRanges = { 20, 15, 10, 5 };
public static float zombieBabyChance = 0.05f;
public static boolean shouldSortRecipies = false;
public ForgeDummyContainer()
{
super(new ModMetadata());
ModMetadata meta = getMetadata();
meta.modId = "Forge";
meta.name = "Minecraft Forge";
meta.version = String.format("%d.%d.%d.%d", majorVersion, minorVersion, revisionVersion, buildVersion);
meta.credits = "Made possible with help from many people";
meta.authorList = Arrays.asList("LexManos", "Eloraam", "Spacetoad");
meta.description = "Minecraft Forge is a common open source API allowing a broad range of mods " +
"to work cooperatively together. It allows many mods to be created without " +
"them editing the main Minecraft code.";
meta.url = "http://MinecraftForge.net";
meta.updateUrl = "http://MinecraftForge.net/forum/index.php/topic,5.0.html";
meta.screenshots = new String[0];
meta.logoFile = "/forge_logo.png";
Configuration config = null;
File cfgFile = new File(Loader.instance().getConfigDir(), "forge.cfg");
try
{
config = new Configuration(cfgFile);
}
catch (Exception e)
{
System.out.println("Error loading forge.cfg, deleting file and resetting: ");
e.printStackTrace();
if (cfgFile.exists())
cfgFile.delete();
config = new Configuration(cfgFile);
}
if (!config.isChild)
{
config.load();
Property enableGlobalCfg = config.get(Configuration.CATEGORY_GENERAL, "enableGlobalConfig", false);
if (enableGlobalCfg.getBoolean(false))
{
Configuration.enableGlobalConfig();
}
}
Property prop;
prop = config.get(Configuration.CATEGORY_GENERAL, "clumpingThreshold", 64);
prop.comment = "Controls the number threshold at which Packet51 is preferred over Packet52, default and minimum 64, maximum 1024";
clumpingThreshold = prop.getInt(64);
if (clumpingThreshold > 1024 || clumpingThreshold < 64)
{
clumpingThreshold = 64;
prop.set(64);
}
prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringEntities", false);
prop.comment = "Set this to just remove any TileEntity that throws a error in there update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.";
removeErroringEntities = prop.getBoolean(false);
if (removeErroringEntities)
{
FMLLog.warning("Enabling removal of erroring Entities - USE AT YOUR OWN RISK");
}
prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringTileEntities", false);
prop.comment = "Set this to just remove any TileEntity that throws a error in there update method instead of closing the server and reporting a crash log. BE WARNED THIS COULD SCREW UP EVERYTHING USE SPARINGLY WE ARE NOT RESPONSIBLE FOR DAMAGES.";
removeErroringTileEntities = prop.getBoolean(false);
if (removeErroringTileEntities)
{
FMLLog.warning("Enabling removal of erroring Tile Entities - USE AT YOUR OWN RISK");
}
//prop = config.get(Configuration.CATEGORY_GENERAL, "disableStitchedFileSaving", true);
//prop.comment = "Set this to just disable the texture stitcher from writing the 'debug.stitched_{name}.png file to disc. Just a small performance tweak. Default: true";
//disableStitchedFileSaving = prop.getBoolean(true);
prop = config.get(Configuration.CATEGORY_GENERAL, "fullBoundingBoxLadders", false);
prop.comment = "Set this to check the entire entity's collision bounding box for ladders instead of just the block they are in. Causes noticable differences in mechanics so default is vanilla behavior. Default: false";
fullBoundingBoxLadders = prop.getBoolean(false);
prop = config.get(Configuration.CATEGORY_GENERAL, "forceDuplicateFluidBlockCrash", true);
prop.comment = "Set this to force a crash if more than one block attempts to link back to the same Fluid. Enabled by default.";
forceDuplicateFluidBlockCrash = prop.getBoolean(true);
if (!forceDuplicateFluidBlockCrash)
{
FMLLog.warning("Disabling forced crashes on duplicate Fluid Blocks - USE AT YOUR OWN RISK");
}
prop = config.get(Configuration.CATEGORY_GENERAL, "biomeSkyBlendRange", new int[] { 20, 15, 10, 5 });
prop.comment = "Control the range of sky blending for colored skies in biomes.";
blendRanges = prop.getIntList();
prop = config.get(Configuration.CATEGORY_GENERAL, "zombieBaseSummonChance", 0.1);
prop.comment = "Base zombie summoning spawn chance. Allows changing the bonus zombie summoning mechanic.";
zombieSummonBaseChance = prop.getDouble(0.1);
prop = config.get(Configuration.CATEGORY_GENERAL, "zombieBabyChance", 0.05);
prop.comment = "Chance that a zombie (or subclass) is a baby. Allows changing the zombie spawning mechanic.";
zombieBabyChance = (float) prop.getDouble(0.05);
prop = config.get(CATEGORY_GENERAL, "sortRecipies", shouldSortRecipies);
prop.comment = "Set to true to enable the post initlization sorting of crafting recipes using Froge's sorter. May cause desyncing on conflicting recipies. ToDo: Set to true by default in 1.7";
shouldSortRecipies = prop.getBoolean(shouldSortRecipies);
if (config.hasChanged())
{
config.save();
}
}
@Override
public boolean registerBus(EventBus bus, LoadController controller)
{
bus.register(this);
return true;
}
@Subscribe
public void modConstruction(FMLConstructionEvent evt)
{
FMLLog.info("Registering Forge Packet Handler");
try
{
FMLNetworkHandler.instance().registerNetworkMod(new ForgeNetworkHandler(this));
FMLLog.info("Succeeded registering Forge Packet Handler");
}
catch (Exception e)
{
FMLLog.log(Level.SEVERE, e, "Failed to register packet handler for Forge");
}
}
@Subscribe
public void preInit(FMLPreInitializationEvent evt)
{
ForgeChunkManager.captureConfig(evt.getModConfigurationDirectory());
}
@Subscribe
public void postInit(FMLPostInitializationEvent evt)
{
BiomeDictionary.registerAllBiomesAndGenerateEvents();
ForgeChunkManager.loadConfiguration();
}
@Subscribe
public void onAvalible(FMLLoadCompleteEvent evt)
{
if (shouldSortRecipies)
{
RecipeSorter.sortCraftManager();
}
}
@Subscribe
public void serverStarting(FMLServerStartingEvent evt)
{
evt.registerServerCommand(new ForgeCommand(evt.getServer()));
}
@Override
public NBTTagCompound getDataForWriting(SaveHandler handler, WorldInfo info)
{
NBTTagCompound forgeData = new NBTTagCompound();
NBTTagCompound dimData = DimensionManager.saveDimensionDataMap();
forgeData.setCompoundTag("DimensionData", dimData);
return forgeData;
}
@Override
public void readData(SaveHandler handler, WorldInfo info, Map<String, NBTBase> propertyMap, NBTTagCompound tag)
{
if (tag.hasKey("DimensionData"))
{
DimensionManager.loadDimensionDataMap(tag.hasKey("DimensionData") ? tag.getCompoundTag("DimensionData") : null);
}
}
@Override
public File getSource()
{
return FMLForgePlugin.forgeLocation;
}
@Override
public Class<?> getCustomResourcePackClass()
{
if (getSource().isDirectory())
{
return FMLFolderResourcePack.class;
}
else
{
return FMLFileResourcePack.class;
}
}
}
@@ -0,0 +1,500 @@
package net.minecraftforge.common;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.Container;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemAxe;
import net.minecraft.item.ItemPickaxe;
import net.minecraft.item.ItemSpade;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.network.NetServerHandler;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.Packet53BlockChange;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.ChatMessageComponent;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumMovingObjectType;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.WeightedRandom;
import net.minecraft.util.WeightedRandomItem;
import net.minecraft.world.EnumGameType;
import net.minecraft.world.World;
import net.minecraftforge.event.Event;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.event.ServerChatEvent;
import net.minecraftforge.event.entity.item.ItemTossEvent;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
import net.minecraftforge.event.entity.living.LivingFallEvent;
import net.minecraftforge.event.entity.living.LivingHurtEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.event.entity.player.PlayerOpenContainerEvent;
import net.minecraftforge.event.world.BlockEvent;
public class ForgeHooks
{
static class GrassEntry extends WeightedRandomItem
{
public final Block block;
public final int metadata;
public GrassEntry(Block block, int meta, int weight)
{
super(weight);
this.block = block;
this.metadata = meta;
}
}
static class SeedEntry extends WeightedRandomItem
{
public final ItemStack seed;
public SeedEntry(ItemStack seed, int weight)
{
super(weight);
this.seed = seed;
}
}
static final List<GrassEntry> grassList = new ArrayList<GrassEntry>();
static final List<SeedEntry> seedList = new ArrayList<SeedEntry>();
public static void plantGrass(World world, int x, int y, int z)
{
GrassEntry grass = (GrassEntry)WeightedRandom.getRandomItem(world.rand, grassList);
if (grass == null || grass.block == null || !grass.block.canBlockStay(world, x, y, z))
{
return;
}
world.setBlock(x, y, z, grass.block.blockID, grass.metadata, 3);
}
public static ItemStack getGrassSeed(World world)
{
SeedEntry entry = (SeedEntry)WeightedRandom.getRandomItem(world.rand, seedList);
if (entry == null || entry.seed == null)
{
return null;
}
return entry.seed.copy();
}
private static boolean toolInit = false;
static HashMap<Item, List> toolClasses = new HashMap<Item, List>();
static HashMap<List, Integer> toolHarvestLevels = new HashMap<List, Integer>();
static HashSet<List> toolEffectiveness = new HashSet<List>();
public static boolean canHarvestBlock(Block block, EntityPlayer player, int metadata)
{
if (block.blockMaterial.isToolNotRequired())
{
return true;
}
ItemStack stack = player.inventory.getCurrentItem();
if (stack == null)
{
return player.canHarvestBlock(block);
}
List info = toolClasses.get(stack.getItem());
if (info == null)
{
return player.canHarvestBlock(block);
}
Object[] tmp = info.toArray();
String toolClass = (String)tmp[0];
int harvestLevel = (Integer)tmp[1];
Integer blockHarvestLevel = toolHarvestLevels.get(Arrays.asList(block, metadata, toolClass));
if (blockHarvestLevel == null)
{
return player.canHarvestBlock(block);
}
if (blockHarvestLevel > harvestLevel)
{
return false;
}
return true;
}
public static boolean canToolHarvestBlock(Block block, int metadata, ItemStack stack)
{
if (stack == null) return false;
List info = toolClasses.get(stack.getItem());
if (info == null) return false;
Object[] tmp = info.toArray();
String toolClass = (String)tmp[0];
int harvestLevel = (Integer)tmp[1];
Integer blockHarvestLevel = toolHarvestLevels.get(Arrays.asList(block, metadata, toolClass));
return !(blockHarvestLevel == null || blockHarvestLevel > harvestLevel);
}
public static float blockStrength(Block block, EntityPlayer player, World world, int x, int y, int z)
{
int metadata = world.getBlockMetadata(x, y, z);
float hardness = block.getBlockHardness(world, x, y, z);
if (hardness < 0.0F)
{
return 0.0F;
}
if (!canHarvestBlock(block, player, metadata))
{
float speed = ForgeEventFactory.getBreakSpeed(player, block, metadata, 1.0f);
return (speed < 0 ? 0 : speed) / hardness / 100F;
}
else
{
return player.getCurrentPlayerStrVsBlock(block, false, metadata) / hardness / 30F;
}
}
public static boolean isToolEffective(ItemStack stack, Block block, int metadata)
{
List toolClass = toolClasses.get(stack.getItem());
return toolClass != null && toolEffectiveness.contains(Arrays.asList(block, metadata, toolClass.get(0)));
}
static void initTools()
{
if (toolInit)
{
return;
}
toolInit = true;
MinecraftForge.setToolClass(Item.pickaxeWood, "pickaxe", 0);
MinecraftForge.setToolClass(Item.pickaxeStone, "pickaxe", 1);
MinecraftForge.setToolClass(Item.pickaxeIron, "pickaxe", 2);
MinecraftForge.setToolClass(Item.pickaxeGold, "pickaxe", 0);
MinecraftForge.setToolClass(Item.pickaxeDiamond, "pickaxe", 3);
MinecraftForge.setToolClass(Item.axeWood, "axe", 0);
MinecraftForge.setToolClass(Item.axeStone, "axe", 1);
MinecraftForge.setToolClass(Item.axeIron, "axe", 2);
MinecraftForge.setToolClass(Item.axeGold, "axe", 0);
MinecraftForge.setToolClass(Item.axeDiamond, "axe", 3);
MinecraftForge.setToolClass(Item.shovelWood, "shovel", 0);
MinecraftForge.setToolClass(Item.shovelStone, "shovel", 1);
MinecraftForge.setToolClass(Item.shovelIron, "shovel", 2);
MinecraftForge.setToolClass(Item.shovelGold, "shovel", 0);
MinecraftForge.setToolClass(Item.shovelDiamond, "shovel", 3);
for (Block block : ItemPickaxe.blocksEffectiveAgainst)
{
MinecraftForge.setBlockHarvestLevel(block, "pickaxe", 0);
}
for (Block block : ItemSpade.blocksEffectiveAgainst)
{
MinecraftForge.setBlockHarvestLevel(block, "shovel", 0);
}
for (Block block : ItemAxe.blocksEffectiveAgainst)
{
MinecraftForge.setBlockHarvestLevel(block, "axe", 0);
}
MinecraftForge.setBlockHarvestLevel(Block.obsidian, "pickaxe", 3);
MinecraftForge.setBlockHarvestLevel(Block.oreEmerald, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.oreDiamond, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.blockDiamond, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.oreGold, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.blockGold, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.oreIron, "pickaxe", 1);
MinecraftForge.setBlockHarvestLevel(Block.blockIron, "pickaxe", 1);
MinecraftForge.setBlockHarvestLevel(Block.oreLapis, "pickaxe", 1);
MinecraftForge.setBlockHarvestLevel(Block.blockLapis, "pickaxe", 1);
MinecraftForge.setBlockHarvestLevel(Block.oreRedstone, "pickaxe", 2);
MinecraftForge.setBlockHarvestLevel(Block.oreRedstoneGlowing, "pickaxe", 2);
MinecraftForge.removeBlockEffectiveness(Block.oreRedstone, "pickaxe");
MinecraftForge.removeBlockEffectiveness(Block.obsidian, "pickaxe");
MinecraftForge.removeBlockEffectiveness(Block.oreRedstoneGlowing, "pickaxe");
}
public static int getTotalArmorValue(EntityPlayer player)
{
int ret = 0;
for (int x = 0; x < player.inventory.armorInventory.length; x++)
{
ItemStack stack = player.inventory.armorInventory[x];
if (stack != null && stack.getItem() instanceof ISpecialArmor)
{
ret += ((ISpecialArmor)stack.getItem()).getArmorDisplay(player, stack, x);
}
else if (stack != null && stack.getItem() instanceof ItemArmor)
{
ret += ((ItemArmor)stack.getItem()).damageReduceAmount;
}
}
return ret;
}
static
{
grassList.add(new GrassEntry(Block.plantYellow, 0, 20));
grassList.add(new GrassEntry(Block.plantRed, 0, 10));
seedList.add(new SeedEntry(new ItemStack(Item.seeds), 10));
initTools();
}
/**
* Called when a player uses 'pick block', calls new Entity and Block hooks.
*/
public static boolean onPickBlock(MovingObjectPosition target, EntityPlayer player, World world)
{
ItemStack result = null;
boolean isCreative = player.capabilities.isCreativeMode;
if (target.typeOfHit == EnumMovingObjectType.TILE)
{
int x = target.blockX;
int y = target.blockY;
int z = target.blockZ;
Block var8 = Block.blocksList[world.getBlockId(x, y, z)];
if (var8 == null)
{
return false;
}
result = var8.getPickBlock(target, world, x, y, z);
}
else
{
if (target.typeOfHit != EnumMovingObjectType.ENTITY || target.entityHit == null || !isCreative)
{
return false;
}
result = target.entityHit.getPickedResult(target);
}
if (result == null)
{
return false;
}
for (int x = 0; x < 9; x++)
{
ItemStack stack = player.inventory.getStackInSlot(x);
if (stack != null && stack.isItemEqual(result) && ItemStack.areItemStackTagsEqual(stack, result))
{
player.inventory.currentItem = x;
return true;
}
}
if (!isCreative)
{
return false;
}
int slot = player.inventory.getFirstEmptyStack();
if (slot < 0 || slot >= 9)
{
slot = player.inventory.currentItem;
}
player.inventory.setInventorySlotContents(slot, result);
player.inventory.currentItem = slot;
return true;
}
//Optifine Helper Functions u.u, these are here specifically for Optifine
//Note: When using Optfine, these methods are invoked using reflection, which
//incurs a major performance penalty.
public static void onLivingSetAttackTarget(EntityLivingBase entity, EntityLivingBase target)
{
MinecraftForge.EVENT_BUS.post(new LivingSetAttackTargetEvent(entity, target));
}
public static boolean onLivingUpdate(EntityLivingBase entity)
{
return MinecraftForge.EVENT_BUS.post(new LivingUpdateEvent(entity));
}
public static boolean onLivingAttack(EntityLivingBase entity, DamageSource src, float amount)
{
return MinecraftForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, amount));
}
public static float onLivingHurt(EntityLivingBase entity, DamageSource src, float amount)
{
LivingHurtEvent event = new LivingHurtEvent(entity, src, amount);
return (MinecraftForge.EVENT_BUS.post(event) ? 0 : event.ammount);
}
public static boolean onLivingDeath(EntityLivingBase entity, DamageSource src)
{
return MinecraftForge.EVENT_BUS.post(new LivingDeathEvent(entity, src));
}
public static boolean onLivingDrops(EntityLivingBase entity, DamageSource source, ArrayList<EntityItem> drops, int lootingLevel, boolean recentlyHit, int specialDropValue)
{
return MinecraftForge.EVENT_BUS.post(new LivingDropsEvent(entity, source, drops, lootingLevel, recentlyHit, specialDropValue));
}
public static float onLivingFall(EntityLivingBase entity, float distance)
{
LivingFallEvent event = new LivingFallEvent(entity, distance);
return (MinecraftForge.EVENT_BUS.post(event) ? 0.0f : event.distance);
}
public static boolean isLivingOnLadder(Block block, World world, int x, int y, int z, EntityLivingBase entity)
{
if (!ForgeDummyContainer.fullBoundingBoxLadders)
{
return block != null && block.isLadder(world, x, y, z, entity);
}
else
{
AxisAlignedBB bb = entity.boundingBox;
int mX = MathHelper.floor_double(bb.minX);
int mY = MathHelper.floor_double(bb.minY);
int mZ = MathHelper.floor_double(bb.minZ);
for (int y2 = mY; y2 < bb.maxY; y2++)
{
for (int x2 = mX; x2 < bb.maxX; x2++)
{
for (int z2 = mZ; z2 < bb.maxZ; z2++)
{
block = Block.blocksList[world.getBlockId(x2, y2, z2)];
if (block != null && block.isLadder(world, x2, y2, z2, entity))
{
return true;
}
}
}
}
return false;
}
}
public static void onLivingJump(EntityLivingBase entity)
{
MinecraftForge.EVENT_BUS.post(new LivingJumpEvent(entity));
}
public static EntityItem onPlayerTossEvent(EntityPlayer player, ItemStack item)
{
player.captureDrops = true;
EntityItem ret = player.dropPlayerItemWithRandomChoice(item, false);
player.capturedDrops.clear();
player.captureDrops = false;
if (ret == null)
{
return null;
}
ItemTossEvent event = new ItemTossEvent(ret, player);
if (MinecraftForge.EVENT_BUS.post(event))
{
return null;
}
player.joinEntityItemWithWorld(event.entityItem);
return event.entityItem;
}
public static float getEnchantPower(World world, int x, int y, int z)
{
if (world.isAirBlock(x, y, z))
{
return 0;
}
Block block = Block.blocksList[world.getBlockId(x, y, z)];
return (block == null ? 0 : block.getEnchantPowerBonus(world, x, y, z));
}
public static ChatMessageComponent onServerChatEvent(NetServerHandler net, String raw, ChatMessageComponent comp)
{
ServerChatEvent event = new ServerChatEvent(net.playerEntity, raw, comp);
if (MinecraftForge.EVENT_BUS.post(event))
{
return null;
}
return event.component;
}
public static boolean canInteractWith(EntityPlayer player, Container openContainer)
{
PlayerOpenContainerEvent event = new PlayerOpenContainerEvent(player, openContainer);
MinecraftForge.EVENT_BUS.post(event);
return event.getResult() == Event.Result.DEFAULT ? event.canInteractWith : event.getResult() == Event.Result.ALLOW ? true : false;
}
public static BlockEvent.BreakEvent onBlockBreakEvent(World world, EnumGameType gameType, EntityPlayerMP entityPlayer, int x, int y, int z)
{
// Logic from tryHarvestBlock for pre-canceling the event
boolean preCancelEvent = false;
if (gameType.isAdventure() && !entityPlayer.isCurrentToolAdventureModeExempt(x, y, z))
{
preCancelEvent = true;
}
else if (gameType.isCreative() && entityPlayer.getHeldItem() != null && entityPlayer.getHeldItem().getItem() instanceof ItemSword)
{
preCancelEvent = true;
}
// Tell client the block is gone immediately then process events
if (world.getBlockTileEntity(x, y, z) == null)
{
Packet53BlockChange packet = new Packet53BlockChange(x, y, z, world);
packet.type = 0;
packet.metadata = 0;
entityPlayer.playerNetServerHandler.sendPacketToPlayer(packet);
}
// Post the block break event
Block block = Block.blocksList[world.getBlockId(x, y, z)];
int blockMetadata = world.getBlockMetadata(x, y, z);
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(x, y, z, world, block, blockMetadata, entityPlayer);
event.setCanceled(preCancelEvent);
MinecraftForge.EVENT_BUS.post(event);
// Handle if the event is canceled
if (event.isCanceled())
{
// Let the client know the block still exists
entityPlayer.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(x, y, z, world));
// Update any tile entity data for this block
TileEntity tileentity = world.getBlockTileEntity(x, y, z);
if (tileentity != null)
{
Packet pkt = tileentity.getDescriptionPacket();
if (pkt != null)
{
entityPlayer.playerNetServerHandler.sendPacketToPlayer(pkt);
}
}
}
return event;
}
}
@@ -0,0 +1,78 @@
package net.minecraftforge.common;
import java.util.UUID;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.event.*;
import net.minecraftforge.event.entity.*;
import net.minecraftforge.event.world.WorldEvent;
public class ForgeInternalHandler
{
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onEntityJoinWorld(EntityJoinWorldEvent event)
{
if (!event.world.isRemote)
{
ForgeChunkManager.loadEntity(event.entity);
}
Entity entity = event.entity;
if (entity.getClass().equals(EntityItem.class))
{
ItemStack stack = entity.getDataWatcher().getWatchableObjectItemStack(10);
if (stack == null)
{
//entity.setDead();
//event.setCanceled(true);
return;
}
Item item = stack.getItem();
if (item == null)
{
FMLLog.warning("Attempted to add a EntityItem to the world with a invalid item: ID %d at " +
"(%2.2f, %2.2f, %2.2f), this is most likely a config issue between you and the server. Please double check your configs",
stack.itemID, entity.posX, entity.posY, entity.posZ);
entity.setDead();
event.setCanceled(true);
return;
}
if (item.hasCustomEntity(stack))
{
Entity newEntity = item.createEntity(event.world, entity, stack);
if (newEntity != null)
{
entity.setDead();
event.setCanceled(true);
event.world.spawnEntityInWorld(newEntity);
}
}
}
}
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onDimensionLoad(WorldEvent.Load event)
{
ForgeChunkManager.loadWorld(event.world);
}
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onDimensionSave(WorldEvent.Save event)
{
ForgeChunkManager.saveWorld(event.world);
}
@ForgeSubscribe(priority = EventPriority.HIGHEST)
public void onDimensionUnload(WorldEvent.Unload event)
{
ForgeChunkManager.unloadWorld(event.world);
}
}
@@ -0,0 +1,44 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
public class ForgeVersion
{
//This number is incremented every time we remove deprecated code/major API changes, never reset
public static final int majorVersion = 9;
//This number is incremented every minecraft release, never reset
public static final int minorVersion = 11;
//This number is incremented every time a interface changes or new major feature is added, and reset every Minecraft version
public static final int revisionVersion = 1;
//This number is incremented every time Jenkins builds Forge, and never reset. Should always be 0 in the repo code.
public static final int buildVersion = 0;
public static int getMajorVersion()
{
return majorVersion;
}
public static int getMinorVersion()
{
return minorVersion;
}
public static int getRevisionVersion()
{
return revisionVersion;
}
public static int getBuildVersion()
{
return buildVersion;
}
public static String getVersion()
{
return String.format("%d.%d.%d.%d", majorVersion, minorVersion, revisionVersion, buildVersion);
}
}
@@ -0,0 +1,37 @@
package net.minecraftforge.common;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.World;
/**
* Allows for custom entity data and logic to be hooked to existing entity classes.
*
* @author cpw, mithion
*
*/
public interface IExtendedEntityProperties {
/**
* Called when the entity that this class is attached to is saved.
* Any custom entity data that needs saving should be saved here.
* @param compound The compound to save to.
*/
public void saveNBTData(NBTTagCompound compound);
/**
* Called when the entity that this class is attached to is loaded.
* In order to hook into this, you will need to subscribe to the EntityConstructing event.
* Otherwise, you will need to initialize manually.
* @param compound The compound to load from.
*/
public void loadNBTData(NBTTagCompound compound);
/**
* Used to initialize the extended properties with the entity that this is attached to, as well
* as the world object.
* Called automatically if you register with the EntityConstructing event.
* @param entity The entity that this extended properties is attached to
* @param world The world in which the entity exists
*/
public void init(Entity entity, World world);
}
@@ -1,25 +1,6 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityMinecart;
@@ -33,7 +14,7 @@ public interface IMinecartCollisionHandler
{
/**
* This basically replaces the function of the same name in EntityMinecart.
* This basically replaces the function of the same name in EnityMinecart.
* Code in IMinecartHooks.applyEntityCollisionHook is still run.
* @param cart The cart that called the collision.
* @param other The object it collided with.
@@ -0,0 +1,10 @@
package net.minecraftforge.common;
import net.minecraft.world.World;
public interface IPlantable
{
public EnumPlantType getPlantType(World world, int x, int y, int z);
public int getPlantID(World world, int x, int y, int z);
public int getPlantMetadata(World world, int x, int y, int z);
}
@@ -1,29 +1,11 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common;
import java.util.List;
import java.util.ArrayList;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.World;
/**
*
@@ -41,17 +23,18 @@ public interface IShearable
*
* @param item The itemstack that is being used, Possible to be null
* @param world The current world
* @param pos Block's position in world.
* @param x The X Position
* @param y The Y Position
* @param z The Z Position
* @return If this is shearable, and onSheared should be called.
*/
public boolean isShearable(ItemStack item, IBlockAccess world, BlockPos pos);
public boolean isShearable(ItemStack item, World world, int x, int y, int z);
/**
* Performs the shear function on this object.
* This is called for both client, and server.
* The object should perform all actions related to being sheared,
* except for dropping of the items, and removal of the block.
* As those are handled by ItemShears itself.
* except for dropping of the items.
*
* Returns a list of items that resulted from the shearing process.
*
@@ -60,9 +43,11 @@ public interface IShearable
*
* @param item The itemstack that is being used, Possible to be null
* @param world The current world
* @param pos If this is a block, the block's position in world.
* @param x The X Position
* @param y The Y Position
* @param z The Z Position
* @param fortune The fortune level of the shears being used
* @return A ArrayList containing all items from this shearing. Possible to be null.
*/
public List<ItemStack> onSheared(ItemStack item, IBlockAccess world, BlockPos pos, int fortune);
public ArrayList<ItemStack> onSheared(ItemStack item, World world, int x, int y, int z, int fortune);
}
@@ -1,22 +1,3 @@
/*
* Minecraft Forge
* Copyright (c) 2016.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
@@ -42,7 +23,6 @@ import net.minecraft.item.ItemStack;
*/
public interface ISpecialArmor
{
//TODO: Change 'int slot' to EnumArmorType
/**
* Retrieves the modifiers to be used when calculating armor damage.
*
@@ -84,14 +64,14 @@ public interface ISpecialArmor
* @param slot The armor slot the item is in.
*/
public abstract void damageArmor(EntityLivingBase entity, ItemStack stack, DamageSource source, int damage, int slot);
public static class ArmorProperties implements Comparable<ArmorProperties>
{
public int Priority = 0;
public int AbsorbMax = Integer.MAX_VALUE;
public double AbsorbRatio = 0;
public int Slot = 0;
private static final boolean DEBUG = false; //Only enable this if you wish to be spammed with debugging information.
private static final boolean DEBUG = false; //Only enable this if you wish to be spamed with debugging information.
//Left it in because I figured it'd be useful for modders developing custom armor.
public ArmorProperties(int priority, double ratio, int max)
@@ -110,7 +90,7 @@ public interface ISpecialArmor
* @param damage The total damage being done
* @return The left over damage that has not been absorbed by the armor
*/
public static float applyArmor(EntityLivingBase entity, ItemStack[] inventory, DamageSource source, double damage)
public static float ApplyArmor(EntityLivingBase entity, ItemStack[] inventory, DamageSource source, double damage)
{
if (DEBUG)
{
@@ -134,7 +114,7 @@ public interface ISpecialArmor
else if (stack.getItem() instanceof ItemArmor && !source.isUnblockable())
{
ItemArmor armor = (ItemArmor)stack.getItem();
prop = new ArmorProperties(0, armor.damageReduceAmount / 25D, Integer.MAX_VALUE);
prop = new ArmorProperties(0, armor.damageReduceAmount / 25D, armor.getMaxDamage() + 1 - stack.getItemDamage());
}
if (prop != null)
{
@@ -313,7 +293,6 @@ public interface ISpecialArmor
}
}
@Override
public int compareTo(ArmorProperties o)
{
if (o.Priority != Priority)
@@ -325,7 +304,6 @@ public interface ISpecialArmor
return (int)(left - right);
}
@Override
public String toString()
{
return String.format("%d, %d, %f, %d", Priority, AbsorbMax, AbsorbRatio, (AbsorbRatio == 0 ? 0 : (int)(AbsorbMax * 100.0D / AbsorbRatio)));
@@ -0,0 +1,222 @@
package net.minecraftforge.common;
import java.lang.reflect.Constructor;
import java.util.*;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.crash.CrashReport;
import net.minecraft.entity.monster.EntityEnderman;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.ForgeHooks.GrassEntry;
import net.minecraftforge.common.ForgeHooks.SeedEntry;
import net.minecraftforge.event.EventBus;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.oredict.OreDictionary;
public class MinecraftForge
{
/**
* The core Forge EventBusses, all events for Forge will be fired on these,
* you should use this to register all your listeners.
* This replaces every register*Handler() function in the old version of Forge.
* TERRAIN_GEN_BUS for terrain gen events
* ORE_GEN_BUS for ore gen events
* EVENT_BUS for everything else
*/
public static final EventBus EVENT_BUS = new EventBus();
public static final EventBus TERRAIN_GEN_BUS = new EventBus();
public static final EventBus ORE_GEN_BUS = new EventBus();
private static final ForgeInternalHandler INTERNAL_HANDLER = new ForgeInternalHandler();
/** Register a new plant to be planted when bonemeal is used on grass.
* @param block The block to place.
* @param metadata The metadata to set for the block when being placed.
* @param weight The weight of the plant, where red flowers are
* 10 and yellow flowers are 20.
*/
public static void addGrassPlant(Block block, int metadata, int weight)
{
ForgeHooks.grassList.add(new GrassEntry(block, metadata, weight));
}
/**
* Register a new seed to be dropped when breaking tall grass.
*
* @param seed The item to drop as a seed.
* @param weight The relative probability of the seeds,
* where wheat seeds are 10.
*/
public static void addGrassSeed(ItemStack seed, int weight)
{
ForgeHooks.seedList.add(new SeedEntry(seed, weight));
}
/**
*
* Register a tool as a tool class with a given harvest level.
*
* @param tool The custom tool to register.
* @param toolClass The tool class to register as. The predefined tool
* clases are "pickaxe", "shovel", "axe". You can add
* others for custom tools.
* @param harvestLevel The harvest level of the tool.
*/
public static void setToolClass(Item tool, String toolClass, int harvestLevel)
{
ForgeHooks.toolClasses.put(tool, Arrays.asList(toolClass, harvestLevel));
}
/**
* Register a block to be harvested by a tool class. This is the metadata
* sensitive version, use it if your blocks are using metadata variants.
* By default, this sets the block class as effective against that type.
*
* @param block The block to register.
* @param metadata The metadata for the block subtype.
* @param toolClass The tool class to register as able to remove this block.
* You may register the same block multiple times with different tool
* classes, if multiple tool types can be used to harvest this block.
* @param harvestLevel The minimum tool harvest level required to successfully
* harvest the block.
* @see MinecraftForge#setToolClass for details on tool classes.
*/
public static void setBlockHarvestLevel(Block block, int metadata, String toolClass, int harvestLevel)
{
List key = Arrays.asList(block, metadata, toolClass);
ForgeHooks.toolHarvestLevels.put(key, harvestLevel);
ForgeHooks.toolEffectiveness.add(key);
}
/**
* Remove a block effectiveness mapping. Since setBlockHarvestLevel
* makes the tool class effective against the block by default, this can be
* used to remove that mapping. This will force a block to be harvested at
* the same speed regardless of tool quality, while still requiring a given
* harvesting level.
*
* @param block The block to remove effectiveness from.
* @param metadata The metadata for the block subtype.
* @param toolClass The tool class to remove the effectiveness mapping from.
* @see MinecraftForge#setToolClass for details on tool classes.
*/
public static void removeBlockEffectiveness(Block block, int metadata, String toolClass)
{
List key = Arrays.asList(block, metadata, toolClass);
ForgeHooks.toolEffectiveness.remove(key);
}
/**
* Register a block to be harvested by a tool class.
* By default, this sets the block class as effective against that type.
*
* @param block The block to register.
* @param toolClass The tool class to register as able to remove this block.
* You may register the same block multiple times with different tool
* classes, if multiple tool types can be used to harvest this block.
* @param harvestLevel The minimum tool harvest level required to successfully
* harvest the block.
* @see MinecraftForge#setToolClass for details on tool classes.
*/
public static void setBlockHarvestLevel(Block block, String toolClass, int harvestLevel)
{
for (int metadata = 0; metadata < 16; metadata++)
{
List key = Arrays.asList(block, metadata, toolClass);
ForgeHooks.toolHarvestLevels.put(key, harvestLevel);
ForgeHooks.toolEffectiveness.add(key);
}
}
/**
* Returns the block harvest level for a particular tool class.
*
* @param block The block to check.
* @param metadata The metadata for the block subtype.
* @param toolClass The tool class to check as able to remove this block.
* @see MinecraftForge#setToolClass for details on tool classes.
* @return The harvest level or -1 if no mapping exists.
*/
public static int getBlockHarvestLevel(Block block, int metadata, String toolClass)
{
ForgeHooks.initTools();
List key = Arrays.asList(block, metadata, toolClass);
Integer harvestLevel = ForgeHooks.toolHarvestLevels.get(key);
return (harvestLevel == null ? -1 : harvestLevel);
}
/**
* Remove a block effectiveness mapping. Since setBlockHarvestLevel
* makes the tool class effective against the block by default, this can be
* used to remove that mapping. This will force a block to be harvested at
* the same speed regardless of tool quality, while still requiring a given
* harvesting level.
*
* @param block The block to remove effectiveness from.
* @param toolClass The tool class to remove the effectiveness mapping from.
* @see MinecraftForge#setToolClass for details on tool classes.
*/
public static void removeBlockEffectiveness(Block block, String toolClass)
{
for (int metadata = 0; metadata < 16; metadata++)
{
List key = Arrays.asList(block, metadata, toolClass);
ForgeHooks.toolEffectiveness.remove(key);
}
}
/**
* Method invoked by FML before any other mods are loaded.
*/
public static void initialize()
{
System.out.printf("MinecraftForge v%s Initialized\n", ForgeVersion.getVersion());
FMLLog.info("MinecraftForge v%s Initialized", ForgeVersion.getVersion());
Block filler = new Block(0, Material.air)
{
@SideOnly(Side.CLIENT)
@Override
public void registerIcons(IconRegister register){}
};
Block.blocksList[0] = null;
Block.opaqueCubeLookup[0] = false;
Block.lightOpacity[0] = 0;
filler.setUnlocalizedName("ForgeFiller");
for (int x = 256; x < 4096; x++)
{
if (Item.itemsList[x] != null)
{
Block.blocksList[x] = filler;
}
}
boolean[] temp = new boolean[4096];
System.arraycopy(EntityEnderman.carriableBlocks, 0, temp, 0, EntityEnderman.carriableBlocks.length);
EntityEnderman.carriableBlocks = temp;
EVENT_BUS.register(INTERNAL_HANDLER);
OreDictionary.getOreName(0);
//Force these classes to be defined, Should prevent derp error hiding.
new CrashReport("ThisIsFake", new Exception("Not real"));
}
public static String getBrandingVersion()
{
return "Minecraft Forge "+ ForgeVersion.getVersion();
}
}
@@ -0,0 +1,409 @@
/**
* This software is provided under the terms of the Minecraft Forge Public
* License v1.0.
*/
package net.minecraftforge.common;
import java.util.ArrayList;
import net.minecraftforge.common.Property.Type;
public class Property
{
public enum Type
{
STRING,
INTEGER,
BOOLEAN,
DOUBLE;
private static Type[] values = {STRING, INTEGER, BOOLEAN, DOUBLE};
public static Type tryParse(char id)
{
for (int x = 0; x < values.length; x++)
{
if (values[x].getID() == id)
{
return values[x];
}
}
return STRING;
}
public char getID()
{
return name().charAt(0);
}
}
private String name;
private String value;
public String comment;
private String[] values;
private final boolean wasRead;
private final boolean isList;
private final Type type;
private boolean changed = false;
public Property()
{
wasRead = false;
type = null;
isList = false;
}
public Property(String name, String value, Type type)
{
this(name, value, type, false);
}
Property(String name, String value, Type type, boolean read)
{
setName(name);
this.value = value;
this.type = type;
wasRead = read;
isList = false;
}
public Property(String name, String[] values, Type type)
{
this(name, values, type, false);
}
Property(String name, String[] values, Type type, boolean read)
{
setName(name);
this.type = type;
this.values = values;
wasRead = read;
isList = true;
}
/**
* Returns the value in this property as it's raw string.
*
* @return current value
*/
public String getString()
{
return value;
}
/**
* Returns the value in this property as an integer,
* if the value is not a valid integer, it will return -1.
*
* @return The value
*/
public int getInt()
{
return getInt(-1);
}
/**
* Returns the value in this property as an integer,
* if the value is not a valid integer, it will return the
* provided default.
*
* @param _default The default to provide if the current value is not a valid integer
* @return The value
*/
public int getInt(int _default)
{
try
{
return Integer.parseInt(value);
}
catch (NumberFormatException e)
{
return _default;
}
}
/**
* Checks if the current value stored in this property can be converted to an integer.
* @return True if the type of the Property is an Integer
*/
public boolean isIntValue()
{
try
{
Integer.parseInt(value);
return true;
}
catch (NumberFormatException e)
{
return false;
}
}
/**
* Returns the value in this property as a boolean,
* if the value is not a valid boolean, it will return the
* provided default.
*
* @param _default The default to provide
* @return The value as a boolean, or the default
*/
public boolean getBoolean(boolean _default)
{
if (isBooleanValue())
{
return Boolean.parseBoolean(value);
}
else
{
return _default;
}
}
/**
* Checks if the current value held by this property is a valid boolean value.
* @return True if it is a boolean value
*/
public boolean isBooleanValue()
{
return ("true".equals(value.toLowerCase()) || "false".equals(value.toLowerCase()));
}
/**
* Checks if the current value held by this property is a valid double value.
* @return True if the value can be converted to an double
*/
public boolean isDoubleValue()
{
try
{
Double.parseDouble(value);
return true;
}
catch (NumberFormatException e)
{
return false;
}
}
/**
* Returns the value in this property as a double,
* if the value is not a valid double, it will return the
* provided default.
*
* @param _default The default to provide if the current value is not a valid double
* @return The value
*/
public double getDouble(double _default)
{
try
{
return Double.parseDouble(value);
}
catch (NumberFormatException e)
{
return _default;
}
}
public String[] getStringList()
{
return values;
}
/**
* Returns the integer value of all values that can
* be parsed in the list.
*
* @return Array of length 0 if none of the values could be parsed.
*/
public int[] getIntList()
{
ArrayList<Integer> nums = new ArrayList<Integer>();
for (String value : values)
{
try
{
nums.add(Integer.parseInt(value));
}
catch (NumberFormatException e){}
}
int[] primitives = new int[nums.size()];
for (int i = 0; i < nums.size(); i++)
{
primitives[i] = nums.get(i);
}
return primitives;
}
/**
* Checks if all of the current values stored in this property can be converted to an integer.
* @return True if the type of the Property is an Integer List
*/
public boolean isIntList()
{
for (String value : values)
{
try
{
Integer.parseInt(value);
}
catch (NumberFormatException e)
{
return false;
}
}
return true;
}
/**
* Returns the boolean value of all values that can
* be parsed in the list.
*
* @return Array of length 0 if none of the values could be parsed.
*/
public boolean[] getBooleanList()
{
ArrayList<Boolean> tmp = new ArrayList<Boolean>();
for (String value : values)
{
try
{
tmp.add(Boolean.parseBoolean(value));
}
catch (NumberFormatException e){}
}
boolean[] primitives = new boolean[tmp.size()];
for (int i = 0; i < tmp.size(); i++)
{
primitives[i] = tmp.get(i);
}
return primitives;
}
/**
* Checks if all of current values stored in this property can be converted to a boolean.
* @return True if it is a boolean value
*/
public boolean isBooleanList()
{
for (String value : values)
{
if (!"true".equalsIgnoreCase(value) && !"false".equalsIgnoreCase(value))
{
return false;
}
}
return true;
}
/**
* Returns the double value of all values that can
* be parsed in the list.
*
* @return Array of length 0 if none of the values could be parsed.
*/
public double[] getDoubleList()
{
ArrayList<Double> tmp = new ArrayList<Double>();
for (String value : values)
{
try
{
tmp.add(Double.parseDouble(value));
}
catch (NumberFormatException e) {}
}
double[] primitives = new double[tmp.size()];
for (int i = 0; i < tmp.size(); i++)
{
primitives[i] = tmp.get(i);
}
return primitives;
}
/**
* Checks if all of the current values stored in this property can be converted to a double.
* @return True if the type of the Property is a double List
*/
public boolean isDoubleList()
{
for (String value : values)
{
try
{
Double.parseDouble(value);
}
catch (NumberFormatException e)
{
return false;
}
}
return true;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
/**
* Determines if this config value was just created, or if it was read from the config file.
* This is useful for mods who auto-assign there blocks to determine if the ID returned is
* a configured one, or a automatically generated one.
*
* @return True if this property was loaded from the config file with a value
*/
public boolean wasRead()
{
return wasRead;
}
public Type getType()
{
return type;
}
public boolean isList()
{
return isList;
}
public boolean hasChanged(){ return changed; }
void resetChangedState(){ changed = false; }
public void set(String value)
{
this.value = value;
changed = true;
}
public void set(String[] values)
{
this.values = values;
changed = true;
}
public void set(int value){ set(Integer.toString(value)); }
public void set(boolean value){ set(Boolean.toString(value)); }
public void set(double value){ set(Double.toString(value)); }
}
@@ -0,0 +1,408 @@
package net.minecraftforge.common;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.minecraft.block.Block;
import net.minecraft.block.BlockAnvil;
import net.minecraft.block.BlockBed;
import net.minecraft.block.BlockButton;
import net.minecraft.block.BlockChest;
import net.minecraft.block.BlockCocoa;
import net.minecraft.block.BlockComparator;
import net.minecraft.block.BlockDetectorRail;
import net.minecraft.block.BlockDispenser;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.BlockEndPortalFrame;
import net.minecraft.block.BlockEnderChest;
import net.minecraft.block.BlockFenceGate;
import net.minecraft.block.BlockFurnace;
import net.minecraft.block.BlockHopper;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockLever;
import net.minecraft.block.BlockLog;
import net.minecraft.block.BlockMushroomCap;
import net.minecraft.block.BlockPistonBase;
import net.minecraft.block.BlockPistonExtension;
import net.minecraft.block.BlockPumpkin;
import net.minecraft.block.BlockRail;
import net.minecraft.block.BlockRailPowered;
import net.minecraft.block.BlockRedstoneRepeater;
import net.minecraft.block.BlockSkull;
import net.minecraft.block.BlockStairs;
import net.minecraft.block.BlockTorch;
import net.minecraft.block.BlockTrapDoor;
import net.minecraft.block.BlockTripWireSource;
import net.minecraft.block.BlockVine;
import net.minecraft.world.World;
import java.util.HashMap;
import java.util.Map;
import static net.minecraftforge.common.ForgeDirection.*;
public class RotationHelper {
/**
* Some blocks have the same rotation.
* The first of these blocks (sorted by itemID) should be listed as a type.
* Some of the types aren't actual blocks (helper types).
*/
private static enum BlockType {
LOG,
DISPENSER,
BED,
RAIL,
RAIL_POWERED,
RAIL_ASCENDING,
RAIL_CORNER,
TORCH,
STAIR,
CHEST,
SIGNPOST,
DOOR,
LEVER,
BUTTON,
REDSTONE_REPEATER,
TRAPDOOR,
MUSHROOM_CAP,
MUSHROOM_CAP_CORNER,
MUSHROOM_CAP_SIDE,
VINE,
SKULL,
ANVIL
}
private static final ForgeDirection[] UP_DOWN_AXES = new ForgeDirection[] { UP, DOWN };
private static final Map<BlockType, BiMap<Integer, ForgeDirection>> MAPPINGS = new HashMap<BlockType, BiMap<Integer, ForgeDirection>>();
public static ForgeDirection[] getValidVanillaBlockRotations(Block block)
{
return (block instanceof BlockBed || block instanceof BlockPumpkin || block instanceof BlockFenceGate || block instanceof BlockEndPortalFrame || block instanceof BlockTripWireSource || block instanceof BlockCocoa || block instanceof BlockRailPowered || block instanceof BlockDetectorRail || block instanceof BlockStairs || block instanceof BlockChest || block instanceof BlockEnderChest || block instanceof BlockFurnace || block instanceof BlockLadder || block.blockID == Block.signWall.blockID || block.blockID == Block.signPost.blockID || block instanceof BlockDoor || block instanceof BlockRail || block instanceof BlockButton || block instanceof BlockRedstoneRepeater || block instanceof BlockComparator || block instanceof BlockTrapDoor || block instanceof BlockMushroomCap || block instanceof BlockVine || block instanceof BlockSkull || block instanceof BlockAnvil) ? UP_DOWN_AXES : VALID_DIRECTIONS;
}
public static boolean rotateVanillaBlock(Block block, World worldObj, int x, int y, int z, ForgeDirection axis)
{
if (worldObj.isRemote)
{
return false;
}
if (axis == UP || axis == DOWN)
{
if (block instanceof BlockBed || block instanceof BlockPumpkin || block instanceof BlockFenceGate || block instanceof BlockEndPortalFrame || block instanceof BlockTripWireSource || block instanceof BlockCocoa)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.BED);
}
if (block instanceof BlockRail)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.RAIL);
}
if (block instanceof BlockRailPowered || block instanceof BlockDetectorRail)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.RAIL_POWERED);
}
if (block instanceof BlockStairs)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.STAIR);
}
if (block instanceof BlockChest || block instanceof BlockEnderChest || block instanceof BlockFurnace || block instanceof BlockLadder || block.blockID == Block.signWall.blockID)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.CHEST);
}
if (block.blockID == Block.signPost.blockID)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.SIGNPOST);
}
if (block instanceof BlockDoor)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.DOOR);
}
if (block instanceof BlockButton)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.BUTTON);
}
if (block instanceof BlockRedstoneRepeater || block instanceof BlockComparator)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.REDSTONE_REPEATER);
}
if (block instanceof BlockTrapDoor)
{
return rotateBlock(worldObj, x, y, z, axis, 0x3, BlockType.TRAPDOOR);
}
if (block instanceof BlockMushroomCap)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.MUSHROOM_CAP);
}
if (block instanceof BlockVine)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.VINE);
}
if (block instanceof BlockSkull)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.SKULL);
}
if (block instanceof BlockAnvil)
{
return rotateBlock(worldObj, x, y, z, axis, 0x1, BlockType.ANVIL);
}
}
if (block instanceof BlockLog)
{
return rotateBlock(worldObj, x, y, z, axis, 0xC, BlockType.LOG);
}
if (block instanceof BlockDispenser || block instanceof BlockPistonBase || block instanceof BlockPistonExtension || block instanceof BlockHopper)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.DISPENSER);
}
if (block instanceof BlockTorch)
{
return rotateBlock(worldObj, x, y, z, axis, 0xF, BlockType.TORCH);
}
if (block instanceof BlockLever)
{
return rotateBlock(worldObj, x, y, z, axis, 0x7, BlockType.LEVER);
}
return false;
}
private static boolean rotateBlock(World worldObj, int x, int y, int z, ForgeDirection axis, int mask, BlockType blockType)
{
int rotMeta = worldObj.getBlockMetadata(x, y, z);
if (blockType == BlockType.DOOR && (rotMeta & 0x8) == 0x8)
{
return false;
}
int masked = rotMeta & ~mask;
int meta = rotateMetadata(axis, blockType, rotMeta & mask);
if (meta == -1)
{
return false;
}
worldObj.setBlockMetadataWithNotify(x, y, z, meta & mask | masked, 3);
return true;
}
private static int rotateMetadata(ForgeDirection axis, BlockType blockType, int meta)
{
if (blockType == BlockType.RAIL || blockType == BlockType.RAIL_POWERED)
{
if (meta == 0x0 || meta == 0x1)
{
return ~meta & 0x1;
}
if (meta >= 0x2 && meta <= 0x5)
{
blockType = BlockType.RAIL_ASCENDING;
}
if (meta >= 0x6 && meta <= 0x9 && blockType == BlockType.RAIL)
{
blockType = BlockType.RAIL_CORNER;
}
}
if (blockType == BlockType.SIGNPOST)
{
return (axis == UP) ? (meta + 0x4) % 0x10 : (meta + 0xC) % 0x10;
}
if (blockType == BlockType.LEVER && (axis == UP || axis == DOWN))
{
switch (meta)
{
case 0x5:
return 0x6;
case 0x6:
return 0x5;
case 0x7:
return 0x0;
case 0x0:
return 0x7;
}
}
if (blockType == BlockType.MUSHROOM_CAP)
{
if (meta % 0x2 == 0)
{
blockType = BlockType.MUSHROOM_CAP_SIDE;
}
else
{
blockType = BlockType.MUSHROOM_CAP_CORNER;
}
}
if (blockType == BlockType.VINE)
{
return ((meta << 1) | ((meta & 0x8) >> 3));
}
ForgeDirection orientation = metadataToDirection(blockType, meta);
ForgeDirection rotated = orientation.getRotation(axis);
return directionToMetadata(blockType, rotated);
}
private static ForgeDirection metadataToDirection(BlockType blockType, int meta)
{
if (blockType == BlockType.LEVER)
{
if (meta == 0x6)
{
meta = 0x5;
}
else if (meta == 0x0)
{
meta = 0x7;
}
}
if (MAPPINGS.containsKey(blockType))
{
BiMap<Integer, ForgeDirection> biMap = MAPPINGS.get(blockType);
if (biMap.containsKey(meta))
{
return biMap.get(meta);
}
}
if (blockType == BlockType.TORCH)
{
return ForgeDirection.getOrientation(6 - meta);
}
if (blockType == BlockType.STAIR)
{
return ForgeDirection.getOrientation(5 - meta);
}
if (blockType == BlockType.CHEST || blockType == BlockType.DISPENSER || blockType == BlockType.SKULL)
{
return ForgeDirection.getOrientation(meta);
}
if (blockType == BlockType.BUTTON)
{
return ForgeDirection.getOrientation(6 - meta);
}
if (blockType == BlockType.TRAPDOOR)
{
return ForgeDirection.getOrientation(meta + 2).getOpposite();
}
return ForgeDirection.UNKNOWN;
}
private static int directionToMetadata(BlockType blockType, ForgeDirection direction)
{
if ((blockType == BlockType.LOG || blockType == BlockType.ANVIL) && (direction.offsetX + direction.offsetY + direction.offsetZ) < 0)
{
direction = direction.getOpposite();
}
if (MAPPINGS.containsKey(blockType))
{
BiMap<ForgeDirection, Integer> biMap = MAPPINGS.get(blockType).inverse();
if (biMap.containsKey(direction))
{
return biMap.get(direction);
}
}
if (blockType == BlockType.TORCH)
{
if (direction.ordinal() >= 1)
{
return 6 - direction.ordinal();
}
}
if (blockType == BlockType.STAIR)
{
return 5 - direction.ordinal();
}
if (blockType == BlockType.CHEST || blockType == BlockType.DISPENSER || blockType == BlockType.SKULL)
{
return direction.ordinal();
}
if (blockType == BlockType.BUTTON)
{
if (direction.ordinal() >= 2)
{
return 6 - direction.ordinal();
}
}
if (blockType == BlockType.TRAPDOOR)
{
return direction.getOpposite().ordinal() - 2;
}
return -1;
}
static
{
BiMap<Integer, ForgeDirection> biMap;
biMap = HashBiMap.create(3);
biMap.put(0x0, UP);
biMap.put(0x4, EAST);
biMap.put(0x8, SOUTH);
MAPPINGS.put(BlockType.LOG, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x0, SOUTH);
biMap.put(0x1, WEST);
biMap.put(0x2, NORTH);
biMap.put(0x3, EAST);
MAPPINGS.put(BlockType.BED, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x2, EAST);
biMap.put(0x3, WEST);
biMap.put(0x4, NORTH);
biMap.put(0x5, SOUTH);
MAPPINGS.put(BlockType.RAIL_ASCENDING, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x6, WEST);
biMap.put(0x7, NORTH);
biMap.put(0x8, EAST);
biMap.put(0x9, SOUTH);
MAPPINGS.put(BlockType.RAIL_CORNER, biMap);
biMap = HashBiMap.create(6);
biMap.put(0x1, EAST);
biMap.put(0x2, WEST);
biMap.put(0x3, SOUTH);
biMap.put(0x4, NORTH);
biMap.put(0x5, UP);
biMap.put(0x7, DOWN);
MAPPINGS.put(BlockType.LEVER, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x0, WEST);
biMap.put(0x1, NORTH);
biMap.put(0x2, EAST);
biMap.put(0x3, SOUTH);
MAPPINGS.put(BlockType.DOOR, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x0, NORTH);
biMap.put(0x1, EAST);
biMap.put(0x2, SOUTH);
biMap.put(0x3, WEST);
MAPPINGS.put(BlockType.REDSTONE_REPEATER, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x1, EAST);
biMap.put(0x3, SOUTH);
biMap.put(0x7, NORTH);
biMap.put(0x9, WEST);
MAPPINGS.put(BlockType.MUSHROOM_CAP_CORNER, biMap);
biMap = HashBiMap.create(4);
biMap.put(0x2, NORTH);
biMap.put(0x4, WEST);
biMap.put(0x6, EAST);
biMap.put(0x8, SOUTH);
MAPPINGS.put(BlockType.MUSHROOM_CAP_SIDE, biMap);
biMap = HashBiMap.create(2);
biMap.put(0x0, SOUTH);
biMap.put(0x1, EAST);
MAPPINGS.put(BlockType.ANVIL, biMap);
}
}
Loaded 100 of 1375 files, more files were not shown because too many files have changed in this diff. Show more