1 Commits
1.16 ... 1.12

Author SHA1 Message Date
Christian Knaapen
c16a924bb9 Added circle, cylinder and sphere buildmodes. Refactored buildmodes to use hierarchy classes, much less code duplication. Added support for multiple options per build mode.
Added alternative placement key (ctrl) that toggles between first two actions of first option.
Fixed crash when placing ladders.
2019-12-23 12:39:08 +01:00
135 changed files with 7893 additions and 9849 deletions

59
.gitignore vendored
View File

@@ -1,26 +1,43 @@
# eclipse ## Based on GitHub's Eclipse .gitignore
bin
*.launch
.settings
.metadata
.classpath
.project
# idea classes/
out run/
*.ipr .gradle/
*.iws build/
gradle-app.setting
## IntelliJ IDEA
.idea/
*.iml *.iml
.idea *.iws
*.ipr
# gradle ## Eclipse
build
.gradle
# other eclipse/
eclipse *.pydevproject
run .project
logs/* .metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# Files from Forge MDK # External tool builders
forge*changelog.txt .externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath

View File

@@ -1,520 +0,0 @@
Unless noted below, Minecraft Forge, Forge Mod Loader, and all
parts herein are 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.
Homepage: http://minecraftforge.net/
https://github.com/MinecraftForge/MinecraftForge
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.
=== 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 (src/main/java/net/minecraftforge/fml/common/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 (src/main/java/net/minecraftforge/common/asm/ and subdirectories)
under any alternative open source license as classified by the OSI (http://opensource.org/licenses)
=========================================================================
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.
=========================================================================
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

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
This is the version for Minecraft 1.12.
1.13 can be found here: https://bitbucket.org/Requios/effortless-building-1.13/src/master/

View File

@@ -1,53 +0,0 @@
-------------------------------------------
Source installation information for modders
-------------------------------------------
This code follows the Minecraft Forge installation methodology. It will apply
some small patches to the vanilla MCP source code, giving you and it access
to some of the data and functions you need to build a successful mod.
Note also that the patches are built against "unrenamed" MCP source code (aka
srgnames) - this means that you will not be able to read them directly against
normal code.
Source pack installation information:
Standalone source installation
==============================
See the Forge Documentation online for more detailed instructions:
http://mcforge.readthedocs.io/en/latest/gettingstarted/
Step 1: Open your command-line and browse to the folder where you extracted the zip file.
Step 2: You're left with a choice.
If you prefer to use Eclipse:
1. Run the following command: "gradlew genEclipseRuns" (./gradlew genEclipseRuns if you are on Mac/Linux)
2. Open Eclipse, Import > Existing Gradle Project > Select Folder
or run "gradlew eclipse" to generate the project.
(Current Issue)
4. Open Project > Run/Debug Settings > Edit runClient and runServer > Environment
5. Edit MOD_CLASSES to show [modid]%%[Path]; 2 times rather then the generated 4.
If you prefer to use IntelliJ:
1. Open IDEA, and import project.
2. Select your build.gradle file and have it import.
3. Run the following command: "gradlew genIntellijRuns" (./gradlew genIntellijRuns if you are on Mac/Linux)
4. Refresh the Gradle Project in IDEA if required.
If at any point you are missing libraries in your IDE, or you've run into problems you can run "gradlew --refresh-dependencies" to refresh the local cache. "gradlew clean" to reset everything {this does not affect your code} and then start the processs again.
Should it still not work,
Refer to #ForgeGradle on EsperNet for more information about the gradle environment.
or the Forge Project Discord discord.gg/UvedJ9m
Forge source installation
=========================
MinecraftForge ships with this code and installs it as part of the forge
installation process, no further action is required on your part.
LexManos' Install Video
=======================
https://www.youtube.com/watch?v=8VEdtQLuLO0&feature=youtu.be
For more details update more often refer to the Forge Forums:
http://www.minecraftforge.net/forum/index.php/topic,14048.0.html

View File

@@ -1,146 +1,82 @@
buildscript { buildscript {
repositories { repositories {
maven { url = 'https://files.minecraftforge.net/maven' }
jcenter() jcenter()
mavenCentral() maven { url = "http://files.minecraftforge.net/maven" }
} }
dependencies { dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1+', changing: true classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
} }
} }
apply plugin: 'net.minecraftforge.gradle' apply plugin: 'net.minecraftforge.gradle.forge'
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup. //Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
version = '1.16.3-2.32'
group = 'nl.requios.effortlessbuilding' // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = 'effortlessbuilding'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly. version = "1.12.2-2.16"
group = "nl.requios.effortlessbuilding" // http://maven.apache.org/guides/mini/guide-naming-conventions.html
archivesBaseName = "effortlessbuilding"
sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
compileJava {
sourceCompatibility = targetCompatibility = '1.8'
}
minecraft { minecraft {
// The mappings can be changed at any time, and must be in the following format. version = "1.12.2-14.23.5.2825"
// snapshot_YYYYMMDD Snapshot are built nightly. runDir = "run"
// stable_# Stables are built at the discretion of the MCP team.
// the mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD snapshot are built nightly.
// stable_# stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not always work. // Use non-default mappings at your own risk. they may not always work.
// Simply re-run your setup task after changing the mappings to update your workspace. // simply re-run your setup task after changing the mappings to update your workspace.
mappings channel: 'official', version: '1.16.5' mappings = "stable_39"
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
}
// Default run configurations. repositories {
// These can be tweaked, removed, or duplicated as needed. flatDir { dirs 'libs' }
runs {
client {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment (SCAN,REGISTRIES,REGISTRYDUMP)
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
mods {
effortlessbuilding {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment (SCAN,REGISTRIES,REGISTRYDUMP)
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
mods {
effortlessbuilding {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment (SCAN,REGISTRIES,REGISTRYDUMP)
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
args '--mod', 'effortlessbuilding', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
mods {
effortlessbuilding {
source sourceSets.main
}
}
}
}
} }
dependencies { dependencies {
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed // you may put jars on which you depend on in ./libs
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. // or you may define them like so..
// The userdev artifact is a special name and will get all sorts of transformations applied to it. //compile "some.group:artifact:version:classifier"
minecraft 'net.minecraftforge:forge:1.16.3-34.0.9' //compile "some.group:artifact:version"
// You may put jars on which you depend on in ./libs or you may define them like so.. // real examples
// compile "some.group:artifact:version:classifier" //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
// compile "some.group:artifact:version" //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// Real examples // the 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
// compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env //provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime. // the deobf configurations: 'deobfCompile' and 'deobfProvided' are the same as the normal compile and provided,
// provided 'com.mod-buildcraft:buildcraft:6.0.8:dev' // except that these dependencies get remapped to your current MCP mappings
//deobfCompile 'com.mod-buildcraft:buildcraft:6.0.8:dev'
//deobfProvided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
provided 'mod.chiselsandbits:chiselsandbits:14.30'
// These dependencies get remapped to your current MCP mappings // for more info...
// deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// For more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html // http://www.gradle.org/docs/current/userguide/dependency_management.html
} }
// Example for how to get properties into the manifest for reading by the runtime.. processResources {
jar { // this will ensure that this task is redone when the versions change.
manifest { inputs.property "version", project.version
attributes([ inputs.property "mcversion", project.minecraft.version
"Specification-Title": "effortlessbuilding",
"Specification-Vendor": "requios", // replace stuff in mcmod.info, nothing else
"Specification-Version": "1", // We are version 1 of ourselves from(sourceSets.main.resources.srcDirs) {
"Implementation-Title": project.name, include 'mcmod.info'
"Implementation-Version": "${version}",
"Implementation-Vendor" :"requios", // replace version and mcversion
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ") expand 'version':project.version, 'mcversion':project.minecraft.version
]) }
}
} // copy everything else except the mcmod.info
from(sourceSets.main.resources.srcDirs) {
// Example configuration to allow publishing using the maven-publish task exclude 'mcmod.info'
// This is the preferred method to reobfuscate your jar file
jar.finalizedBy('reobfJar')
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
//publish.dependsOn('reobfJar')
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file:///${project.projectDir}/mcmodsrepo"
}
} }
} }

View File

@@ -1,4 +0,0 @@
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
# This is required to provide enough memory for the Minecraft decompilation process.
org.gradle.jvmargs=-Xmx3G
org.gradle.daemon=false

Binary file not shown.

View File

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

71
gradlew vendored
View File

@@ -1,20 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## ##
@@ -44,7 +28,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"
@@ -72,7 +56,7 @@ case "`uname`" in
Darwin* ) Darwin* )
darwin=true darwin=true
;; ;;
MSYS* | MINGW* ) MINGW* )
msys=true msys=true
;; ;;
NONSTOP* ) NONSTOP* )
@@ -82,7 +66,6 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -126,11 +109,10 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin or MSYS, switch paths to Windows format before running java # For Cygwin, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath # We build the pattern for arguments to be converted via cygpath
@@ -156,28 +138,35 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else else
eval `echo args$i`="\"$arg\"" eval `echo args$i`="\"$arg\""
fi fi
i=`expr $i + 1` i=$((i+1))
done done
case $i in case $i in
0) set -- ;; (0) set -- ;;
1) set -- "$args0" ;; (1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;; (2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;; (3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
ARGV=("$@") # Escape application args
eval set -- $DEFAULT_JVM_OPTS save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
IFS=$' # Collect all arguments for the java command, following the shell quoting and substitution rules
' read -rd '' -a JAVA_OPTS_ARR <<< "$(echo $JAVA_OPTS | xargs -n1)" eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
IFS=$'
' read -rd '' -a GRADLE_OPTS_ARR <<< "$(echo $GRADLE_OPTS | xargs -n1)"
exec "$JAVACMD" "$@" "${JAVA_OPTS_ARR[@]}" "${GRADLE_OPTS_ARR[@]}" "-Dorg.gradle.appname=$APP_BASE_NAME" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "${ARGV[@]}" # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

43
gradlew.bat vendored
View File

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

Binary file not shown.

View File

@@ -1,134 +1,89 @@
package nl.requios.effortlessbuilding; package nl.requios.effortlessbuilding;
import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.common.config.Config;
import static net.minecraftforge.common.config.Config.*;
@Config(modid = EffortlessBuilding.MODID, name = "EffortlessBuilding", type = Type.INSTANCE, category = "")
public class BuildConfig { public class BuildConfig {
private static final ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder(); public static Reach reach = new Reach();
public static final Reach reach = new Reach(builder); public static SurvivalBalancers survivalBalancers = new SurvivalBalancers();
public static final SurvivalBalancers survivalBalancers = new SurvivalBalancers(builder); public static Visuals visuals = new Visuals();
public static final Visuals visuals = new Visuals(builder);
public static final ForgeConfigSpec spec = builder.build();
public static class Reach { public static class Reach {
public final ForgeConfigSpec.ConfigValue<Boolean> enableReachUpgrades; @Comment({"Reach: how far away the player can place blocks using mirror/array etc.",
public final ForgeConfigSpec.ConfigValue<Integer> maxReachCreative; "Enable the crafting of reach upgrades to increase reach.",
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel0; "If disabled, reach is set to level 3 for survival players."})
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel1; public boolean enableReachUpgrades = true;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel2;
public final ForgeConfigSpec.ConfigValue<Integer> maxReachLevel3;
public Reach(ForgeConfigSpec.Builder builder) { @Comment({"Maximum reach in creative",
builder.push("Reach"); "Keep in mind that chunks need to be loaded to be able to place blocks inside."})
enableReachUpgrades = builder public int maxReachCreative = 200;
.comment("Reach: how far away the player can place blocks using mirror/array etc.",
"Enable the crafting of reach upgrades to increase reach.",
"If disabled, reach is set to level 3 for survival players.")
.define("enableReachUpgrades", true);
maxReachCreative = builder @Comment({"Maximum reach in survival without upgrades",
.comment("Maximum reach in creative", "Reach upgrades are craftable consumables that permanently increase reach.",
"Keep in mind that chunks need to be loaded to be able to place blocks inside.") "Set to 0 to disable Effortless Building until the player has consumed a reach upgrade."})
.define("maxReachCreative", 200); public int maxReachLevel0 = 20;
maxReachLevel0 = builder @Comment("Maximum reach in survival with one upgrade")
.comment("Maximum reach in survival without upgrades", public int maxReachLevel1 = 50;
"Reach upgrades are craftable consumables that permanently increase reach.",
"Set to 0 to disable Effortless Building until the player has consumed a reach upgrade.")
.define("maxReachLevel0", 20);
maxReachLevel1 = builder @Comment("Maximum reach in survival with two upgrades")
.comment("Maximum reach in survival with one upgrade") public int maxReachLevel2 = 100;
.define("maxReachLevel1", 50);
maxReachLevel2 = builder @Comment("Maximum reach in survival with three upgrades")
.comment("Maximum reach in survival with two upgrades") public int maxReachLevel3 = 200;
.define("maxReachLevel2", 100); }
maxReachLevel3 = builder public static class SurvivalBalancers {
.comment("Maximum reach in survival with three upgrades") @Comment({"Allows a survival player to break blocks that are far away, in addition to placing blocks.",
.define("maxReachLevel3", 200); "Note: this allows insta-breaking of blocks in survival."})
public boolean breakFar = false;
builder.pop(); @Comment({"Increases the time to mine a block when breaking multiple at once.",
} "Mining time depends on how many blocks, what type of blocks, and the percentage below.",
} "Example: breaking 1 dirt + 1 obsidian takes the time of breaking 1 dirt + 1 obsidian."})
public boolean increasedMiningTime = true;
public static class SurvivalBalancers { @Comment({"How much the mining time of each additional block counts towards an increased mining time.",
public final ForgeConfigSpec.ConfigValue<Boolean> breakFar; "A percentage between 0% and 100%, where 0% is the same as disabling it,",
public final ForgeConfigSpec.ConfigValue<Boolean> increasedMiningTime; "and 100% takes as much time as breaking each block individually.",
public final ForgeConfigSpec.ConfigValue<Integer> miningTimePercentage; "The block in front of you always counts as 100%."})
public final ForgeConfigSpec.ConfigValue<Integer> quickReplaceMiningLevel; @RangeInt(min = 0, max = 200)
public final ForgeConfigSpec.ConfigValue<Integer> undoStackSize; public int miningTimePercentage = 50;
public SurvivalBalancers(ForgeConfigSpec.Builder builder) { @Comment({"Determines what blocks can be replaced in survival.",
builder.push("SurvivalBalancers"); "-1: only blocks that can be harvested by hand (default)",
"0: blocks that can be harvested with wooden or gold tools",
"1: blocks that can be harvested with stone tools",
"2: blocks that can be harvested with iron tools",
"3: blocks that can be harvested with diamond tools",
})
@RangeInt(min = -1, max = 3)
public int quickReplaceMiningLevel = -1;
breakFar = builder @Comment({"How many placements are remembered for the undo functionality."})
.comment("Allows a survival player to break blocks that are far away, in addition to placing blocks.", @RequiresMcRestart
"Note: this allows insta-breaking of blocks in survival.") public int undoStackSize = 10;
.define("breakFar", false); }
increasedMiningTime = builder public static class Visuals {
.comment("Increases the time to mine a block when breaking multiple at once.", @Comment({"Show a block preview if you have a block in hand on build mode NORMAL"})
"Mining time depends on how many blocks, what type of blocks, and the percentage below.", public boolean alwaysShowBlockPreview = false;
"Example: breaking 1 dirt + 1 obsidian takes the time of breaking 1 dirt + 1 obsidian.")
.define("increasedMiningTime", true);
miningTimePercentage = builder @Comment({"How long the dissolve effect takes when placing blocks.",
.comment("How much the mining time of each additional block counts towards an increased mining time.", "Default between 30 and 60 ticks, you can multiply that here.",
"A percentage between 0% and 100%, where 0% is the same as disabling it,", "Recommended values:",
"and 100% takes as much time as breaking each block individually.", "Snappy: 0.7",
"The block in front of you always counts as 100%.") "Relaxing: 1.5"})
.defineInRange("miningTimePercentage", 50, 0, 200); public double dissolveTimeMultiplier = 1.0;
quickReplaceMiningLevel = builder @Comment({"Switch to using the simple performance shader when placing more than this many blocks."})
.comment("Determines what blocks can be replaced in survival.", public int shaderTreshold = 1500;
"-1: only blocks that can be harvested by hand (default)",
"0: blocks that can be harvested with wooden or gold tools",
"1: blocks that can be harvested with stone tools",
"2: blocks that can be harvested with iron tools",
"3: blocks that can be harvested with diamond tools")
.defineInRange("quickReplaceMiningLevel", -1, -1, 3);
undoStackSize = builder @Comment({"Use fancy shaders while placing blocks"})
.comment("How many placements are remembered for the undo functionality.") public boolean useShaders = true;
.worldRestart()
.define("undoStackSize", 10);
builder.pop(); }
}
}
public static class Visuals {
public final ForgeConfigSpec.ConfigValue<Boolean> alwaysShowBlockPreview;
public final ForgeConfigSpec.ConfigValue<Double> dissolveTimeMultiplier;
public final ForgeConfigSpec.ConfigValue<Integer> shaderTreshold;
public final ForgeConfigSpec.ConfigValue<Boolean> useShaders;
public Visuals(ForgeConfigSpec.Builder builder) {
builder.push("Visuals");
alwaysShowBlockPreview = builder
.comment("Show a block preview if you have a block in hand even in the 'Normal' build mode")
.define("alwaysShowBlockPreview", false);
dissolveTimeMultiplier = builder
.comment("How long the dissolve effect takes when placing blocks.",
"Default between 30 and 60 ticks, you can multiply that here.",
"Recommended values:",
"Snappy: 0.7",
"Relaxing: 1.5")
.define("dissolveTimeMultiplier", 1.0);
shaderTreshold = builder
.comment("Switch to using the simple performance shader when placing more than this many blocks.")
.define("shaderTreshold", 1500);
useShaders = builder
.comment("Use fancy shaders while placing blocks")
.define("useShaders", true);
builder.pop();
}
}
} }

View File

@@ -1,115 +1,150 @@
package nl.requios.effortlessbuilding; package nl.requios.effortlessbuilding;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.block.Block;
import net.minecraft.inventory.container.Container; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.common.config.Config;
import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.common.config.ConfigManager;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.network.IContainerFactory; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.capability.ModeCapabilityManager; import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.command.CommandReach;
import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagContainer; import nl.requios.effortlessbuilding.gui.RandomizerBagGuiHandler;
import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagContainer; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.gui.RandomizerBagContainer; import nl.requios.effortlessbuilding.item.ItemReachUpgrade1;
import nl.requios.effortlessbuilding.item.*; import nl.requios.effortlessbuilding.item.ItemReachUpgrade2;
import nl.requios.effortlessbuilding.network.PacketHandler; import nl.requios.effortlessbuilding.item.ItemReachUpgrade3;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.network.*;
import nl.requios.effortlessbuilding.proxy.IProxy; import nl.requios.effortlessbuilding.proxy.IProxy;
import nl.requios.effortlessbuilding.proxy.ServerProxy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
// The value here should match an entry in the META-INF/mods.toml file @Mod(modid = EffortlessBuilding.MODID, name = EffortlessBuilding.NAME, version = EffortlessBuilding.VERSION)
@Mod(EffortlessBuilding.MODID) @Mod.EventBusSubscriber
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) public class EffortlessBuilding
public class EffortlessBuilding { {
public static final String MODID = "effortlessbuilding"; public static final String MODID = "effortlessbuilding";
public static final Logger logger = LogManager.getLogger(); public static final String NAME = "Effortless Building";
public static final String VERSION = "1.12.2-2.16";
public static EffortlessBuilding instance; @Mod.Instance(EffortlessBuilding.MODID)
public static IProxy proxy = DistExecutor.runForDist(() -> ClientProxy::new, () -> ServerProxy::new); public static EffortlessBuilding instance;
//Registration public static Logger logger;
private static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID);
private static final DeferredRegister<ContainerType<?>> CONTAINERS = DeferredRegister.create(ForgeRegistries.CONTAINERS, EffortlessBuilding.MODID);
public static final RegistryObject<Item> RANDOMIZER_BAG_ITEM = ITEMS.register("randomizer_bag", RandomizerBagItem::new); @SidedProxy(
public static final RegistryObject<Item> GOLDEN_RANDOMIZER_BAG_ITEM = ITEMS.register("golden_randomizer_bag", GoldenRandomizerBagItem::new); clientSide="nl.requios.effortlessbuilding.proxy.ClientProxy",
public static final RegistryObject<Item> DIAMOND_RANDOMIZER_BAG_ITEM = ITEMS.register("diamond_randomizer_bag", DiamondRandomizerBagItem::new); serverSide="nl.requios.effortlessbuilding.proxy.ServerProxy"
public static final RegistryObject<Item> REACH_UPGRADE_1_ITEM = ITEMS.register("reach_upgrade1", ReachUpgrade1Item::new); )
public static final RegistryObject<Item> REACH_UPGRADE_2_ITEM = ITEMS.register("reach_upgrade2", ReachUpgrade2Item::new); public static IProxy proxy;
public static final RegistryObject<Item> REACH_UPGRADE_3_ITEM = ITEMS.register("reach_upgrade3", ReachUpgrade3Item::new);
public static final RegistryObject<ContainerType<RandomizerBagContainer>> RANDOMIZER_BAG_CONTAINER = CONTAINERS.register("randomizer_bag", () -> registerContainer(RandomizerBagContainer::new)); public static final SimpleNetworkWrapper packetHandler = NetworkRegistry.INSTANCE.newSimpleChannel(EffortlessBuilding.MODID);
public static final RegistryObject<ContainerType<GoldenRandomizerBagContainer>> GOLDEN_RANDOMIZER_BAG_CONTAINER = CONTAINERS.register("golden_randomizer_bag", () -> registerContainer(GoldenRandomizerBagContainer::new));
public static final RegistryObject<ContainerType<DiamondRandomizerBagContainer>> DIAMOND_RANDOMIZER_BAG_CONTAINER = CONTAINERS.register("diamond_randomizer_bag", () -> registerContainer(DiamondRandomizerBagContainer::new));
public EffortlessBuilding() { public static final ItemRandomizerBag ITEM_RANDOMIZER_BAG = new ItemRandomizerBag();
instance = this; public static final ItemReachUpgrade1 ITEM_REACH_UPGRADE_1 = new ItemReachUpgrade1();
public static final ItemReachUpgrade2 ITEM_REACH_UPGRADE_2 = new ItemReachUpgrade2();
public static final ItemReachUpgrade3 ITEM_REACH_UPGRADE_3 = new ItemReachUpgrade3();
// Register ourselves for server and other game events we are interested in public static final Block[] BLOCKS = {
FMLJavaModLoadingContext.get().getModEventBus().register(this); };
ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus()); public static final Item[] ITEMS = {
CONTAINERS.register(FMLJavaModLoadingContext.get().getModEventBus()); ITEM_RANDOMIZER_BAG,
ITEM_REACH_UPGRADE_1,
ITEM_REACH_UPGRADE_2,
ITEM_REACH_UPGRADE_3
};
//Register config public static final int RANDOMIZER_BAG_GUI = 0;
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, BuildConfig.spec);
}
public static <T extends Container> ContainerType<T> registerContainer(IContainerFactory<T> fact){ @EventHandler
ContainerType<T> type = new ContainerType<T>(fact); // preInit "Run before anything else. Read your config, create blocks, items, etc, and register them with the GameRegistry."
return type; public void preInit(FMLPreInitializationEvent event)
} {
logger = event.getModLog();
public static void log(String msg) { CapabilityManager.INSTANCE.register(ModifierCapabilityManager.IModifierCapability.class, new ModifierCapabilityManager.Storage(), ModifierCapabilityManager.ModifierCapability.class);
logger.info(msg); CapabilityManager.INSTANCE.register(ModeCapabilityManager.IModeCapability.class, new ModeCapabilityManager.Storage(), ModeCapabilityManager.ModeCapability.class);
}
public static void log(PlayerEntity player, String msg) { EffortlessBuilding.packetHandler.registerMessage(ModifierSettingsMessage.MessageHandler.class, ModifierSettingsMessage.class, 0, Side.SERVER);
log(player, msg, false); EffortlessBuilding.packetHandler.registerMessage(ModifierSettingsMessage.MessageHandler.class, ModifierSettingsMessage.class, 0, Side.CLIENT);
}
public static void log(PlayerEntity player, String msg, boolean actionBar) { EffortlessBuilding.packetHandler.registerMessage(ModeSettingsMessage.MessageHandler.class, ModeSettingsMessage.class, 1, Side.SERVER);
player.displayClientMessage(new StringTextComponent(msg), actionBar); EffortlessBuilding.packetHandler.registerMessage(ModeSettingsMessage.MessageHandler.class, ModeSettingsMessage.class, 1, Side.CLIENT);
}
//Log with translation supported, call either on client or server (which then sends a message) EffortlessBuilding.packetHandler.registerMessage(ModeActionMessage.MessageHandler.class, ModeActionMessage.class, 2, Side.SERVER);
public static void logTranslate(PlayerEntity player, String prefix, String translationKey, String suffix, boolean actionBar) { EffortlessBuilding.packetHandler.registerMessage(ModeActionMessage.MessageHandler.class, ModeActionMessage.class, 2, Side.CLIENT);
proxy.logTranslate(player, prefix, translationKey, suffix, actionBar);
}
@SubscribeEvent EffortlessBuilding.packetHandler.registerMessage(BlockPlacedMessage.MessageHandler.class, BlockPlacedMessage.class, 3, Side.SERVER);
public void setup(final FMLCommonSetupEvent event) { EffortlessBuilding.packetHandler.registerMessage(BlockPlacedMessage.MessageHandler.class, BlockPlacedMessage.class, 3, Side.CLIENT);
CapabilityManager.INSTANCE.register(ModifierCapabilityManager.IModifierCapability.class, new ModifierCapabilityManager.Storage(), ModifierCapabilityManager.ModifierCapability::new);
CapabilityManager.INSTANCE.register(ModeCapabilityManager.IModeCapability.class, new ModeCapabilityManager.Storage(), ModeCapabilityManager.ModeCapability::new);
PacketHandler.register(); EffortlessBuilding.packetHandler.registerMessage(BlockBrokenMessage.MessageHandler.class, BlockBrokenMessage.class, 4, Side.SERVER);
EffortlessBuilding.packetHandler.registerMessage(BlockBrokenMessage.MessageHandler.class, BlockBrokenMessage.class, 4, Side.CLIENT);
//TODO 1.13 config EffortlessBuilding.packetHandler.registerMessage(CancelModeMessage.MessageHandler.class, CancelModeMessage.class, 5, Side.SERVER);
// ConfigManager.sync(MODID, Config.Type.INSTANCE); EffortlessBuilding.packetHandler.registerMessage(CancelModeMessage.MessageHandler.class, CancelModeMessage.class, 5, Side.CLIENT);
proxy.setup(event); EffortlessBuilding.packetHandler.registerMessage(RequestLookAtMessage.MessageHandler.class, RequestLookAtMessage.class, 6, Side.SERVER);
EffortlessBuilding.packetHandler.registerMessage(RequestLookAtMessage.MessageHandler.class, RequestLookAtMessage.class, 6, Side.CLIENT);
CompatHelper.setup(); EffortlessBuilding.packetHandler.registerMessage(AddUndoMessage.MessageHandler.class, AddUndoMessage.class, 7, Side.SERVER);
} EffortlessBuilding.packetHandler.registerMessage(AddUndoMessage.MessageHandler.class, AddUndoMessage.class, 7, Side.CLIENT);
@SubscribeEvent EffortlessBuilding.packetHandler.registerMessage(ClearUndoMessage.MessageHandler.class, ClearUndoMessage.class, 8, Side.SERVER);
public void clientSetup(final FMLClientSetupEvent event) { EffortlessBuilding.packetHandler.registerMessage(ClearUndoMessage.MessageHandler.class, ClearUndoMessage.class, 8, Side.CLIENT);
proxy.clientSetup(event); proxy.preInit(event);
} }
@EventHandler
// Do your mod setup. Build whatever data structures you care about.
// Register network handlers
public void init(FMLInitializationEvent event)
{
ConfigManager.sync(MODID, Config.Type.INSTANCE);
NetworkRegistry.INSTANCE.registerGuiHandler(EffortlessBuilding.instance, new RandomizerBagGuiHandler());
proxy.init(event);
}
@EventHandler
// postInit "Handle interaction with other mods, complete your setup based on this."
public void postInit(FMLPostInitializationEvent event)
{
proxy.postInit(event);
CompatHelper.postInit();
}
@EventHandler
public void serverStarting(FMLServerStartingEvent event)
{
event.registerServerCommand(new CommandReach());
proxy.serverStarting(event);
}
public static void log(String msg){
logger.info(msg);
}
public static void log(EntityPlayer player, String msg){
log(player, msg, false);
}
public static void log(EntityPlayer player, String msg, boolean actionBar){
player.sendStatusMessage(new TextComponentString(msg), actionBar);
}
} }

View File

@@ -1,22 +1,29 @@
package nl.requios.effortlessbuilding; package nl.requios.effortlessbuilding;
import net.minecraft.block.BlockState; import net.minecraft.block.Block;
import net.minecraft.block.Blocks; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.common.config.Config;
import net.minecraftforge.common.config.ConfigManager;
import net.minecraftforge.event.AttachCapabilitiesEvent; import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.BlockSet;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
@@ -25,184 +32,175 @@ import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.network.AddUndoMessage; import nl.requios.effortlessbuilding.network.AddUndoMessage;
import nl.requios.effortlessbuilding.network.BlockBrokenMessage;
import nl.requios.effortlessbuilding.network.ClearUndoMessage; import nl.requios.effortlessbuilding.network.ClearUndoMessage;
import nl.requios.effortlessbuilding.network.PacketHandler;
import nl.requios.effortlessbuilding.network.RequestLookAtMessage; import nl.requios.effortlessbuilding.network.RequestLookAtMessage;
import scala.actors.threadpool.Arrays;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static net.minecraftforge.fml.common.gameevent.PlayerEvent.*;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class EventHandler { public class EventHandler
{
@SubscribeEvent @SubscribeEvent
public static void attachCapabilities(AttachCapabilitiesEvent<Entity> event) { public static void registerBlocks(RegistryEvent.Register<Block> event)
if (event.getObject() instanceof FakePlayer) return; {
if (event.getObject() instanceof PlayerEntity) { event.getRegistry().registerAll(EffortlessBuilding.BLOCKS);
event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "build_modifier"), new ModifierCapabilityManager.Provider()); }
event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "build_mode"), new ModeCapabilityManager.Provider());
}
}
@SubscribeEvent @SubscribeEvent
public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) { public static void registerItems(RegistryEvent.Register<Item> event)
if (event.getWorld().isClientSide()) return; {
event.getRegistry().registerAll(EffortlessBuilding.ITEMS);
if (!(event.getEntity() instanceof PlayerEntity)) return; for (Block block : EffortlessBuilding.BLOCKS)
{
event.getRegistry().register(new ItemBlock(block).setRegistryName(block.getRegistryName()));
}
}
if (event.getEntity() instanceof FakePlayer) return; @SubscribeEvent
public static void attachCapabilities(AttachCapabilitiesEvent<Entity> event) {
if (event.getObject() instanceof EntityPlayer) {
event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "BuildModifier"), new ModifierCapabilityManager.Provider());
event.addCapability(new ResourceLocation(EffortlessBuilding.MODID, "BuildMode"), new ModeCapabilityManager.Provider());
}
}
//Cancel event if necessary @SubscribeEvent
ServerPlayerEntity player = ((ServerPlayerEntity) event.getEntity()); public static void onConfigChangedEvent(ConfigChangedEvent.OnConfigChangedEvent event)
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); {
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); if (event.getModID().equals(EffortlessBuilding.MODID))
{
ConfigManager.sync(EffortlessBuilding.MODID, Config.Type.INSTANCE);
}
}
if (buildMode != BuildModes.BuildModeEnum.NORMAL) { // @SubscribeEvent
event.setCanceled(true); // public static void onServerTick(TickEvent.ServerTickEvent event) {
} else if (modifierSettings.doQuickReplace()) {
//Cancel event and send message if QuickReplace
event.setCanceled(true);
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new RequestLookAtMessage(true));
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
} else {
//NORMAL mode, let vanilla handle block placing
//But modifiers should still work
//Send message to client, which sends message back with raytrace info
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new RequestLookAtMessage(false));
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()));
}
// Stat<ResourceLocation> blocksPlacedStat = StatList.CUSTOM.get(new ResourceLocation(EffortlessBuilding.MODID, "blocks_placed"));
// player.getStats().increment(player, blocksPlacedStat, 1);
// //
// System.out.println(player.getStats().getValue(blocksPlacedStat)); // }
}
@SubscribeEvent @SubscribeEvent
public static void onBlockBroken(BlockEvent.BreakEvent event) { //Only called serverside (except with lilypads...)
if (event.getWorld().isClientSide()) return; public static void onBlockPlaced(BlockEvent.PlaceEvent event) {
if (event.getWorld().isRemote) return;
if (event.getPlayer() instanceof FakePlayer) return; //Cancel event if necessary
EntityPlayer player = event.getPlayer();
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
//Cancel event if necessary if (buildMode != BuildModes.BuildModeEnum.NORMAL) {
//If cant break far then dont cancel event ever event.setCanceled(true);
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(event.getPlayer()).getBuildMode(); } else if (modifierSettings.doQuickReplace()) {
if (buildMode != BuildModes.BuildModeEnum.NORMAL && ReachHelper.canBreakFar(event.getPlayer())) { //Cancel event and send message if QuickReplace
event.setCanceled(true); event.setCanceled(true);
} else { EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(true), (EntityPlayerMP) player);
//NORMAL mode, let vanilla handle block breaking EffortlessBuilding.packetHandler.sendTo(new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()), (EntityPlayerMP) player);
//But modifiers and QuickReplace should still work } else {
//Dont break the original block yourself, otherwise Tinkers Hammer and Veinminer won't work //NORMAL mode, let vanilla handle block placing
BuildModes.onBlockBroken(event.getPlayer(), event.getPos(), false); //But modifiers should still work
//Add to undo stack in client //Send message to client, which sends message back with raytrace info
if (event.getPlayer() instanceof ServerPlayerEntity && event.getState() != null && event.getPos() != null) { EffortlessBuilding.packetHandler.sendTo(new RequestLookAtMessage(false), (EntityPlayerMP) player);
PacketDistributor.PacketTarget packetTarget = PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getPlayer()); EffortlessBuilding.packetHandler.sendTo(new AddUndoMessage(event.getPos(), event.getBlockSnapshot().getReplacedBlock(), event.getState()), (EntityPlayerMP) player);
if (packetTarget != null) }
PacketHandler.INSTANCE.send(packetTarget, new AddUndoMessage(event.getPos(), event.getState(), Blocks.AIR.defaultBlockState())); }
}
}
}
@SubscribeEvent @SubscribeEvent
public static void breakSpeed(PlayerEvent.BreakSpeed event) { public static void onBlockBroken(BlockEvent.BreakEvent event) {
//Disable if config says so if (event.getWorld().isRemote) return;
if (!BuildConfig.survivalBalancers.increasedMiningTime.get()) return;
if (event.getPlayer() instanceof FakePlayer) return; //Cancel event if necessary
//If cant break far then dont cancel event ever
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(event.getPlayer()).getBuildMode();
if (buildMode != BuildModes.BuildModeEnum.NORMAL && ReachHelper.canBreakFar(event.getPlayer())) {
event.setCanceled(true);
} else {
//NORMAL mode, let vanilla handle block breaking
//But modifiers should still work
//Dont break the original block yourself, otherwise Tinkers Hammer and Veinminer won't work
BuildModes.onBlockBroken(event.getPlayer(), event.getPos(), false);
PlayerEntity player = event.getPlayer(); //Add to undo stack in client
World world = player.level; EffortlessBuilding.packetHandler.sendTo(new AddUndoMessage(event.getPos(), event.getState(), Blocks.AIR.getDefaultState()), (EntityPlayerMP) event.getPlayer());
BlockPos pos = event.getPos(); }
}
//EffortlessBuilding.log(player, String.valueOf(event.getNewSpeed())); @SubscribeEvent
public static void breakSpeed(PlayerEvent.BreakSpeed event) {
//Disable if config says so
if (!BuildConfig.survivalBalancers.increasedMiningTime) return;
float originalBlockHardness = event.getState().getDestroySpeed(world, pos); EntityPlayer player = event.getEntityPlayer();
if (originalBlockHardness < 0) return; //Dont break bedrock World world = player.world;
float totalBlockHardness = 0; BlockPos pos = event.getPos();
//get coordinates
List<BlockPos> coordinates = BuildModifiers.findCoordinates(player, pos);
for (int i = 1; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
//get existing blockstates at those coordinates
BlockState blockState = world.getBlockState(coordinate);
//add hardness for each blockstate, if can break
if (SurvivalHelper.canBreak(world, player, coordinate))
totalBlockHardness += blockState.getDestroySpeed(world, coordinate);
}
//Grabbing percentage from config //EffortlessBuilding.log(player, String.valueOf(event.getNewSpeed()));
float percentage = (float) BuildConfig.survivalBalancers.miningTimePercentage.get() / 100;
totalBlockHardness *= percentage;
totalBlockHardness += originalBlockHardness;
float newSpeed = event.getOriginalSpeed() / totalBlockHardness * originalBlockHardness; float originalBlockHardness = event.getState().getBlockHardness(world, pos);
if (Float.isNaN(newSpeed) || newSpeed == 0f) newSpeed = 1f; if (originalBlockHardness < 0) return; //Dont break bedrock
event.setNewSpeed(newSpeed); float totalBlockHardness = 0;
//get coordinates
List<BlockPos> coordinates = BuildModifiers.findCoordinates(player, pos);
for (int i = 1; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
//get existing blockstates at those coordinates
IBlockState blockState = world.getBlockState(coordinate);
//add hardness for each blockstate, if can break
if (SurvivalHelper.canBreak(world, player, coordinate))
totalBlockHardness += blockState.getBlockHardness(world, coordinate);
}
//EffortlessBuilding.log(player, String.valueOf(event.getNewSpeed())); //Grabbing percentage from config
} float percentage = (float) BuildConfig.survivalBalancers.miningTimePercentage / 100;
totalBlockHardness *= percentage;
totalBlockHardness += originalBlockHardness;
@SubscribeEvent float newSpeed = event.getOriginalSpeed() / totalBlockHardness * originalBlockHardness;
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) { if (Float.isNaN(newSpeed) || newSpeed == 0f) newSpeed = 1f;
if (event.getPlayer() instanceof FakePlayer) return; event.setNewSpeed(newSpeed);
PlayerEntity player = event.getPlayer();
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
}
@SubscribeEvent //EffortlessBuilding.log(player, String.valueOf(event.getNewSpeed()));
public static void onPlayerLoggedOut(PlayerEvent.PlayerLoggedOutEvent event) { }
if (event.getPlayer() instanceof FakePlayer) return;
PlayerEntity player = event.getPlayer();
if (player.getCommandSenderWorld().isClientSide) return;
UndoRedo.clear(player); @SubscribeEvent
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new ClearUndoMessage()); public static void onPlayerLoggedIn(PlayerLoggedInEvent event) {
} EntityPlayer player = event.player;
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
}
@SubscribeEvent @SubscribeEvent
public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) { public static void onPlayerLoggedOut(PlayerLoggedOutEvent event) {
if (event.getPlayer() instanceof FakePlayer) return; EntityPlayer player = event.player;
PlayerEntity player = event.getPlayer(); if (player.getEntityWorld().isRemote) return;
ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
}
@SubscribeEvent UndoRedo.clear(player);
public static void onPlayerChangedDimension(PlayerEvent.PlayerChangedDimensionEvent event) { EffortlessBuilding.packetHandler.sendTo(new ClearUndoMessage(), (EntityPlayerMP) player);
if (event.getPlayer() instanceof FakePlayer) return; }
PlayerEntity player = event.getPlayer();
if (player.getCommandSenderWorld().isClientSide) return;
//Set build mode to normal @SubscribeEvent
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); public static void onPlayerRespawn(PlayerRespawnEvent event) {
modeSettings.setBuildMode(BuildModes.BuildModeEnum.NORMAL); EntityPlayer player = event.player;
ModeSettingsManager.setModeSettings(player, modeSettings); ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player);
}
//Disable modifiers @SubscribeEvent
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); public static void onPlayerChangedDimension(PlayerChangedDimensionEvent event) {
modifierSettings.getMirrorSettings().enabled = false; EntityPlayer player = event.player;
modifierSettings.getRadialMirrorSettings().enabled = false; if (player.getEntityWorld().isRemote) return;
modifierSettings.getArraySettings().enabled = false;
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
ModifierSettingsManager.handleNewPlayer(player); ModifierSettingsManager.handleNewPlayer(player);
ModeSettingsManager.handleNewPlayer(player); ModeSettingsManager.handleNewPlayer(player);
UndoRedo.clear(player); UndoRedo.clear(player);
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new ClearUndoMessage()); EffortlessBuilding.packetHandler.sendTo(new ClearUndoMessage(), (EntityPlayerMP) player);
} }
@SubscribeEvent
public static void onPlayerClone(PlayerEvent.Clone event) {
if (event.getPlayer() instanceof FakePlayer) return;
//Attach capabilities on death, otherwise crash
PlayerEntity oldPlayer = event.getOriginal();
oldPlayer.revive();
PlayerEntity newPlayer = event.getPlayer();
ModifierSettingsManager.setModifierSettings(newPlayer, ModifierSettingsManager.getModifierSettings(oldPlayer));
ModeSettingsManager.setModeSettings(newPlayer, ModeSettingsManager.getModeSettings(oldPlayer));
}
} }

View File

@@ -1,46 +0,0 @@
package nl.requios.effortlessbuilding;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import java.util.HashMap;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD, value = {Dist.CLIENT})
public class ModClientEventHandler {
private static final HashMap<BuildModes.BuildModeEnum, ResourceLocation> buildModeIcons = new HashMap<>();
private static final HashMap<ModeOptions.ActionEnum, ResourceLocation> modeOptionIcons = new HashMap<>();
@SubscribeEvent
public static void onTextureStitch(final TextureStitchEvent.Pre event) {
EffortlessBuilding.log("Stitching textures");
//register icon textures
for (final BuildModes.BuildModeEnum mode : BuildModes.BuildModeEnum.values()) {
final ResourceLocation spriteLocation = new ResourceLocation(EffortlessBuilding.MODID, "icons/" + mode.name().toLowerCase());
event.addSprite(spriteLocation);
buildModeIcons.put(mode, spriteLocation);
}
for (final ModeOptions.ActionEnum action : ModeOptions.ActionEnum.values()) {
final ResourceLocation spriteLocation = new ResourceLocation(EffortlessBuilding.MODID, "icons/" + action.name().toLowerCase());
event.addSprite(spriteLocation);
modeOptionIcons.put(action, spriteLocation);
}
}
public static TextureAtlasSprite getBuildModeIcon(BuildModes.BuildModeEnum mode) {
return Minecraft.getInstance().getModelManager().getAtlas(AtlasTexture.LOCATION_BLOCKS).getSprite(buildModeIcons.get(mode));
}
public static TextureAtlasSprite getModeOptionIcon(ModeOptions.ActionEnum action) {
return Minecraft.getInstance().getModelManager().getAtlas(AtlasTexture.LOCATION_BLOCKS).getSprite(modeOptionIcons.get(action));
}
}

View File

@@ -1,39 +1,40 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import java.util.Dictionary; import java.util.Dictionary;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public abstract class BaseBuildMode implements IBuildMode { public abstract class BaseBuildMode implements IBuildMode {
//In singleplayer client and server variables are shared //In singleplayer client and server variables are shared
//Split everything that needs separate values and may not be called twice in one click //Split everything that needs separate values and may not be called twice in one click
protected Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>(); protected Dictionary<UUID, Integer> rightClickClientTable = new Hashtable<>();
protected Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>(); protected Dictionary<UUID, Integer> rightClickServerTable = new Hashtable<>();
protected Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>(); protected Dictionary<UUID, BlockPos> firstPosTable = new Hashtable<>();
protected Dictionary<UUID, Direction> sideHitTable = new Hashtable<>(); protected Dictionary<UUID, EnumFacing> sideHitTable = new Hashtable<>();
protected Dictionary<UUID, Vector3d> hitVecTable = new Hashtable<>(); protected Dictionary<UUID, Vec3d> hitVecTable = new Hashtable<>();
@Override @Override
public void initialize(PlayerEntity player) { public void initialize(EntityPlayer player) {
rightClickClientTable.put(player.getUUID(), 0); rightClickClientTable.put(player.getUniqueID(), 0);
rightClickServerTable.put(player.getUUID(), 0); rightClickServerTable.put(player.getUniqueID(), 0);
firstPosTable.put(player.getUUID(), BlockPos.ZERO); firstPosTable.put(player.getUniqueID(), BlockPos.ORIGIN);
sideHitTable.put(player.getUUID(), Direction.UP); sideHitTable.put(player.getUniqueID(), EnumFacing.UP);
hitVecTable.put(player.getUUID(), Vector3d.ZERO); hitVecTable.put(player.getUniqueID(), Vec3d.ZERO);
} }
@Override @Override
public Direction getSideHit(PlayerEntity player) { public EnumFacing getSideHit(EntityPlayer player) {
return sideHitTable.get(player.getUUID()); return sideHitTable.get(player.getUniqueID());
} }
@Override @Override
public Vector3d getHitVec(PlayerEntity player) { public Vec3d getHitVec(EntityPlayer player) {
return hitVecTable.get(player.getUUID()); return hitVecTable.get(player.getUniqueID());
} }
} }

View File

@@ -1,16 +1,17 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceContext;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Vector4f;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.buildmodes.*; import nl.requios.effortlessbuilding.buildmode.buildmodes.*;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers; import nl.requios.effortlessbuilding.buildmode.buildmodes.Circle;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmode.buildmodes.Cylinder;
import nl.requios.effortlessbuilding.buildmode.buildmodes.Sphere;
import nl.requios.effortlessbuilding.buildmodifier.*;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.network.BlockBrokenMessage; import nl.requios.effortlessbuilding.network.BlockBrokenMessage;
@@ -21,275 +22,224 @@ import java.util.Dictionary;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import static nl.requios.effortlessbuilding.buildmode.ModeOptions.OptionEnum; import static nl.requios.effortlessbuilding.buildmode.ModeOptions.*;
public class BuildModes { public class BuildModes {
//Static variables are shared between client and server in singleplayer //Static variables are shared between client and server in singleplayer
//We need them separate //We need them separate
public static Dictionary<PlayerEntity, Boolean> currentlyBreakingClient = new Hashtable<>(); public static Dictionary<EntityPlayer, Boolean> currentlyBreakingClient = new Hashtable<>();
public static Dictionary<PlayerEntity, Boolean> currentlyBreakingServer = new Hashtable<>(); public static Dictionary<EntityPlayer, Boolean> currentlyBreakingServer = new Hashtable<>();
//Uses a network message to get the previous raytraceresult from the player public enum BuildModeEnum {
//The server could keep track of all raytraceresults but this might lag with many players NORMAL("effortlessbuilding.mode.normal", new Normal()),
//Raytraceresult is needed for sideHit and hitVec NORMAL_PLUS("effortlessbuilding.mode.normal_plus", new NormalPlus(), OptionEnum.BUILD_SPEED),
public static void onBlockPlacedMessage(PlayerEntity player, BlockPlacedMessage message) { LINE("effortlessbuilding.mode.line", new Line() /*, OptionEnum.THICKNESS*/),
WALL("effortlessbuilding.mode.wall", new Wall(), OptionEnum.FILL),
FLOOR("effortlessbuilding.mode.floor", new Floor(), OptionEnum.FILL),
DIAGONAL_LINE("effortlessbuilding.mode.diagonal_line", new DiagonalLine() /*, OptionEnum.THICKNESS*/),
DIAGONAL_WALL("effortlessbuilding.mode.diagonal_wall", new DiagonalWall() /*, OptionEnum.FILL*/),
SLOPE_FLOOR("effortlessbuilding.mode.slope_floor", new SlopeFloor(), OptionEnum.RAISED_EDGE),
CIRCLE("effortlessbuilding.mode.circle", new Circle(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
CYLINDER("effortlessbuilding.mode.cylinder", new Cylinder(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
SPHERE("effortlessbuilding.mode.sphere", new Sphere(), OptionEnum.CIRCLE_START, OptionEnum.FILL),
CUBE("effortlessbuilding.mode.cube", new Cube(), OptionEnum.CUBE_FILL);
//Check if not in the middle of breaking public String name;
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer; public IBuildMode instance;
if (currentlyBreaking.get(player) != null && currentlyBreaking.get(player)) { public OptionEnum[] options;
//Cancel breaking
initializeMode(player);
return;
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); BuildModeEnum(String name, IBuildMode instance, OptionEnum... options) {
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); this.name = name;
BuildModeEnum buildMode = modeSettings.getBuildMode(); this.instance = instance;
this.options = options;
}
}
BlockPos startPos = null; //Uses a network message to get the previous raytraceresult from the player
//The server could keep track of all raytraceresults but this might lag with many players
//Raytraceresult is needed for sideHit and hitVec
public static void onBlockPlacedMessage(EntityPlayer player, BlockPlacedMessage message) {
if (message.isBlockHit() && message.getBlockPos() != null) { //Check if not in the middle of breaking
startPos = message.getBlockPos(); Dictionary<EntityPlayer, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer;
if (currentlyBreaking.get(player) != null && currentlyBreaking.get(player)) {
//Cancel breaking
initializeMode(player);
return;
}
//Offset in direction of sidehit if not quickreplace and not replaceable ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
//TODO 1.13 replaceable ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable(); BuildModeEnum buildMode = modeSettings.getBuildMode();
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos, message.getSideHit());
if (!modifierSettings.doQuickReplace() && !replaceable && !becomesDoubleSlab) {
startPos = startPos.relative(message.getSideHit());
}
//Get under tall grass and other replaceable blocks BlockPos startPos = null;
if (modifierSettings.doQuickReplace() && replaceable) {
startPos = startPos.below();
}
//Check if player reach does not exceed startpos if (message.isBlockHit() && message.getBlockPos() != null) {
int maxReach = ReachHelper.getMaxReach(player); startPos = message.getBlockPos();
if (buildMode != BuildModeEnum.NORMAL && player.blockPosition().distSqr(startPos) > maxReach * maxReach) {
EffortlessBuilding.log(player, "Placement exceeds your reach.");
return;
}
}
//Even when no starting block is found, call buildmode instance //Offset in direction of sidehit if not quickreplace and not replaceable
//We might want to place things in the air boolean replaceable = player.world.getBlockState(startPos).getBlock().isReplaceable(player.world, startPos);
List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, message.getSideHit(), message.getHitVec(), modifierSettings.doQuickReplace()); boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos, message.getSideHit());
if (!modifierSettings.doQuickReplace() && !replaceable && !becomesDoubleSlab) {
startPos = startPos.offset(message.getSideHit());
}
if (coordinates.isEmpty()) { //Get under tall grass and other replaceable blocks
currentlyBreaking.put(player, false); if (modifierSettings.doQuickReplace() && replaceable) {
return; startPos = startPos.down();
} }
//Limit number of blocks you can place //Check if player reach does not exceed startpos
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player); int maxReach = ReachHelper.getMaxReach(player);
if (coordinates.size() > limit) { if (buildMode != BuildModeEnum.NORMAL && player.getPosition().distanceSq(startPos) > maxReach * maxReach) {
coordinates = coordinates.subList(0, limit); EffortlessBuilding.log(player, "Placement exceeds your reach.");
} return;
}
}
Direction sideHit = buildMode.instance.getSideHit(player); //Even when no starting block is found, call buildmode instance
if (sideHit == null) sideHit = message.getSideHit(); //We might want to place things in the air
List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, message.getSideHit(), message.getHitVec(), modifierSettings.doQuickReplace());
Vector3d hitVec = buildMode.instance.getHitVec(player); if (coordinates.isEmpty()) {
if (hitVec == null) hitVec = message.getHitVec(); currentlyBreaking.put(player, false);
return;
}
BuildModifiers.onBlockPlaced(player, coordinates, sideHit, hitVec, message.getPlaceStartPos()); //Limit number of blocks you can place
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
if (coordinates.size() > limit) {
coordinates = coordinates.subList(0, limit);
}
//Only works when finishing a buildmode is equal to placing some blocks EnumFacing sideHit = buildMode.instance.getSideHit(player);
//No intermediate blocks allowed if (sideHit == null) sideHit = message.getSideHit();
currentlyBreaking.remove(player);
} Vec3d hitVec = buildMode.instance.getHitVec(player);
if (hitVec == null) hitVec = message.getHitVec();
//Use a network message to break blocks in the distance using clientside mouse input BuildModifiers.onBlockPlaced(player, coordinates, sideHit, hitVec, message.getPlaceStartPos());
public static void onBlockBrokenMessage(PlayerEntity player, BlockBrokenMessage message) {
BlockPos startPos = message.isBlockHit() ? message.getBlockPos() : null;
onBlockBroken(player, startPos, true);
}
public static void onBlockBroken(PlayerEntity player, BlockPos startPos, boolean breakStartPos) { //Only works when finishing a buildmode is equal to placing some blocks
//No intermediate blocks allowed
currentlyBreaking.remove(player);
//Check if not in the middle of placing }
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
if (currentlyBreaking.get(player) != null && !currentlyBreaking.get(player)) {
//Cancel placing
initializeMode(player);
return;
}
//If first click //Use a network message to break blocks in the distance using clientside mouse input
if (currentlyBreaking.get(player) == null) { public static void onBlockBrokenMessage(EntityPlayer player, BlockBrokenMessage message) {
//If startpos is null, dont do anything BlockPos startPos = message.isBlockHit() ? message.getBlockPos() : null;
if (startPos == null) return; onBlockBroken(player, startPos, true);
} }
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); public static void onBlockBroken(EntityPlayer player, BlockPos startPos, boolean breakStartPos) {
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Get coordinates //Check if not in the middle of placing
BuildModeEnum buildMode = modeSettings.getBuildMode(); Dictionary<EntityPlayer, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer;
List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, Direction.UP, Vector3d.ZERO, true); if (currentlyBreaking.get(player) != null && !currentlyBreaking.get(player)) {
//Cancel placing
initializeMode(player);
return;
}
if (coordinates.isEmpty()) { //If first click
currentlyBreaking.put(player, true); if (currentlyBreaking.get(player) == null) {
return; //If startpos is null, dont do anything
} if (startPos == null) return;
}
//Let buildmodifiers break blocks ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
BuildModifiers.onBlockBroken(player, coordinates, breakStartPos); ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Only works when finishing a buildmode is equal to breaking some blocks //Get coordinates
//No intermediate blocks allowed BuildModeEnum buildMode = modeSettings.getBuildMode();
currentlyBreaking.remove(player); List<BlockPos> coordinates = buildMode.instance.onRightClick(player, startPos, EnumFacing.UP, Vec3d.ZERO, true);
}
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos startPos, boolean skipRaytrace) { if (coordinates.isEmpty()) {
List<BlockPos> coordinates = new ArrayList<>(); currentlyBreaking.put(player, true);
return;
}
ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); //Let buildmodifiers break blocks
coordinates.addAll(modeSettings.getBuildMode().instance.findCoordinates(player, startPos, skipRaytrace)); BuildModifiers.onBlockBroken(player, coordinates, breakStartPos);
return coordinates; //Only works when finishing a buildmode is equal to breaking some blocks
} //No intermediate blocks allowed
currentlyBreaking.remove(player);
}
public static void initializeMode(PlayerEntity player) { public static List<BlockPos> findCoordinates(EntityPlayer player, BlockPos startPos, boolean skipRaytrace) {
//Resetting mode, so not placing or breaking List<BlockPos> coordinates = new ArrayList<>();
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
currentlyBreaking.remove(player);
ModeSettingsManager.getModeSettings(player).getBuildMode().instance.initialize(player); ModeSettingsManager.ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
} coordinates.addAll(modeSettings.getBuildMode().instance.findCoordinates(player, startPos, skipRaytrace));
public static boolean isCurrentlyPlacing(PlayerEntity player) { return coordinates;
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer; }
return currentlyBreaking.get(player) != null && !currentlyBreaking.get(player);
}
public static boolean isCurrentlyBreaking(PlayerEntity player) { public static void initializeMode(EntityPlayer player) {
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer; //Resetting mode, so not placing or breaking
return currentlyBreaking.get(player) != null && currentlyBreaking.get(player); Dictionary<EntityPlayer, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer;
} currentlyBreaking.remove(player);
//Either placing or breaking ModeSettingsManager.getModeSettings(player).getBuildMode().instance.initialize(player);
public static boolean isActive(PlayerEntity player) { }
Dictionary<PlayerEntity, Boolean> currentlyBreaking = player.level.isClientSide ? currentlyBreakingClient : currentlyBreakingServer;
return currentlyBreaking.get(player) != null;
}
//Find coordinates on a line bound by a plane public static boolean isCurrentlyPlacing(EntityPlayer player) {
public static Vector3d findXBound(double x, Vector3d start, Vector3d look) { Dictionary<EntityPlayer, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer;
//then y and z are return currentlyBreaking.get(player) != null && !currentlyBreaking.get(player);
double y = (x - start.x) / look.x * look.y + start.y; }
double z = (x - start.x) / look.x * look.z + start.z;
return new Vector3d(x, y, z); public static boolean isCurrentlyBreaking(EntityPlayer player) {
} Dictionary<EntityPlayer, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer;
return currentlyBreaking.get(player) != null && currentlyBreaking.get(player);
}
//Either placing or breaking
public static boolean isActive(EntityPlayer player) {
Dictionary<EntityPlayer, Boolean> currentlyBreaking = player.world.isRemote ? currentlyBreakingClient : currentlyBreakingServer;
return currentlyBreaking.get(player) != null;
}
//-- Common build mode functionality --// //Find coordinates on a line bound by a plane
public static Vec3d findXBound(double x, Vec3d start, Vec3d look) {
//then y and z are
double y = (x - start.x) / look.x * look.y + start.y;
double z = (x - start.x) / look.x * look.z + start.z;
public static Vector3d findYBound(double y, Vector3d start, Vector3d look) { return new Vec3d(x, y, z);
//then x and z are }
double x = (y - start.y) / look.y * look.x + start.x;
double z = (y - start.y) / look.y * look.z + start.z;
return new Vector3d(x, y, z); public static Vec3d findYBound(double y, Vec3d start, Vec3d look) {
} //then x and z are
double x = (y - start.y) / look.y * look.x + start.x;
double z = (y - start.y) / look.y * look.z + start.z;
public static Vector3d findZBound(double z, Vector3d start, Vector3d look) { return new Vec3d(x, y, z);
//then x and y are }
double x = (z - start.z) / look.z * look.x + start.x;
double y = (z - start.z) / look.z * look.y + start.y;
return new Vector3d(x, y, z); public static Vec3d findZBound(double z, Vec3d start, Vec3d look) {
} //then x and y are
double x = (z - start.z) / look.z * look.x + start.x;
double y = (z - start.z) / look.z * look.y + start.y;
//Use this instead of player.getLookVec() in any buildmodes code return new Vec3d(x, y, z);
public static Vector3d getPlayerLookVec(PlayerEntity player) { }
Vector3d lookVec = player.getLookAngle();
double x = lookVec.x;
double y = lookVec.y;
double z = lookVec.z;
//Further calculations (findXBound etc) don't like any component being 0 or 1 (e.g. dividing by 0) public static boolean isCriteriaValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace, Vec3d lineBound, Vec3d planeBound, double distToPlayerSq) {
//isCriteriaValid below will take up to 2 minutes to raytrace blocks towards infinity if that is the case boolean intersects = false;
//So make sure they are close to but never exactly 0 or 1 if (!skipRaytrace) {
if (Math.abs(x) < 0.0001) x = 0.0001; //collision within a 1 block radius to selected is fine
if (Math.abs(x - 1.0) < 0.0001) x = 0.9999; RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, lineBound, false, true, false);
if (Math.abs(x + 1.0) < 0.0001) x = -0.9999; intersects = rayTraceResult != null && rayTraceResult.typeOfHit == RayTraceResult.Type.BLOCK &&
planeBound.subtract(rayTraceResult.hitVec).lengthSquared() > 4;
}
if (Math.abs(y) < 0.0001) y = 0.0001; return planeBound.subtract(start).dotProduct(look) > 0 &&
if (Math.abs(y - 1.0) < 0.0001) y = 0.9999; distToPlayerSq > 2 && distToPlayerSq < reach * reach &&
if (Math.abs(y + 1.0) < 0.0001) y = -0.9999; !intersects;
}
if (Math.abs(z) < 0.0001) z = 0.0001;
if (Math.abs(z - 1.0) < 0.0001) z = 0.9999;
if (Math.abs(z + 1.0) < 0.0001) z = -0.9999;
return new Vector3d(x, y, z);
}
public static boolean isCriteriaValid(Vector3d start, Vector3d look, int reach, PlayerEntity player, boolean skipRaytrace, Vector3d lineBound, Vector3d planeBound, double distToPlayerSq) {
boolean intersects = false;
if (!skipRaytrace) {
//collision within a 1 block radius to selected is fine
RayTraceContext rayTraceContext = new RayTraceContext(start, lineBound, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, player);
RayTraceResult rayTraceResult = player.level.clip(rayTraceContext);
intersects = rayTraceResult != null && rayTraceResult.getType() == RayTraceResult.Type.BLOCK &&
planeBound.subtract(rayTraceResult.getLocation()).lengthSqr() > 4;
}
return planeBound.subtract(start).dot(look) > 0 &&
distToPlayerSq > 2 && distToPlayerSq < reach * reach &&
!intersects;
}
public enum BuildModeEnum {
NORMAL("normal", new Normal(), BuildModeCategoryEnum.BASIC),
NORMAL_PLUS("normal_plus", new NormalPlus(), BuildModeCategoryEnum.BASIC, OptionEnum.BUILD_SPEED),
LINE("line", new Line(), BuildModeCategoryEnum.BASIC /*, OptionEnum.THICKNESS*/),
WALL("wall", new Wall(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL),
FLOOR("floor", new Floor(), BuildModeCategoryEnum.BASIC, OptionEnum.FILL),
CUBE("cube", new Cube(), BuildModeCategoryEnum.BASIC, OptionEnum.CUBE_FILL),
DIAGONAL_LINE("diagonal_line", new DiagonalLine(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.THICKNESS*/),
DIAGONAL_WALL("diagonal_wall", new DiagonalWall(), BuildModeCategoryEnum.DIAGONAL /*, OptionEnum.FILL*/),
SLOPE_FLOOR("slope_floor", new SlopeFloor(), BuildModeCategoryEnum.DIAGONAL, OptionEnum.RAISED_EDGE),
CIRCLE("circle", new Circle(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL),
CYLINDER("cylinder", new Cylinder(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL),
SPHERE("sphere", new Sphere(), BuildModeCategoryEnum.CIRCULAR, OptionEnum.CIRCLE_START, OptionEnum.FILL);
public String name;
public IBuildMode instance;
public final BuildModeCategoryEnum category;
public OptionEnum[] options;
BuildModeEnum(String name, IBuildMode instance, BuildModeCategoryEnum category, OptionEnum... options) {
this.name = name;
this.instance = instance;
this.category = category;
this.options = options;
}
public String getNameKey() {
return "effortlessbuilding.mode." + name;
}
public String getDescriptionKey() {
return "effortlessbuilding.modedescription." + name;
}
}
public enum BuildModeCategoryEnum {
BASIC(new Vector4f(0f, .5f, 1f, .8f)),
DIAGONAL(new Vector4f(0.56f, 0.28f, 0.87f, .8f)),
CIRCULAR(new Vector4f(0.29f, 0.76f, 0.3f, 1f)),
ROOF(new Vector4f(0.83f, 0.87f, 0.23f, .8f));
public final Vector4f color;
BuildModeCategoryEnum(Vector4f color) {
this.color = color;
}
}
} }

View File

@@ -1,25 +1,25 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import java.util.List; import java.util.List;
public interface IBuildMode { public interface IBuildMode {
//Fired when a player selects a buildmode and when it needs to initializeMode //Fired when a player selects a buildmode and when it needs to initializeMode
void initialize(PlayerEntity player); void initialize(EntityPlayer player);
//Fired when a block would be placed //Fired when a block would be placed
//Return a list of coordinates where you want to place blocks //Return a list of coordinates where you want to place blocks
List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vector3d hitVec, boolean skipRaytrace); List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace);
//Fired continuously for visualization purposes //Fired continuously for visualization purposes
List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace); List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace);
Direction getSideHit(PlayerEntity player); EnumFacing getSideHit(EntityPlayer player);
Vector3d getHitVec(PlayerEntity player); Vec3d getHitVec(EntityPlayer player);
} }

View File

@@ -1,6 +1,6 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
@@ -9,183 +9,174 @@ import nl.requios.effortlessbuilding.proxy.ClientProxy;
public class ModeOptions { public class ModeOptions {
private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED; public enum ActionEnum {
private static ActionEnum fill = ActionEnum.FULL; UNDO("effortlessbuilding.action.undo"),
private static ActionEnum cubeFill = ActionEnum.CUBE_FULL; REDO("effortlessbuilding.action.redo"),
private static ActionEnum raisedEdge = ActionEnum.SHORT_EDGE; REPLACE("effortlessbuilding.action.replace"),
private static ActionEnum lineThickness = ActionEnum.THICKNESS_1; OPEN_MODIFIER_SETTINGS("effortlessbuilding.action.open_modifier_settings"),
private static ActionEnum circleStart = ActionEnum.CIRCLE_START_CORNER;
public static ActionEnum getOptionSetting(OptionEnum option) { NORMAL_SPEED("effortlessbuilding.action.normal_speed"),
switch (option) { FAST_SPEED("effortlessbuilding.action.fast_speed"),
case BUILD_SPEED:
return getBuildSpeed();
case FILL:
return getFill();
case CUBE_FILL:
return getCubeFill();
case RAISED_EDGE:
return getRaisedEdge();
case LINE_THICKNESS:
return getLineThickness();
case CIRCLE_START:
return getCircleStart();
default:
return null;
}
}
public static ActionEnum getBuildSpeed() { FULL("effortlessbuilding.action.full"),
return buildSpeed; HOLLOW("effortlessbuilding.action.hollow"),
}
public static ActionEnum getFill() { CUBE_FULL("effortlessbuilding.action.full"),
return fill; CUBE_HOLLOW("effortlessbuilding.action.hollow"),
} CUBE_SKELETON("effortlessbuilding.action.skeleton"),
public static ActionEnum getCubeFill() { SHORT_EDGE("effortlessbuilding.action.short_edge"),
return cubeFill; LONG_EDGE("effortlessbuilding.action.long_edge"),
}
public static ActionEnum getRaisedEdge() { THICKNESS_1("effortlessbuilding.action.thickness_1"),
return raisedEdge; THICKNESS_3("effortlessbuilding.action.thickness_3"),
} THICKNESS_5("effortlessbuilding.action.thickness_5"),
public static ActionEnum getLineThickness() { CIRCLE_START_CORNER("effortlessbuilding.action.start_corner"),
return lineThickness; CIRCLE_START_CENTER("effortlessbuilding.action.start_center");
}
public static ActionEnum getCircleStart() { public String name;
return circleStart;
}
//Called on both client and server ActionEnum(String name) {
public static void performAction(PlayerEntity player, ActionEnum action) { this.name = name;
if (action == null) return; }
}
switch (action) { public enum OptionEnum {
case UNDO: BUILD_SPEED("effortlessbuilding.action.build_speed", ActionEnum.NORMAL_SPEED, ActionEnum.FAST_SPEED),
UndoRedo.undo(player); FILL("effortlessbuilding.action.filling", ActionEnum.FULL, ActionEnum.HOLLOW),
break; CUBE_FILL("effortlessbuilding.action.filling", ActionEnum.CUBE_FULL, ActionEnum.CUBE_HOLLOW, ActionEnum.CUBE_SKELETON),
case REDO: RAISED_EDGE("effortlessbuilding.action.raised_edge", ActionEnum.SHORT_EDGE, ActionEnum.LONG_EDGE),
UndoRedo.redo(player); LINE_THICKNESS("effortlessbuilding.action.thickness", ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5),
break; CIRCLE_START("effortlessbuilding.action.circle_start", ActionEnum.CIRCLE_START_CORNER, ActionEnum.CIRCLE_START_CENTER);
case REPLACE:
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace());
EffortlessBuilding.log(player, "Set " + TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + (
modifierSettings.doQuickReplace() ? "on" : "off"), true);
break;
case OPEN_MODIFIER_SETTINGS:
if (player.level.isClientSide)
ClientProxy.openModifierSettings();
break;
case OPEN_PLAYER_SETTINGS:
if (player.level.isClientSide)
ClientProxy.openPlayerSettings();
break;
case NORMAL_SPEED: public String name;
buildSpeed = ActionEnum.NORMAL_SPEED; public ActionEnum[] actions;
break;
case FAST_SPEED:
buildSpeed = ActionEnum.FAST_SPEED;
break;
case FULL:
fill = ActionEnum.FULL;
break;
case HOLLOW:
fill = ActionEnum.HOLLOW;
break;
case CUBE_FULL:
cubeFill = ActionEnum.CUBE_FULL;
break;
case CUBE_HOLLOW:
cubeFill = ActionEnum.CUBE_HOLLOW;
break;
case CUBE_SKELETON:
cubeFill = ActionEnum.CUBE_SKELETON;
break;
case SHORT_EDGE:
raisedEdge = ActionEnum.SHORT_EDGE;
break;
case LONG_EDGE:
raisedEdge = ActionEnum.LONG_EDGE;
break;
case THICKNESS_1:
lineThickness = ActionEnum.THICKNESS_1;
break;
case THICKNESS_3:
lineThickness = ActionEnum.THICKNESS_3;
break;
case THICKNESS_5:
lineThickness = ActionEnum.THICKNESS_5;
break;
case CIRCLE_START_CENTER:
circleStart = ActionEnum.CIRCLE_START_CENTER;
break;
case CIRCLE_START_CORNER:
circleStart = ActionEnum.CIRCLE_START_CORNER;
break;
}
if (player.level.isClientSide && OptionEnum(String name, ActionEnum... actions){
action != ActionEnum.REPLACE && this.name = name;
action != ActionEnum.OPEN_MODIFIER_SETTINGS && this.actions = actions;
action != ActionEnum.OPEN_PLAYER_SETTINGS) { }
}
EffortlessBuilding.logTranslate(player, "", action.name, "", true); private static ActionEnum buildSpeed = ActionEnum.NORMAL_SPEED;
} private static ActionEnum fill = ActionEnum.FULL;
} private static ActionEnum cubeFill = ActionEnum.CUBE_FULL;
private static ActionEnum raisedEdge = ActionEnum.SHORT_EDGE;
private static ActionEnum lineThickness = ActionEnum.THICKNESS_1;
private static ActionEnum circleStart = ActionEnum.CIRCLE_START_CORNER;
public enum ActionEnum { public static ActionEnum getOptionSetting(OptionEnum option) {
UNDO("effortlessbuilding.action.undo"), switch (option) {
REDO("effortlessbuilding.action.redo"), case BUILD_SPEED:
REPLACE("effortlessbuilding.action.replace"), return getBuildSpeed();
OPEN_MODIFIER_SETTINGS("effortlessbuilding.action.open_modifier_settings"), case FILL:
OPEN_PLAYER_SETTINGS("effortlessbuilding.action.open_player_settings"), return getFill();
case CUBE_FILL:
return getCubeFill();
case RAISED_EDGE:
return getRaisedEdge();
case LINE_THICKNESS:
return getLineThickness();
case CIRCLE_START:
return getCircleStart();
default:
return null;
}
}
NORMAL_SPEED("effortlessbuilding.action.normal_speed"), public static ActionEnum getBuildSpeed() {
FAST_SPEED("effortlessbuilding.action.fast_speed"), return buildSpeed;
}
FULL("effortlessbuilding.action.full"), public static ActionEnum getFill() {
HOLLOW("effortlessbuilding.action.hollow"), return fill;
}
CUBE_FULL("effortlessbuilding.action.full"), public static ActionEnum getCubeFill() {
CUBE_HOLLOW("effortlessbuilding.action.hollow"), return cubeFill;
CUBE_SKELETON("effortlessbuilding.action.skeleton"), }
SHORT_EDGE("effortlessbuilding.action.short_edge"), public static ActionEnum getRaisedEdge() {
LONG_EDGE("effortlessbuilding.action.long_edge"), return raisedEdge;
}
THICKNESS_1("effortlessbuilding.action.thickness_1"), public static ActionEnum getLineThickness() {
THICKNESS_3("effortlessbuilding.action.thickness_3"), return lineThickness;
THICKNESS_5("effortlessbuilding.action.thickness_5"), }
CIRCLE_START_CORNER("effortlessbuilding.action.start_corner"), public static ActionEnum getCircleStart() {
CIRCLE_START_CENTER("effortlessbuilding.action.start_center"); return circleStart;
}
public String name; //Called on both client and server
public static void performAction(EntityPlayer player, ActionEnum action) {
if (action == null) return;
ActionEnum(String name) { switch (action) {
this.name = name; case UNDO:
} UndoRedo.undo(player);
} break;
case REDO:
UndoRedo.redo(player);
break;
case REPLACE:
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace());
EffortlessBuilding.log(player, "Set " + TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + (
modifierSettings.doQuickReplace() ? "on" : "off"), true);
break;
case OPEN_MODIFIER_SETTINGS:
if (player.world.isRemote)
ClientProxy.openModifierSettings();
break;
public enum OptionEnum { case NORMAL_SPEED:
BUILD_SPEED("effortlessbuilding.action.build_speed", ActionEnum.NORMAL_SPEED, ActionEnum.FAST_SPEED), buildSpeed = ActionEnum.NORMAL_SPEED;
FILL("effortlessbuilding.action.filling", ActionEnum.FULL, ActionEnum.HOLLOW), break;
CUBE_FILL("effortlessbuilding.action.filling", ActionEnum.CUBE_FULL, ActionEnum.CUBE_HOLLOW, ActionEnum.CUBE_SKELETON), case FAST_SPEED:
RAISED_EDGE("effortlessbuilding.action.raised_edge", ActionEnum.SHORT_EDGE, ActionEnum.LONG_EDGE), buildSpeed = ActionEnum.FAST_SPEED;
LINE_THICKNESS("effortlessbuilding.action.thickness", ActionEnum.THICKNESS_1, ActionEnum.THICKNESS_3, ActionEnum.THICKNESS_5), break;
CIRCLE_START("effortlessbuilding.action.circle_start", ActionEnum.CIRCLE_START_CORNER, ActionEnum.CIRCLE_START_CENTER); case FULL:
fill = ActionEnum.FULL;
break;
case HOLLOW:
fill = ActionEnum.HOLLOW;
break;
case CUBE_FULL:
cubeFill = ActionEnum.CUBE_FULL;
break;
case CUBE_HOLLOW:
cubeFill = ActionEnum.CUBE_HOLLOW;
break;
case CUBE_SKELETON:
cubeFill = ActionEnum.CUBE_SKELETON;
break;
case SHORT_EDGE:
raisedEdge = ActionEnum.SHORT_EDGE;
break;
case LONG_EDGE:
raisedEdge = ActionEnum.LONG_EDGE;
break;
case THICKNESS_1:
lineThickness = ActionEnum.THICKNESS_1;
break;
case THICKNESS_3:
lineThickness = ActionEnum.THICKNESS_3;
break;
case THICKNESS_5:
lineThickness = ActionEnum.THICKNESS_5;
break;
case CIRCLE_START_CENTER:
circleStart = ActionEnum.CIRCLE_START_CENTER;
break;
case CIRCLE_START_CORNER:
circleStart = ActionEnum.CIRCLE_START_CORNER;
break;
}
public String name; if (player.world.isRemote && action != ActionEnum.REPLACE && action != ActionEnum.OPEN_MODIFIER_SETTINGS) {
public ActionEnum[] actions; ClientProxy.logTranslate(action.name);
}
OptionEnum(String name, ActionEnum... actions) { }
this.name = name;
this.actions = actions;
}
}
} }

View File

@@ -1,98 +1,86 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.network.PacketDistributor;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.capability.ModeCapabilityManager; import nl.requios.effortlessbuilding.capability.ModeCapabilityManager;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.network.ModeSettingsMessage; import nl.requios.effortlessbuilding.network.ModeSettingsMessage;
import nl.requios.effortlessbuilding.network.PacketHandler;
import javax.annotation.Nonnull;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ModeSettingsManager { public class ModeSettingsManager {
//Retrieves the buildsettings of a player through the modifierCapability capability //Retrieves the buildsettings of a player through the modifierCapability capability
//Never returns null //Never returns null
@Nonnull public static ModeSettings getModeSettings(EntityPlayer player) {
public static ModeSettings getModeSettings(PlayerEntity player) { if (player.hasCapability(ModeCapabilityManager.modeCapability, null)) {
LazyOptional<ModeCapabilityManager.IModeCapability> modeCapability = ModeCapabilityManager.IModeCapability capability = player.getCapability(
player.getCapability(ModeCapabilityManager.modeCapability, null); ModeCapabilityManager.modeCapability, null);
if (capability.getModeData() == null) {
capability.setModeData(new ModeSettings());
}
return capability.getModeData();
}
throw new IllegalArgumentException("Player does not have modeCapability capability");
}
if (modeCapability.isPresent()) { public static void setModeSettings(EntityPlayer player, ModeSettings modeSettings) {
ModeCapabilityManager.IModeCapability capability = modeCapability.orElse(null); if (player == null) {
if (capability.getModeData() == null) { EffortlessBuilding.log("Cannot set buildsettings, player is null");
capability.setModeData(new ModeSettings()); return;
} }
return capability.getModeData(); if (player.hasCapability(ModeCapabilityManager.modeCapability, null)) {
} ModeCapabilityManager.IModeCapability capability = player.getCapability(
ModeCapabilityManager.modeCapability, null);
//Player does not have modeCapability capability capability.setModeData(modeSettings);
//Return dummy settings
return new ModeSettings();
// throw new IllegalArgumentException("Player does not have modeCapability capability");
}
public static void setModeSettings(PlayerEntity player, ModeSettings modeSettings) { //Initialize new mode
if (player == null) { BuildModes.initializeMode(player);
EffortlessBuilding.log("Cannot set buildmode settings, player is null"); } else {
return; EffortlessBuilding.log(player, "Saving buildsettings failed.");
} }
LazyOptional<ModeCapabilityManager.IModeCapability> modeCapability = }
player.getCapability(ModeCapabilityManager.modeCapability, null);
modeCapability.ifPresent((capability) -> { public static String sanitize(ModeSettings modeSettings, EntityPlayer player) {
capability.setModeData(modeSettings); int maxReach = ReachHelper.getMaxReach(player);
String error = "";
BuildModes.initializeMode(player); //TODO sanitize
});
if (!modeCapability.isPresent()) { return error;
EffortlessBuilding.log(player, "Saving buildmode settings failed."); }
}
}
public static String sanitize(ModeSettings modeSettings, PlayerEntity player) { public static class ModeSettings {
int maxReach = ReachHelper.getMaxReach(player); private BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.NORMAL;
String error = "";
//TODO sanitize public ModeSettings() {
}
return error; public ModeSettings(BuildModes.BuildModeEnum buildMode) {
} this.buildMode = buildMode;
}
public static void handleNewPlayer(PlayerEntity player) { public BuildModes.BuildModeEnum getBuildMode() {
//Makes sure player has mode settings (if it doesnt it will create it) return this.buildMode;
getModeSettings(player); }
//Only on server public void setBuildMode(BuildModes.BuildModeEnum buildMode) {
if (!player.level.isClientSide) { this.buildMode = buildMode;
//Send to client }
ModeSettingsMessage msg = new ModeSettingsMessage(getModeSettings(player)); }
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), msg);
}
}
public static class ModeSettings { public static void handleNewPlayer(EntityPlayer player){
private BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.NORMAL; if (getModeSettings(player) == null) {
setModeSettings(player, new ModeSettings());
}
public ModeSettings() { //Only on server
} if (!player.world.isRemote) {
//Send to client
public ModeSettings(BuildModes.BuildModeEnum buildMode) { ModeSettingsMessage msg = new ModeSettingsMessage(getModeSettings(player));
this.buildMode = buildMode; EffortlessBuilding.packetHandler.sendTo(msg, (EntityPlayerMP) player);
} }
}
public BuildModes.BuildModeEnum getBuildMode() {
return this.buildMode;
}
public void setBuildMode(BuildModes.BuildModeEnum buildMode) {
this.buildMode = buildMode;
}
}
} }

View File

@@ -1,213 +1,215 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.buildmodes.DiagonalLine;
import nl.requios.effortlessbuilding.buildmode.buildmodes.Floor;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.*; import java.util.*;
public abstract class ThreeClicksBuildMode extends BaseBuildMode { public abstract class ThreeClicksBuildMode extends BaseBuildMode {
protected Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>(); protected Dictionary<UUID, BlockPos> secondPosTable = new Hashtable<>();
//Finds height after floor has been chosen in buildmodes with 3 clicks static class HeightCriteria {
public static BlockPos findHeight(PlayerEntity player, BlockPos secondPos, boolean skipRaytrace) { Vec3d planeBound;
Vector3d look = BuildModes.getPlayerLookVec(player); Vec3d lineBound;
Vector3d start = new Vector3d(player.getX(), player.getY() + player.getEyeHeight(), player.getZ()); double distToLineSq;
double distToPlayerSq;
List<HeightCriteria> criteriaList = new ArrayList<>(3); HeightCriteria(Vec3d planeBound, BlockPos secondPos, Vec3d start) {
this.planeBound = planeBound;
this.lineBound = toLongestLine(this.planeBound, secondPos);
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSquared();
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
}
//X //Make it from a plane into a line, on y axis only
Vector3d xBound = BuildModes.findXBound(secondPos.getX(), start, look); private Vec3d toLongestLine(Vec3d boundVec, BlockPos secondPos) {
criteriaList.add(new HeightCriteria(xBound, secondPos, start)); BlockPos bound = new BlockPos(boundVec);
return new Vec3d(secondPos.getX(), bound.getY(), secondPos.getZ());
}
//Z //check if its not behind the player and its not too close and not too far
Vector3d zBound = BuildModes.findZBound(secondPos.getZ(), start, look); //also check if raytrace from player to block does not intersect blocks
criteriaList.add(new HeightCriteria(zBound, secondPos, start)); public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
//Remove invalid criteria return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq);
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach }
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace)); }
//If none are valid, return empty list of blocks @Override
if (criteriaList.isEmpty()) return null; public void initialize(EntityPlayer player) {
super.initialize(player);
secondPosTable.put(player.getUniqueID(), BlockPos.ORIGIN);
}
//If only 1 is valid, choose that one @Override
HeightCriteria selected = criteriaList.get(0); public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
//If multiple are valid, choose based on criteria Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
if (criteriaList.size() > 1) { int rightClickNr = rightClickTable.get(player.getUniqueID());
//Select the one that is closest (from wall position to its line counterpart) rightClickNr++;
for (int i = 1; i < criteriaList.size(); i++) { rightClickTable.put(player.getUniqueID(), rightClickNr);
HeightCriteria criteria = criteriaList.get(i);
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
//Both very close to line, choose closest to player
if (criteria.distToPlayerSq < selected.distToPlayerSq)
selected = criteria;
} else {
//Pick closest to line
if (criteria.distToLineSq < selected.distToLineSq)
selected = criteria;
}
}
}
return new BlockPos(selected.lineBound);
}
@Override if (rightClickNr == 1) {
public void initialize(PlayerEntity player) { //If clicking in air, reset and try again
super.initialize(player); if (blockPos == null) {
secondPosTable.put(player.getUUID(), BlockPos.ZERO); rightClickTable.put(player.getUniqueID(), 0);
} return list;
}
@Override //First click, remember starting position
public List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vector3d hitVec, boolean skipRaytrace) { firstPosTable.put(player.getUniqueID(), blockPos);
List<BlockPos> list = new ArrayList<>(); sideHitTable.put(player.getUniqueID(), sideHit);
hitVecTable.put(player.getUniqueID(), hitVec);
//Keep list empty, dont place any blocks yet
} else if (rightClickNr == 2) {
//Second click, find other floor point
BlockPos firstPos = firstPosTable.get(player.getUniqueID());
BlockPos secondPos = findSecondPos(player, firstPos, true);
Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable; if (secondPos == null) {
int rightClickNr = rightClickTable.get(player.getUUID()); rightClickTable.put(player.getUniqueID(), 1);
rightClickNr++; return list;
rightClickTable.put(player.getUUID(), rightClickNr); }
if (rightClickNr == 1) { secondPosTable.put(player.getUniqueID(), secondPos);
//If clicking in air, reset and try again
if (blockPos == null) {
rightClickTable.put(player.getUUID(), 0);
return list;
}
//First click, remember starting position } else {
firstPosTable.put(player.getUUID(), blockPos); //Third click, place diagonal wall with height
sideHitTable.put(player.getUUID(), sideHit); list = findCoordinates(player, blockPos, skipRaytrace);
hitVecTable.put(player.getUUID(), hitVec); rightClickTable.put(player.getUniqueID(), 0);
//Keep list empty, dont place any blocks yet }
} else if (rightClickNr == 2) {
//Second click, find other floor point
BlockPos firstPos = firstPosTable.get(player.getUUID());
BlockPos secondPos = findSecondPos(player, firstPos, true);
if (secondPos == null) { return list;
rightClickTable.put(player.getUUID(), 1); }
return list;
}
secondPosTable.put(player.getUUID(), secondPos); @Override
public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
int rightClickNr = rightClickTable.get(player.getUniqueID());
} else { if (rightClickNr == 0) {
//Third click, place diagonal wall with height if (blockPos != null)
list = findCoordinates(player, blockPos, skipRaytrace); list.add(blockPos);
rightClickTable.put(player.getUUID(), 0); } else if (rightClickNr == 1) {
} BlockPos firstPos = firstPosTable.get(player.getUniqueID());
return list; BlockPos secondPos = findSecondPos(player, firstPos, true);
} if (secondPos == null) return list;
@Override //Limit amount of blocks you can place per row
public List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace) { int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable;
int rightClickNr = rightClickTable.get(player.getUUID());
if (rightClickNr == 0) { int x1 = firstPos.getX(), x2 = secondPos.getX();
if (blockPos != null) int y1 = firstPos.getY(), y2 = secondPos.getY();
list.add(blockPos); int z1 = firstPos.getZ(), z2 = secondPos.getZ();
} else if (rightClickNr == 1) {
BlockPos firstPos = firstPosTable.get(player.getUUID());
BlockPos secondPos = findSecondPos(player, firstPos, true); //limit axis
if (secondPos == null) return list; if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
//Limit amount of blocks you can place per row //Add diagonal line from first to second
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player); list.addAll(getIntermediateBlocks(player, x1, y1, z1, x2, y2, z2));
int x1 = firstPos.getX(), x2 = secondPos.getX(); } else {
int y1 = firstPos.getY(), y2 = secondPos.getY(); BlockPos firstPos = firstPosTable.get(player.getUniqueID());
int z1 = firstPos.getZ(), z2 = secondPos.getZ(); BlockPos secondPos = secondPosTable.get(player.getUniqueID());
//limit axis BlockPos thirdPos = findThirdPos(player, firstPos, secondPos, skipRaytrace);
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1; if (thirdPos == null) return list;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
//Add diagonal line from first to second //Limit amount of blocks you can place per row
list.addAll(getIntermediateBlocks(player, x1, y1, z1, x2, y2, z2)); int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
} else { int x1 = firstPos.getX(), x2 = secondPos.getX(), x3 = thirdPos.getX();
BlockPos firstPos = firstPosTable.get(player.getUUID()); int y1 = firstPos.getY(), y2 = secondPos.getY(), y3 = thirdPos.getY();
BlockPos secondPos = secondPosTable.get(player.getUUID()); int z1 = firstPos.getZ(), z2 = secondPos.getZ(), z3 = thirdPos.getZ();
BlockPos thirdPos = findThirdPos(player, firstPos, secondPos, skipRaytrace); //limit axis
if (thirdPos == null) return list; if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
//Limit amount of blocks you can place per row if (x3 - x1 >= axisLimit) x3 = x1 + axisLimit - 1;
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player); if (x1 - x3 >= axisLimit) x3 = x1 - axisLimit + 1;
if (y3 - y1 >= axisLimit) y3 = y1 + axisLimit - 1;
if (y1 - y3 >= axisLimit) y3 = y1 - axisLimit + 1;
if (z3 - z1 >= axisLimit) z3 = z1 + axisLimit - 1;
if (z1 - z3 >= axisLimit) z3 = z1 - axisLimit + 1;
int x1 = firstPos.getX(), x2 = secondPos.getX(), x3 = thirdPos.getX(); //Add diagonal line from first to third
int y1 = firstPos.getY(), y2 = secondPos.getY(), y3 = thirdPos.getY(); list.addAll(getFinalBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3));
int z1 = firstPos.getZ(), z2 = secondPos.getZ(), z3 = thirdPos.getZ(); }
//limit axis return list;
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1; }
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
if (x3 - x1 >= axisLimit) x3 = x1 + axisLimit - 1; //Finds the place of the second block pos
if (x1 - x3 >= axisLimit) x3 = x1 - axisLimit + 1; protected abstract BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace);
if (y3 - y1 >= axisLimit) y3 = y1 + axisLimit - 1;
if (y1 - y3 >= axisLimit) y3 = y1 - axisLimit + 1;
if (z3 - z1 >= axisLimit) z3 = z1 + axisLimit - 1;
if (z1 - z3 >= axisLimit) z3 = z1 - axisLimit + 1;
//Add diagonal line from first to third //Finds the place of the third block pos
list.addAll(getFinalBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3)); protected abstract BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace);
}
return list; //After first and second pos are known, we want to visualize the blocks in a way (like floor for cube)
} protected abstract List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2);
//Finds the place of the second block pos //After first, second and third pos are known, we want all the blocks
protected abstract BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace); protected abstract List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3);
//Finds the place of the third block pos //Finds height after floor has been chosen in buildmodes with 3 clicks
protected abstract BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace); public static BlockPos findHeight(EntityPlayer player, BlockPos secondPos, boolean skipRaytrace) {
Vec3d look = player.getLookVec();
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
//After first and second pos are known, we want to visualize the blocks in a way (like floor for cube) List<HeightCriteria> criteriaList = new ArrayList<>(3);
protected abstract List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2);
//After first, second and third pos are known, we want all the blocks //X
protected abstract List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3); Vec3d xBound = BuildModes.findXBound(secondPos.getX(), start, look);
criteriaList.add(new HeightCriteria(xBound, secondPos, start));
static class HeightCriteria { //Z
Vector3d planeBound; Vec3d zBound = BuildModes.findZBound(secondPos.getZ(), start, look);
Vector3d lineBound; criteriaList.add(new HeightCriteria(zBound, secondPos, start));
double distToLineSq;
double distToPlayerSq;
HeightCriteria(Vector3d planeBound, BlockPos secondPos, Vector3d start) { //Remove invalid criteria
this.planeBound = planeBound; int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
this.lineBound = toLongestLine(this.planeBound, secondPos); criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSqr();
this.distToPlayerSq = this.planeBound.subtract(start).lengthSqr();
}
//Make it from a plane into a line, on y axis only //If none are valid, return empty list of blocks
private Vector3d toLongestLine(Vector3d boundVec, BlockPos secondPos) { if (criteriaList.isEmpty()) return null;
BlockPos bound = new BlockPos(boundVec);
return new Vector3d(secondPos.getX(), bound.getY(), secondPos.getZ());
}
//check if its not behind the player and its not too close and not too far //If only 1 is valid, choose that one
//also check if raytrace from player to block does not intersect blocks HeightCriteria selected = criteriaList.get(0);
public boolean isValid(Vector3d start, Vector3d look, int reach, PlayerEntity player, boolean skipRaytrace) {
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq); //If multiple are valid, choose based on criteria
} if (criteriaList.size() > 1) {
} //Select the one that is closest (from wall position to its line counterpart)
for (int i = 1; i < criteriaList.size(); i++) {
HeightCriteria criteria = criteriaList.get(i);
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
//Both very close to line, choose closest to player
if (criteria.distToPlayerSq < selected.distToPlayerSq)
selected = criteria;
} else {
//Pick closest to line
if (criteria.distToLineSq < selected.distToLineSq)
selected = criteria;
}
}
}
return new BlockPos(selected.lineBound);
}
} }

View File

@@ -1,9 +1,9 @@
package nl.requios.effortlessbuilding.buildmode; package nl.requios.effortlessbuilding.buildmode;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList; import java.util.ArrayList;
@@ -13,74 +13,74 @@ import java.util.UUID;
public abstract class TwoClicksBuildMode extends BaseBuildMode { public abstract class TwoClicksBuildMode extends BaseBuildMode {
@Override @Override
public List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vector3d hitVec, boolean skipRaytrace) { public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable; Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
int rightClickNr = rightClickTable.get(player.getUUID()); int rightClickNr = rightClickTable.get(player.getUniqueID());
rightClickNr++; rightClickNr++;
rightClickTable.put(player.getUUID(), rightClickNr); rightClickTable.put(player.getUniqueID(), rightClickNr);
if (rightClickNr == 1) { if (rightClickNr == 1) {
//If clicking in air, reset and try again //If clicking in air, reset and try again
if (blockPos == null) { if (blockPos == null) {
rightClickTable.put(player.getUUID(), 0); rightClickTable.put(player.getUniqueID(), 0);
return list; return list;
} }
//First click, remember starting position //First click, remember starting position
firstPosTable.put(player.getUUID(), blockPos); firstPosTable.put(player.getUniqueID(), blockPos);
sideHitTable.put(player.getUUID(), sideHit); sideHitTable.put(player.getUniqueID(), sideHit);
hitVecTable.put(player.getUUID(), hitVec); hitVecTable.put(player.getUniqueID(), hitVec);
//Keep list empty, dont place any blocks yet //Keep list empty, dont place any blocks yet
} else { } else {
//Second click, place blocks //Second click, place blocks
list = findCoordinates(player, blockPos, skipRaytrace); list = findCoordinates(player, blockPos, skipRaytrace);
rightClickTable.put(player.getUUID(), 0); rightClickTable.put(player.getUniqueID(), 0);
} }
return list; return list;
} }
@Override @Override
public List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace) { public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
Dictionary<UUID, Integer> rightClickTable = player.level.isClientSide ? rightClickClientTable : rightClickServerTable; Dictionary<UUID, Integer> rightClickTable = player.world.isRemote ? rightClickClientTable : rightClickServerTable;
int rightClickNr = rightClickTable.get(player.getUUID()); int rightClickNr = rightClickTable.get(player.getUniqueID());
BlockPos firstPos = firstPosTable.get(player.getUUID()); BlockPos firstPos = firstPosTable.get(player.getUniqueID());
if (rightClickNr == 0) { if (rightClickNr == 0) {
if (blockPos != null) if (blockPos != null)
list.add(blockPos); list.add(blockPos);
} else { } else {
BlockPos secondPos = findSecondPos(player, firstPos, skipRaytrace); BlockPos secondPos = findSecondPos(player, firstPos, skipRaytrace);
if (secondPos == null) return list; if (secondPos == null) return list;
//Limit amount of blocks we can place per row //Limit amount of blocks we can place per row
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player); int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
int x1 = firstPos.getX(), x2 = secondPos.getX(); int x1 = firstPos.getX(), x2 = secondPos.getX();
int y1 = firstPos.getY(), y2 = secondPos.getY(); int y1 = firstPos.getY(), y2 = secondPos.getY();
int z1 = firstPos.getZ(), z2 = secondPos.getZ(); int z1 = firstPos.getZ(), z2 = secondPos.getZ();
//limit axis //limit axis
if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1; if (x2 - x1 >= axisLimit) x2 = x1 + axisLimit - 1;
if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1; if (x1 - x2 >= axisLimit) x2 = x1 - axisLimit + 1;
if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1; if (y2 - y1 >= axisLimit) y2 = y1 + axisLimit - 1;
if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1; if (y1 - y2 >= axisLimit) y2 = y1 - axisLimit + 1;
if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1; if (z2 - z1 >= axisLimit) z2 = z1 + axisLimit - 1;
if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1; if (z1 - z2 >= axisLimit) z2 = z1 - axisLimit + 1;
list.addAll(getAllBlocks(player, x1, y1, z1, x2, y2, z2)); list.addAll(getAllBlocks(player, x1, y1, z1, x2, y2, z2));
} }
return list; return list;
} }
//Finds the place of the second block pos based on criteria (floor must be on same height as first click, wall on same plane etc) //Finds the place of the second block pos based on criteria (floor must be on same height as first click, wall on same plane etc)
protected abstract BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace); protected abstract BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace);
//After first and second pos are known, we want all the blocks //After first and second pos are known, we want all the blocks
protected abstract List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2); protected abstract List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2);
} }

View File

@@ -1,89 +1,88 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import java.util.ArrayList; import java.util.*;
import java.util.List;
public class Circle extends TwoClicksBuildMode { public class Circle extends TwoClicksBuildMode {
public static List<BlockPos> getCircleBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { @Override
List<BlockPos> list = new ArrayList<>(); protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
float centerX = x1; @Override
float centerZ = z1; protected List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
}
//Adjust for CIRCLE_START public static List<BlockPos> getCircleBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) { List<BlockPos> list = new ArrayList<>();
centerX = x1 + (x2 - x1) / 2f;
centerZ = z1 + (z2 - z1) / 2f;
} else {
x1 = (int) (centerX - (x2 - centerX));
z1 = (int) (centerZ - (z2 - centerZ));
}
float radiusX = MathHelper.abs(x2 - centerX); float centerX = x1;
float radiusZ = MathHelper.abs(z2 - centerZ); float centerZ = z1;
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL) //Adjust for CIRCLE_START
addCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ); if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) {
else centerX = x1 + (x2 - x1) / 2f;
addHollowCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ); centerZ = z1 + (z2 - z1) / 2f;
} else {
x1 = (int) (centerX - (x2 - centerX));
z1 = (int) (centerZ - (z2 - centerZ));
}
return list; float radiusX = MathHelper.abs(x2 - centerX);
} float radiusZ = MathHelper.abs(z2 - centerZ);
public static void addCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) { if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ);
else
addHollowCircleBlocks(list, x1, y1, z1, x2, y2, z2, centerX, centerZ, radiusX, radiusZ);
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { return list;
}
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { public static void addCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) {
float distance = distance(l, n, centerX, centerZ); for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
if (distance < radius + 0.4f)
list.add(new BlockPos(l, y1, n));
}
}
}
public static void addHollowCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { float distance = distance(l, n, centerX, centerZ);
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
if (distance < radius + 0.4f)
list.add(new BlockPos(l, y1, n));
}
}
}
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { public static void addHollowCircleBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, float centerX, float centerZ, float radiusX, float radiusZ) {
float distance = distance(l, n, centerX, centerZ); for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
if (distance < radius + 0.4f && distance > radius - 0.6f)
list.add(new BlockPos(l, y1, n));
}
}
}
private static float distance(float x1, float z1, float x2, float z2) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
return MathHelper.sqrt((x2 - x1) * (x2 - x1) + (z2 - z1) * (z2 - z1));
}
public static float calculateEllipseRadius(float centerX, float centerZ, float radiusX, float radiusZ, int x, int z) { float distance = distance(l, n, centerX, centerZ);
//https://math.stackexchange.com/questions/432902/how-to-get-the-radius-of-an-ellipse-at-a-specific-angle-by-knowing-its-semi-majo float radius = calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, l, n);
float theta = (float) MathHelper.atan2(z - centerZ, x - centerX); if (distance < radius + 0.4f && distance > radius - 0.6f)
float part1 = radiusX * radiusX * MathHelper.sin(theta) * MathHelper.sin(theta); list.add(new BlockPos(l, y1, n));
float part2 = radiusZ * radiusZ * MathHelper.cos(theta) * MathHelper.cos(theta); }
return radiusX * radiusZ / MathHelper.sqrt(part1 + part2); }
} }
@Override private static float distance(float x1, float z1, float x2, float z2) {
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { return MathHelper.sqrt((x2 - x1) * (x2 - x1) + (z2 - z1) * (z2 - z1));
return Floor.findFloor(player, firstPos, skipRaytrace); }
}
@Override public static float calculateEllipseRadius(float centerX, float centerZ, float radiusX, float radiusZ, int x, int z) {
protected List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { //https://math.stackexchange.com/questions/432902/how-to-get-the-radius-of-an-ellipse-at-a-specific-angle-by-knowing-its-semi-majo
return getCircleBlocks(player, x1, y1, z1, x2, y2, z2); float theta = (float) MathHelper.atan2(z - centerZ, x - centerX);
} float part1 = radiusX * radiusX * MathHelper.sin(theta) * MathHelper.sin(theta);
float part2 = radiusZ * radiusZ * MathHelper.cos(theta) * MathHelper.cos(theta);
return radiusX * radiusZ / MathHelper.sqrt(part1 + part2);
}
} }

View File

@@ -1,101 +1,104 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList; import java.util.*;
import java.util.List;
public class Cube extends ThreeClicksBuildMode { public class Cube extends ThreeClicksBuildMode {
public static List<BlockPos> getFloorBlocksUsingCubeFill(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { @Override
List<BlockPos> list = new ArrayList<>(); protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
if (ModeOptions.getCubeFill() == ModeOptions.ActionEnum.CUBE_SKELETON) @Override
Floor.addHollowFloorBlocks(list, x1, x2, y1, z1, z2); protected BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
else return findHeight(player, secondPos, skipRaytrace);
Floor.addFloorBlocks(list, x1, x2, y1, z1, z2); }
return list; @Override
} protected List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getFloorBlocksUsingCubeFill(player, x1, y1, z1, x2, y2, z2);
}
public static List<BlockPos> getCubeBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { @Override
List<BlockPos> list = new ArrayList<>(); protected List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
return getCubeBlocks(player, x1, y1, z1, x3, y3, z3);
}
switch (ModeOptions.getCubeFill()) { public static List<BlockPos> getFloorBlocksUsingCubeFill(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
case CUBE_FULL: List<BlockPos> list = new ArrayList<>();
addCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
case CUBE_HOLLOW:
addHollowCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
case CUBE_SKELETON:
addSkeletonCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
}
return list; if (ModeOptions.getCubeFill() == ModeOptions.ActionEnum.CUBE_SKELETON)
} Floor.addHollowFloorBlocks(list, x1, x2, y1, z1, z2);
else
Floor.addFloorBlocks(list, x1, x2, y1, z1, z2);
public static void addCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) { return list;
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { }
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { public static List<BlockPos> getCubeBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
List<BlockPos> list = new ArrayList<>();
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) { switch (ModeOptions.getCubeFill()) {
list.add(new BlockPos(l, m, n)); case CUBE_FULL:
} addCubeBlocks(list, x1, x2, y1, y2, z1, z2);
} break;
} case CUBE_HOLLOW:
} addHollowCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
case CUBE_SKELETON:
addSkeletonCubeBlocks(list, x1, x2, y1, y2, z1, z2);
break;
}
public static void addHollowCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) { return list;
Wall.addXWallBlocks(list, x1, y1, y2, z1, z2); }
Wall.addXWallBlocks(list, x2, y1, y2, z1, z2);
Wall.addZWallBlocks(list, x1, x2, y1, y2, z1); public static void addCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
Wall.addZWallBlocks(list, x1, x2, y1, y2, z2); for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
Floor.addFloorBlocks(list, x1, x2, y1, z1, z2); for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
Floor.addFloorBlocks(list, x1, x2, y2, z1, z2);
}
public static void addSkeletonCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) { for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
Line.addXLineBlocks(list, x1, x2, y1, z1); list.add(new BlockPos(l, m, n));
Line.addXLineBlocks(list, x1, x2, y1, z2); }
Line.addXLineBlocks(list, x1, x2, y2, z1); }
Line.addXLineBlocks(list, x1, x2, y2, z2); }
}
Line.addYLineBlocks(list, y1, y2, x1, z1); public static void addHollowCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
Line.addYLineBlocks(list, y1, y2, x1, z2); Wall.addXWallBlocks(list, x1, y1, y2, z1, z2);
Line.addYLineBlocks(list, y1, y2, x2, z1); Wall.addXWallBlocks(list, x2, y1, y2, z1, z2);
Line.addYLineBlocks(list, y1, y2, x2, z2);
Line.addZLineBlocks(list, z1, z2, x1, y1); Wall.addZWallBlocks(list, x1, x2, y1, y2, z1);
Line.addZLineBlocks(list, z1, z2, x1, y2); Wall.addZWallBlocks(list, x1, x2, y1, y2, z2);
Line.addZLineBlocks(list, z1, z2, x2, y1);
Line.addZLineBlocks(list, z1, z2, x2, y2);
}
@Override Floor.addFloorBlocks(list, x1, x2, y1, z1, z2);
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { Floor.addFloorBlocks(list, x1, x2, y2, z1, z2);
return Floor.findFloor(player, firstPos, skipRaytrace); }
}
@Override public static void addSkeletonCubeBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z1, int z2) {
protected BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { Line.addXLineBlocks(list, x1, x2, y1, z1);
return findHeight(player, secondPos, skipRaytrace); Line.addXLineBlocks(list, x1, x2, y1, z2);
} Line.addXLineBlocks(list, x1, x2, y2, z1);
Line.addXLineBlocks(list, x1, x2, y2, z2);
@Override Line.addYLineBlocks(list, y1, y2, x1, z1);
protected List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { Line.addYLineBlocks(list, y1, y2, x1, z2);
return getFloorBlocksUsingCubeFill(player, x1, y1, z1, x2, y2, z2); Line.addYLineBlocks(list, y1, y2, x2, z1);
} Line.addYLineBlocks(list, y1, y2, x2, z2);
@Override Line.addZLineBlocks(list, z1, z2, x1, y1);
protected List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { Line.addZLineBlocks(list, z1, z2, x1, y2);
return getCubeBlocks(player, x1, y1, z1, x3, y3, z3); Line.addZLineBlocks(list, z1, z2, x2, y1);
} Line.addZLineBlocks(list, z1, z2, x2, y2);
}
} }

View File

@@ -1,6 +1,6 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
@@ -9,42 +9,42 @@ import java.util.List;
public class Cylinder extends ThreeClicksBuildMode { public class Cylinder extends ThreeClicksBuildMode {
public static List<BlockPos> getCylinderBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { @Override
List<BlockPos> list = new ArrayList<>(); public BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
//Get circle blocks (using CIRCLE_START and FILL options built-in) @Override
List<BlockPos> circleBlocks = Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2); public BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
int lowest = Math.min(y1, y3); @Override
int highest = Math.max(y1, y3); public List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
}
//Copy circle on y axis @Override
for (int y = lowest; y <= highest; y++) { public List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
for (BlockPos blockPos : circleBlocks) { return getCylinderBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ())); }
}
}
return list; public static List<BlockPos> getCylinderBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
} List<BlockPos> list = new ArrayList<>();
@Override //Get circle blocks (using CIRCLE_START and FILL options built-in)
public BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { List<BlockPos> circleBlocks = Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override int lowest = Math.min(y1, y3);
public BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { int highest = Math.max(y1, y3);
return findHeight(player, secondPos, skipRaytrace);
}
@Override //Copy circle on y axis
public List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { for (int y = lowest; y <= highest; y++) {
return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2); for (BlockPos blockPos : circleBlocks) {
} list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ()));
}
}
@Override return list;
public List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { }
return getCylinderBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
} }

View File

@@ -1,53 +1,54 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DiagonalLine extends ThreeClicksBuildMode { public class DiagonalLine extends ThreeClicksBuildMode {
//Add diagonal line from first to second @Override
public static List<BlockPos> getDiagonalLineBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, float sampleMultiplier) { protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); return Floor.findFloor(player, firstPos, skipRaytrace);
}
Vector3d first = new Vector3d(x1, y1, z1).add(0.5, 0.5, 0.5); @Override
Vector3d second = new Vector3d(x2, y2, z2).add(0.5, 0.5, 0.5); protected BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
int iterations = (int) Math.ceil(first.distanceTo(second) * sampleMultiplier); @Override
for (double t = 0; t <= 1.0; t += 1.0 / iterations) { protected List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
Vector3d lerp = first.add(second.subtract(first).scale(t)); //Add diagonal line from first to second
BlockPos candidate = new BlockPos(lerp); return getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 10);
//Only add if not equal to the last in the list }
if (list.isEmpty() || !list.get(list.size() - 1).equals(candidate))
list.add(candidate);
}
return list; @Override
} protected List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
//Add diagonal line from first to third
return getDiagonalLineBlocks(player, x1, y1, z1, x3, y3, z3, 10);
}
@Override //Add diagonal line from first to second
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { public static List<BlockPos> getDiagonalLineBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, float sampleMultiplier) {
return Floor.findFloor(player, firstPos, skipRaytrace); List<BlockPos> list = new ArrayList<>();
}
@Override Vec3d first = new Vec3d(x1, y1, z1).add(0.5, 0.5, 0.5);
protected BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { Vec3d second = new Vec3d(x2, y2, z2).add(0.5, 0.5, 0.5);
return findHeight(player, secondPos, skipRaytrace);
}
@Override int iterations = (int) Math.ceil(first.distanceTo(second) * sampleMultiplier);
protected List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { for (double t = 0; t <= 1.0; t += 1.0/iterations) {
//Add diagonal line from first to second Vec3d lerp = first.add(second.subtract(first).scale(t));
return getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 10); BlockPos candidate = new BlockPos(lerp);
} //Only add if not equal to the last in the list
if (list.isEmpty() || !list.get(list.size() - 1).equals(candidate))
list.add(candidate);
}
@Override return list;
protected List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { }
//Add diagonal line from first to third
return getDiagonalLineBlocks(player, x1, y1, z1, x3, y3, z3, 10);
}
} }

View File

@@ -1,51 +1,52 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DiagonalWall extends ThreeClicksBuildMode { public class DiagonalWall extends ThreeClicksBuildMode {
//Add diagonal wall from first to second @Override
public static List<BlockPos> getDiagonalWallBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); return Floor.findFloor(player, firstPos, skipRaytrace);
}
//Get diagonal line blocks @Override
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1); protected BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
int lowest = Math.min(y1, y3); @Override
int highest = Math.max(y1, y3); protected List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
return DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1);
}
//Copy diagonal line on y axis @Override
for (int y = lowest; y <= highest; y++) { protected List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
for (BlockPos blockPos : diagonalLineBlocks) { return getDiagonalWallBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ())); }
}
}
return list; //Add diagonal wall from first to second
} public static List<BlockPos> getDiagonalWallBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
List<BlockPos> list = new ArrayList<>();
@Override //Get diagonal line blocks
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1);
return Floor.findFloor(player, firstPos, skipRaytrace);
}
@Override int lowest = Math.min(y1, y3);
protected BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { int highest = Math.max(y1, y3);
return findHeight(player, secondPos, skipRaytrace);
}
@Override //Copy diagonal line on y axis
protected List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { for (int y = lowest; y <= highest; y++) {
return DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y2, z2, 1); for (BlockPos blockPos : diagonalLineBlocks) {
} list.add(new BlockPos(blockPos.getX(), y, blockPos.getZ()));
}
}
@Override return list;
protected List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { }
return getDiagonalWallBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
} }

View File

@@ -1,94 +1,93 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList; import java.util.*;
import java.util.List;
public class Floor extends TwoClicksBuildMode { public class Floor extends TwoClicksBuildMode {
public static BlockPos findFloor(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { static class Criteria {
Vector3d look = BuildModes.getPlayerLookVec(player); Vec3d planeBound;
Vector3d start = new Vector3d(player.getX(), player.getY() + player.getEyeHeight(), player.getZ()); double distToPlayerSq;
List<Criteria> criteriaList = new ArrayList<>(3); Criteria(Vec3d planeBound, Vec3d start) {
this.planeBound = planeBound;
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
}
//Y //check if its not behind the player and its not too close and not too far
Vector3d yBound = BuildModes.findYBound(firstPos.getY(), start, look); //also check if raytrace from player to block does not intersect blocks
criteriaList.add(new Criteria(yBound, start)); public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
//Remove invalid criteria return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq);
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach }
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace)); }
//If none are valid, return empty list of blocks @Override
if (criteriaList.isEmpty()) return null; protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
return findFloor(player, firstPos, skipRaytrace);
}
//Then only 1 can be valid, return that one public static BlockPos findFloor(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
Criteria selected = criteriaList.get(0); Vec3d look = player.getLookVec();
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
return new BlockPos(selected.planeBound); List<Criteria> criteriaList = new ArrayList<>(3);
}
public static List<BlockPos> getFloorBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { //Y
List<BlockPos> list = new ArrayList<>(); Vec3d yBound = BuildModes.findYBound(firstPos.getY(), start, look);
criteriaList.add(new Criteria(yBound, start));
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL) //Remove invalid criteria
addFloorBlocks(list, x1, x2, y1, z1, z2); int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
else criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
addHollowFloorBlocks(list, x1, x2, y1, z1, z2);
return list; //If none are valid, return empty list of blocks
} if (criteriaList.isEmpty()) return null;
public static void addFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) { //Then only 1 can be valid, return that one
Criteria selected = criteriaList.get(0);
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { return new BlockPos(selected.planeBound);
}
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { @Override
protected List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
list.add(new BlockPos(l, y, n)); public static List<BlockPos> getFloorBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
} List<BlockPos> list = new ArrayList<>();
}
}
public static void addHollowFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) { if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
Line.addXLineBlocks(list, x1, x2, y, z1); addFloorBlocks(list, x1, x2, y1, z1, z2);
Line.addXLineBlocks(list, x1, x2, y, z2); else
Line.addZLineBlocks(list, z1, z2, x1, y); addHollowFloorBlocks(list, x1, x2, y1, z1, z2);
Line.addZLineBlocks(list, z1, z2, x2, y);
}
@Override return list;
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { }
return findFloor(player, firstPos, skipRaytrace);
}
@Override public static void addFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) {
protected List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
static class Criteria { for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
Vector3d planeBound;
double distToPlayerSq;
Criteria(Vector3d planeBound, Vector3d start) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
this.planeBound = planeBound;
this.distToPlayerSq = this.planeBound.subtract(start).lengthSqr();
}
//check if its not behind the player and its not too close and not too far list.add(new BlockPos(l, y, n));
//also check if raytrace from player to block does not intersect blocks }
public boolean isValid(Vector3d start, Vector3d look, int reach, PlayerEntity player, boolean skipRaytrace) { }
}
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq); public static void addHollowFloorBlocks(List<BlockPos> list, int x1, int x2, int y, int z1, int z2) {
} Line.addXLineBlocks(list, x1, x2, y, z1);
} Line.addXLineBlocks(list, x1, x2, y, z2);
Line.addZLineBlocks(list, z1, z2, x1, y);
Line.addZLineBlocks(list, z1, z2, x2, y);
}
} }

View File

@@ -1,8 +1,8 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
@@ -12,136 +12,136 @@ import java.util.List;
public class Line extends TwoClicksBuildMode { public class Line extends TwoClicksBuildMode {
public static BlockPos findLine(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { static class Criteria {
Vector3d look = BuildModes.getPlayerLookVec(player); Vec3d planeBound;
Vector3d start = new Vector3d(player.getX(), player.getY() + player.getEyeHeight(), player.getZ()); Vec3d lineBound;
double distToLineSq;
double distToPlayerSq;
List<Criteria> criteriaList = new ArrayList<>(3); Criteria(Vec3d planeBound, BlockPos firstPos, Vec3d start) {
this.planeBound = planeBound;
this.lineBound = toLongestLine(this.planeBound, firstPos);
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSquared();
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
}
//X //Make it from a plane into a line
Vector3d xBound = BuildModes.findXBound(firstPos.getX(), start, look); //Select the axis that is longest
criteriaList.add(new Criteria(xBound, firstPos, start)); private Vec3d toLongestLine(Vec3d boundVec, BlockPos firstPos) {
BlockPos bound = new BlockPos(boundVec);
//Y BlockPos firstToSecond = bound.subtract(firstPos);
Vector3d yBound = BuildModes.findYBound(firstPos.getY(), start, look); firstToSecond = new BlockPos(Math.abs(firstToSecond.getX()), Math.abs(firstToSecond.getY()), Math.abs(firstToSecond.getZ()));
criteriaList.add(new Criteria(yBound, firstPos, start)); int longest = Math.max(firstToSecond.getX(), Math.max(firstToSecond.getY(), firstToSecond.getZ()));
if (longest == firstToSecond.getX()) {
return new Vec3d(bound.getX(), firstPos.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getY()) {
return new Vec3d(firstPos.getX(), bound.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getZ()) {
return new Vec3d(firstPos.getX(), firstPos.getY(), bound.getZ());
}
return null;
}
//Z //check if its not behind the player and its not too close and not too far
Vector3d zBound = BuildModes.findZBound(firstPos.getZ(), start, look); //also check if raytrace from player to block does not intersect blocks
criteriaList.add(new Criteria(zBound, firstPos, start)); public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
//Remove invalid criteria return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq);
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach }
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
//If none are valid, return empty list of blocks }
if (criteriaList.isEmpty()) return null;
//If only 1 is valid, choose that one @Override
Criteria selected = criteriaList.get(0); protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
return findLine(player, firstPos, skipRaytrace);
}
//If multiple are valid, choose based on criteria public static BlockPos findLine(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
if (criteriaList.size() > 1) { Vec3d look = player.getLookVec();
//Select the one that is closest (from wall position to its line counterpart) Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
for (int i = 1; i < criteriaList.size(); i++) {
Criteria criteria = criteriaList.get(i);
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
//Both very close to line, choose closest to player
if (criteria.distToPlayerSq < selected.distToPlayerSq)
selected = criteria;
} else {
//Pick closest to line
if (criteria.distToLineSq < selected.distToLineSq)
selected = criteria;
}
}
} List<Criteria> criteriaList = new ArrayList<>(3);
return new BlockPos(selected.lineBound); //X
} Vec3d xBound = BuildModes.findXBound(firstPos.getX(), start, look);
criteriaList.add(new Criteria(xBound, firstPos, start));
public static List<BlockPos> getLineBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { //Y
List<BlockPos> list = new ArrayList<>(); Vec3d yBound = BuildModes.findYBound(firstPos.getY(), start, look);
criteriaList.add(new Criteria(yBound, firstPos, start));
if (x1 != x2) { //Z
addXLineBlocks(list, x1, x2, y1, z1); Vec3d zBound = BuildModes.findZBound(firstPos.getZ(), start, look);
} else if (y1 != y2) { criteriaList.add(new Criteria(zBound, firstPos, start));
addYLineBlocks(list, y1, y2, x1, z1);
} else {
addZLineBlocks(list, z1, z2, x1, y1);
}
return list; //Remove invalid criteria
} int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
public static void addXLineBlocks(List<BlockPos> list, int x1, int x2, int y, int z) { //If none are valid, return empty list of blocks
for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) { if (criteriaList.isEmpty()) return null;
list.add(new BlockPos(x, y, z));
}
}
public static void addYLineBlocks(List<BlockPos> list, int y1, int y2, int x, int z) { //If only 1 is valid, choose that one
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) { Criteria selected = criteriaList.get(0);
list.add(new BlockPos(x, y, z));
}
}
public static void addZLineBlocks(List<BlockPos> list, int z1, int z2, int x, int y) { //If multiple are valid, choose based on criteria
for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) { if (criteriaList.size() > 1) {
list.add(new BlockPos(x, y, z)); //Select the one that is closest (from wall position to its line counterpart)
} for (int i = 1; i < criteriaList.size(); i++) {
} Criteria criteria = criteriaList.get(i);
if (criteria.distToLineSq < 2.0 && selected.distToLineSq < 2.0) {
//Both very close to line, choose closest to player
if (criteria.distToPlayerSq < selected.distToPlayerSq)
selected = criteria;
} else {
//Pick closest to line
if (criteria.distToLineSq < selected.distToLineSq)
selected = criteria;
}
}
@Override }
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) {
return findLine(player, firstPos, skipRaytrace);
}
@Override return new BlockPos(selected.lineBound);
protected List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { }
return getLineBlocks(player, x1, y1, z1, x2, y2, z2);
}
static class Criteria { @Override
Vector3d planeBound; protected List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
Vector3d lineBound; return getLineBlocks(player, x1, y1, z1, x2, y2, z2);
double distToLineSq; }
double distToPlayerSq;
Criteria(Vector3d planeBound, BlockPos firstPos, Vector3d start) { public static List<BlockPos> getLineBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
this.planeBound = planeBound; List<BlockPos> list = new ArrayList<>();
this.lineBound = toLongestLine(this.planeBound, firstPos);
this.distToLineSq = this.lineBound.subtract(this.planeBound).lengthSqr();
this.distToPlayerSq = this.planeBound.subtract(start).lengthSqr();
}
//Make it from a plane into a line if (x1 != x2) {
//Select the axis that is longest addXLineBlocks(list, x1, x2, y1, z1);
private Vector3d toLongestLine(Vector3d boundVec, BlockPos firstPos) { } else if (y1 != y2) {
BlockPos bound = new BlockPos(boundVec); addYLineBlocks(list, y1, y2, x1, z1);
} else {
addZLineBlocks(list, z1, z2, x1, y1);
}
BlockPos firstToSecond = bound.subtract(firstPos); return list;
firstToSecond = new BlockPos(Math.abs(firstToSecond.getX()), Math.abs(firstToSecond.getY()), Math.abs(firstToSecond.getZ())); }
int longest = Math.max(firstToSecond.getX(), Math.max(firstToSecond.getY(), firstToSecond.getZ()));
if (longest == firstToSecond.getX()) {
return new Vector3d(bound.getX(), firstPos.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getY()) {
return new Vector3d(firstPos.getX(), bound.getY(), firstPos.getZ());
}
if (longest == firstToSecond.getZ()) {
return new Vector3d(firstPos.getX(), firstPos.getY(), bound.getZ());
}
return null;
}
//check if its not behind the player and its not too close and not too far public static void addXLineBlocks(List<BlockPos> list, int x1, int x2, int y, int z) {
//also check if raytrace from player to block does not intersect blocks for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) {
public boolean isValid(Vector3d start, Vector3d look, int reach, PlayerEntity player, boolean skipRaytrace) { list.add(new BlockPos(x, y, z));
}
}
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, lineBound, planeBound, distToPlayerSq); public static void addYLineBlocks(List<BlockPos> list, int y1, int y2, int x, int z) {
} for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
list.add(new BlockPos(x, y, z));
}
}
} public static void addZLineBlocks(List<BlockPos> list, int z1, int z2, int x, int y) {
for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) {
list.add(new BlockPos(x, y, z));
}
}
} }

View File

@@ -1,41 +1,41 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.IBuildMode; import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Normal implements IBuildMode { public class Normal implements IBuildMode {
@Override @Override
public void initialize(PlayerEntity player) { public void initialize(EntityPlayer player) {
} }
@Override @Override
public List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vector3d hitVec, boolean skipRaytrace) { public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos); if (blockPos != null) list.add(blockPos);
return list; return list;
} }
@Override @Override
public List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace) { public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos); if (blockPos != null) list.add(blockPos);
return list; return list;
} }
@Override @Override
public Direction getSideHit(PlayerEntity player) { public EnumFacing getSideHit(EntityPlayer player) {
return null; return null;
} }
@Override @Override
public Vector3d getHitVec(PlayerEntity player) { public Vec3d getHitVec(EntityPlayer player) {
return null; return null;
} }
} }

View File

@@ -1,41 +1,41 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.IBuildMode; import nl.requios.effortlessbuilding.buildmode.IBuildMode;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class NormalPlus implements IBuildMode { public class NormalPlus implements IBuildMode {
@Override @Override
public void initialize(PlayerEntity player) { public void initialize(EntityPlayer player) {
} }
@Override @Override
public List<BlockPos> onRightClick(PlayerEntity player, BlockPos blockPos, Direction sideHit, Vector3d hitVec, boolean skipRaytrace) { public List<BlockPos> onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos); if (blockPos != null) list.add(blockPos);
return list; return list;
} }
@Override @Override
public List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos, boolean skipRaytrace) { public List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); List<BlockPos> list = new ArrayList<>();
if (blockPos != null) list.add(blockPos); if (blockPos != null) list.add(blockPos);
return list; return list;
} }
@Override @Override
public Direction getSideHit(PlayerEntity player) { public EnumFacing getSideHit(EntityPlayer player) {
return null; return null;
} }
@Override @Override
public Vector3d getHitVec(PlayerEntity player) { public Vec3d getHitVec(EntityPlayer player) {
return null; return null;
} }
} }

View File

@@ -1,6 +1,6 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.ThreeClicksBuildMode;
@@ -11,85 +11,85 @@ import java.util.List;
public class SlopeFloor extends ThreeClicksBuildMode { public class SlopeFloor extends ThreeClicksBuildMode {
//Add slope floor from first to second @Override
public static List<BlockPos> getSlopeFloorBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
List<BlockPos> list = new ArrayList<>(); return Floor.findFloor(player, firstPos, skipRaytrace);
}
int axisLimit = ReachHelper.getMaxBlocksPerAxis(player); @Override
protected BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
//Determine whether to use x or z axis to slope up @Override
boolean onXAxis = true; protected List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
return Floor.getFloorBlocks(player, x1, y1, z1, x2, y2, z2);
}
int xLength = Math.abs(x2 - x1); @Override
int zLength = Math.abs(z2 - z1); protected List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
return getSlopeFloorBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
if (ModeOptions.getRaisedEdge() == ModeOptions.ActionEnum.SHORT_EDGE) { //Add slope floor from first to second
//Slope along short edge public static List<BlockPos> getSlopeFloorBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
if (zLength > xLength) onXAxis = false; List<BlockPos> list = new ArrayList<>();
} else {
//Slope along long edge
if (zLength <= xLength) onXAxis = false;
}
if (onXAxis) { int axisLimit = ReachHelper.getMaxBlocksPerAxis(player);
//Along X goes up
//Get diagonal line blocks //Determine whether to use x or z axis to slope up
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y3, z1, 1f); boolean onXAxis = true;
//Limit amount of blocks we can place int xLength = Math.abs(x2 - x1);
int lowest = Math.min(z1, z2); int zLength = Math.abs(z2 - z1);
int highest = Math.max(z1, z2);
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1; if (ModeOptions.getRaisedEdge() == ModeOptions.ActionEnum.SHORT_EDGE) {
//Slope along short edge
if (zLength > xLength) onXAxis = false;
} else {
//Slope along long edge
if (zLength <= xLength) onXAxis = false;
}
//Copy diagonal line on x axis if (onXAxis) {
for (int z = lowest; z <= highest; z++) { //Along X goes up
for (BlockPos blockPos : diagonalLineBlocks) {
list.add(new BlockPos(blockPos.getX(), blockPos.getY(), z));
}
}
} else { //Get diagonal line blocks
//Along Z goes up List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x2, y3, z1, 1f);
//Get diagonal line blocks //Limit amount of blocks we can place
List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x1, y3, z2, 1f); int lowest = Math.min(z1, z2);
int highest = Math.max(z1, z2);
//Limit amount of blocks we can place if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
int lowest = Math.min(x1, x2);
int highest = Math.max(x1, x2);
if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1; //Copy diagonal line on x axis
for (int z = lowest; z <= highest; z++) {
for (BlockPos blockPos : diagonalLineBlocks) {
list.add(new BlockPos(blockPos.getX(), blockPos.getY(), z));
}
}
//Copy diagonal line on x axis } else {
for (int x = lowest; x <= highest; x++) { //Along Z goes up
for (BlockPos blockPos : diagonalLineBlocks) {
list.add(new BlockPos(x, blockPos.getY(), blockPos.getZ()));
}
}
}
return list; //Get diagonal line blocks
} List<BlockPos> diagonalLineBlocks = DiagonalLine.getDiagonalLineBlocks(player, x1, y1, z1, x1, y3, z2, 1f);
@Override //Limit amount of blocks we can place
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { int lowest = Math.min(x1, x2);
return Floor.findFloor(player, firstPos, skipRaytrace); int highest = Math.max(x1, x2);
}
@Override if (highest - lowest >= axisLimit) highest = lowest + axisLimit - 1;
protected BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
return findHeight(player, secondPos, skipRaytrace);
}
@Override //Copy diagonal line on x axis
protected List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { for (int x = lowest; x <= highest; x++) {
return Floor.getFloorBlocks(player, x1, y1, z1, x2, y2, z2); for (BlockPos blockPos : diagonalLineBlocks) {
} list.add(new BlockPos(x, blockPos.getY(), blockPos.getZ()));
}
}
}
@Override return list;
protected List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { }
return getSlopeFloorBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
} }

View File

@@ -1,6 +1,6 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
@@ -11,100 +11,100 @@ import java.util.List;
public class Sphere extends ThreeClicksBuildMode { public class Sphere extends ThreeClicksBuildMode {
public static List<BlockPos> getSphereBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { @Override
List<BlockPos> list = new ArrayList<>(); public BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
return Floor.findFloor(player, firstPos, skipRaytrace);
}
float centerX = x1; @Override
float centerY = y1; public BlockPos findThirdPos(EntityPlayer player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) {
float centerZ = z1; return findHeight(player, secondPos, skipRaytrace);
}
//Adjust for CIRCLE_START @Override
if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) { public List<BlockPos> getIntermediateBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
centerX = x1 + (x2 - x1) / 2f; return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
centerY = y1 + (y3 - y1) / 2f; }
centerZ = z1 + (z2 - z1) / 2f;
} else {
x1 = (int) (centerX - (x2 - centerX));
y1 = (int) (centerY - (y3 - centerY));
z1 = (int) (centerZ - (z2 - centerZ));
}
float radiusX = MathHelper.abs(x2 - centerX); @Override
float radiusY = MathHelper.abs(y3 - centerY); public List<BlockPos> getFinalBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
float radiusZ = MathHelper.abs(z2 - centerZ); return getSphereBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL) public static List<BlockPos> getSphereBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) {
addSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ); List<BlockPos> list = new ArrayList<>();
else
addHollowSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
return list; float centerX = x1;
} float centerY = y1;
float centerZ = z1;
public static void addSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, //Adjust for CIRCLE_START
float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) { if (ModeOptions.getCircleStart() == ModeOptions.ActionEnum.CIRCLE_START_CORNER) {
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { centerX = x1 + (x2 - x1) / 2f;
centerY = y1 + (y3 - y1) / 2f;
centerZ = z1 + (z2 - z1) / 2f;
} else {
x1 = (int) (centerX - (x2 - centerX));
y1 = (int) (centerY - (y3 - centerY));
z1 = (int) (centerZ - (z2 - centerZ));
}
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { float radiusX = MathHelper.abs(x2 - centerX);
float radiusY = MathHelper.abs(y3 - centerY);
float radiusZ = MathHelper.abs(z2 - centerZ);
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) { if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
else
addHollowSphereBlocks(list, x1, y1, z1, x3, y3, z3, centerX, centerY, centerZ, radiusX, radiusY, radiusZ);
float distance = distance(l, m, n, centerX, centerY, centerZ); return list;
float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n); }
if (distance < radius + 0.4f)
list.add(new BlockPos(l, m, n));
}
}
}
}
public static void addHollowSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2, public static void addSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2,
float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) { float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) {
for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) { for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
float distance = distance(l, m, n, centerX, centerY, centerZ); float distance = distance(l, m, n, centerX, centerY, centerZ);
float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n); float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n);
if (distance < radius + 0.4f && distance > radius - 0.6f) if (distance < radius + 0.4f)
list.add(new BlockPos(l, m, n)); list.add(new BlockPos(l, m, n));
} }
} }
} }
} }
private static float distance(float x1, float y1, float z1, float x2, float y2, float z2) { public static void addHollowSphereBlocks(List<BlockPos> list, int x1, int y1, int z1, int x2, int y2, int z2,
return MathHelper.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1)); float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ) {
} for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) {
public static float calculateSpheroidRadius(float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ, int x, int y, int z) { for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) {
//Twice ellipse radius
float radiusXZ = Circle.calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, x, z);
//TODO project x to plane for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) {
return Circle.calculateEllipseRadius(centerX, centerY, radiusXZ, radiusY, x, y); float distance = distance(l, m, n, centerX, centerY, centerZ);
} float radius = calculateSpheroidRadius(centerX, centerY, centerZ, radiusX, radiusY, radiusZ, l, m, n);
if (distance < radius + 0.4f && distance > radius - 0.6f)
list.add(new BlockPos(l, m, n));
}
}
}
}
@Override private static float distance(float x1, float y1, float z1, float x2, float y2, float z2) {
public BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { return MathHelper.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) + (z2 - z1) * (z2 - z1));
return Floor.findFloor(player, firstPos, skipRaytrace); }
}
@Override public static float calculateSpheroidRadius(float centerX, float centerY, float centerZ, float radiusX, float radiusY, float radiusZ, int x, int y, int z) {
public BlockPos findThirdPos(PlayerEntity player, BlockPos firstPos, BlockPos secondPos, boolean skipRaytrace) { //Twice ellipse radius
return findHeight(player, secondPos, skipRaytrace); float radiusXZ = Circle.calculateEllipseRadius(centerX, centerZ, radiusX, radiusZ, x, z);
}
@Override //TODO project x to plane
public List<BlockPos> getIntermediateBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) {
return Circle.getCircleBlocks(player, x1, y1, z1, x2, y2, z2);
}
@Override return Circle.calculateEllipseRadius(centerX, centerY, radiusXZ, radiusY, x, y);
public List<BlockPos> getFinalBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2, int x3, int y3, int z3) { }
return getSphereBlocks(player, x1, y1, z1, x2, y2, z2, x3, y3, z3);
}
} }

View File

@@ -1,135 +1,134 @@
package nl.requios.effortlessbuilding.buildmode.buildmodes; package nl.requios.effortlessbuilding.buildmode.buildmodes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode; import nl.requios.effortlessbuilding.buildmode.TwoClicksBuildMode;
import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.util.ArrayList; import java.util.*;
import java.util.List;
public class Wall extends TwoClicksBuildMode { public class Wall extends TwoClicksBuildMode {
public static BlockPos findWall(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { static class Criteria {
Vector3d look = BuildModes.getPlayerLookVec(player); Vec3d planeBound;
Vector3d start = new Vector3d(player.getX(), player.getY() + player.getEyeHeight(), player.getZ()); double distToPlayerSq;
double angle;
List<Criteria> criteriaList = new ArrayList<>(3); Criteria(Vec3d planeBound, BlockPos firstPos, Vec3d start, Vec3d look) {
this.planeBound = planeBound;
this.distToPlayerSq = this.planeBound.subtract(start).lengthSquared();
Vec3d wall = this.planeBound.subtract(new Vec3d(firstPos));
this.angle = wall.x * look.x + wall.z * look.z; //dot product ignoring y (looking up/down should not affect this angle)
}
//X //check if its not behind the player and its not too close and not too far
Vector3d xBound = BuildModes.findXBound(firstPos.getX(), start, look); //also check if raytrace from player to block does not intersect blocks
criteriaList.add(new Criteria(xBound, firstPos, start, look)); public boolean isValid(Vec3d start, Vec3d look, int reach, EntityPlayer player, boolean skipRaytrace) {
//Z return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq);
Vector3d zBound = BuildModes.findZBound(firstPos.getZ(), start, look); }
criteriaList.add(new Criteria(zBound, firstPos, start, look)); }
//Remove invalid criteria @Override
int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach protected BlockPos findSecondPos(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace)); return findWall(player, firstPos, skipRaytrace);
}
//If none are valid, return empty list of blocks public static BlockPos findWall(EntityPlayer player, BlockPos firstPos, boolean skipRaytrace) {
if (criteriaList.isEmpty()) return null; Vec3d look = player.getLookVec();
Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
//If only 1 is valid, choose that one List<Criteria> criteriaList = new ArrayList<>(3);
Criteria selected = criteriaList.get(0);
//If multiple are valid, choose based on criteria //X
if (criteriaList.size() > 1) { Vec3d xBound = BuildModes.findXBound(firstPos.getX(), start, look);
//Select the one that is closest criteriaList.add(new Criteria(xBound, firstPos, start, look));
//Limit the angle to not be too extreme
for (int i = 1; i < criteriaList.size(); i++) {
Criteria criteria = criteriaList.get(i);
if (criteria.distToPlayerSq < selected.distToPlayerSq && Math.abs(criteria.angle) - Math.abs(selected.angle) < 3)
selected = criteria;
}
}
return new BlockPos(selected.planeBound); //Z
} Vec3d zBound = BuildModes.findZBound(firstPos.getZ(), start, look);
criteriaList.add(new Criteria(zBound, firstPos, start, look));
public static List<BlockPos> getWallBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) { //Remove invalid criteria
List<BlockPos> list = new ArrayList<>(); int reach = ReachHelper.getPlacementReach(player) * 4; //4 times as much as normal placement reach
criteriaList.removeIf(criteria -> !criteria.isValid(start, look, reach, player, skipRaytrace));
if (x1 == x2) { //If none are valid, return empty list of blocks
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL) if (criteriaList.isEmpty()) return null;
addXWallBlocks(list, x1, y1, y2, z1, z2);
else
addXHollowWallBlocks(list, x1, y1, y2, z1, z2);
} else {
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addZWallBlocks(list, x1, x2, y1, y2, z1);
else
addZHollowWallBlocks(list, x1, x2, y1, y2, z1);
}
return list; //If only 1 is valid, choose that one
} Criteria selected = criteriaList.get(0);
public static void addXWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) { //If multiple are valid, choose based on criteria
if (criteriaList.size() > 1) {
//Select the one that is closest
//Limit the angle to not be too extreme
for (int i = 1; i < criteriaList.size(); i++) {
Criteria criteria = criteriaList.get(i);
if (criteria.distToPlayerSq < selected.distToPlayerSq && Math.abs(criteria.angle) - Math.abs(selected.angle) < 3)
selected = criteria;
}
}
for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) { return new BlockPos(selected.planeBound);
}
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) { @Override
list.add(new BlockPos(x, y, z)); protected List<BlockPos> getAllBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
} return getWallBlocks(player, x1, y1, z1, x2, y2, z2);
} }
}
public static void addZWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) { public static List<BlockPos> getWallBlocks(EntityPlayer player, int x1, int y1, int z1, int x2, int y2, int z2) {
List<BlockPos> list = new ArrayList<>();
for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) { if (x1 == x2) {
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addXWallBlocks(list, x1, y1, y2, z1, z2);
else
addXHollowWallBlocks(list, x1, y1, y2, z1, z2);
} else {
if (ModeOptions.getFill() == ModeOptions.ActionEnum.FULL)
addZWallBlocks(list, x1, x2, y1, y2, z1);
else
addZHollowWallBlocks(list, x1, x2, y1, y2, z1);
}
for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) { return list;
list.add(new BlockPos(x, y, z)); }
}
}
}
public static void addXHollowWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) { public static void addXWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) {
Line.addZLineBlocks(list, z1, z2, x, y1);
Line.addZLineBlocks(list, z1, z2, x, y2);
Line.addYLineBlocks(list, y1, y2, x, z1);
Line.addYLineBlocks(list, y1, y2, x, z2);
}
public static void addZHollowWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) { for (int z = z1; z1 < z2 ? z <= z2 : z >= z2; z += z1 < z2 ? 1 : -1) {
Line.addXLineBlocks(list, x1, x2, y1, z);
Line.addXLineBlocks(list, x1, x2, y2, z);
Line.addYLineBlocks(list, y1, y2, x1, z);
Line.addYLineBlocks(list, y1, y2, x2, z);
}
@Override for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
protected BlockPos findSecondPos(PlayerEntity player, BlockPos firstPos, boolean skipRaytrace) { list.add(new BlockPos(x, y, z));
return findWall(player, firstPos, skipRaytrace); }
} }
}
@Override public static void addZWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) {
protected List<BlockPos> getAllBlocks(PlayerEntity player, int x1, int y1, int z1, int x2, int y2, int z2) {
return getWallBlocks(player, x1, y1, z1, x2, y2, z2);
}
static class Criteria { for (int x = x1; x1 < x2 ? x <= x2 : x >= x2; x += x1 < x2 ? 1 : -1) {
Vector3d planeBound;
double distToPlayerSq;
double angle;
Criteria(Vector3d planeBound, BlockPos firstPos, Vector3d start, Vector3d look) { for (int y = y1; y1 < y2 ? y <= y2 : y >= y2; y += y1 < y2 ? 1 : -1) {
this.planeBound = planeBound; list.add(new BlockPos(x, y, z));
this.distToPlayerSq = this.planeBound.subtract(start).lengthSqr(); }
Vector3d wall = this.planeBound.subtract(Vector3d.atLowerCornerOf(firstPos)); }
this.angle = wall.x * look.x + wall.z * look.z; //dot product ignoring y (looking up/down should not affect this angle) }
}
//check if its not behind the player and its not too close and not too far public static void addXHollowWallBlocks(List<BlockPos> list, int x, int y1, int y2, int z1, int z2) {
//also check if raytrace from player to block does not intersect blocks Line.addZLineBlocks(list, z1, z2, x, y1);
public boolean isValid(Vector3d start, Vector3d look, int reach, PlayerEntity player, boolean skipRaytrace) { Line.addZLineBlocks(list, z1, z2, x, y2);
Line.addYLineBlocks(list, y1, y2, x, z1);
Line.addYLineBlocks(list, y1, y2, x, z2);
}
return BuildModes.isCriteriaValid(start, look, reach, player, skipRaytrace, planeBound, planeBound, distToPlayerSq); public static void addZHollowWallBlocks(List<BlockPos> list, int x1, int x2, int y1, int y2, int z) {
} Line.addXLineBlocks(list, x1, x2, y1, z);
} Line.addXLineBlocks(list, x1, x2, y2, z);
Line.addYLineBlocks(list, y1, y2, x1, z);
Line.addYLineBlocks(list, y1, y2, x2, z);
}
} }

View File

@@ -1,104 +1,104 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.BlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.Hand; import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Vector3i; import net.minecraft.util.math.Vec3i;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Array { public class Array {
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos startPos) { public static class ArraySettings{
List<BlockPos> coordinates = new ArrayList<>(); public boolean enabled = false;
public BlockPos offset = BlockPos.ORIGIN;
public int count = 5;
//find arraysettings for the player public ArraySettings() {
ArraySettings a = ModifierSettingsManager.getModifierSettings(player).getArraySettings(); }
if (!isEnabled(a)) return coordinates;
BlockPos pos = startPos; public ArraySettings(boolean enabled, BlockPos offset, int count) {
Vector3i offset = new Vector3i(a.offset.getX(), a.offset.getY(), a.offset.getZ()); this.enabled = enabled;
this.offset = offset;
this.count = count;
}
for (int i = 0; i < a.count; i++) { public int getReach() {
pos = pos.offset(offset); //find largest offset
coordinates.add(pos); int x = Math.abs(offset.getX());
} int y = Math.abs(offset.getY());
int z = Math.abs(offset.getZ());
int largestOffset = Math.max(Math.max(x, y), z);
return coordinates; return largestOffset * count;
} }
}
public static List<BlockState> findBlockStates(PlayerEntity player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) { public static List<BlockPos> findCoordinates(EntityPlayer player, BlockPos startPos) {
List<BlockState> blockStates = new ArrayList<>(); List<BlockPos> coordinates = new ArrayList<>();
//find arraysettings for the player that placed the block //find arraysettings for the player
ArraySettings a = ModifierSettingsManager.getModifierSettings(player).getArraySettings(); ArraySettings a = ModifierSettingsManager.getModifierSettings(player).getArraySettings();
if (!isEnabled(a)) return blockStates; if (!isEnabled(a)) return coordinates;
BlockPos pos = startPos; BlockPos pos = startPos;
Vector3i offset = new Vector3i(a.offset.getX(), a.offset.getY(), a.offset.getZ()); Vec3i offset = new Vec3i(a.offset.getX(), a.offset.getY(), a.offset.getZ());
//Randomizer bag synergy for (int i = 0; i < a.count; i++) {
AbstractRandomizerBagItem randomizerBagItem = null; pos = pos.add(offset);
IItemHandler bagInventory = null; coordinates.add(pos);
if (!itemStack.isEmpty() && itemStack.getItem() instanceof AbstractRandomizerBagItem) { }
randomizerBagItem = (AbstractRandomizerBagItem) itemStack.getItem();
bagInventory = randomizerBagItem.getBagInventory(itemStack);
}
for (int i = 0; i < a.count; i++) { return coordinates;
pos = pos.offset(offset); }
//Randomizer bag synergy public static List<IBlockState> findBlockStates(EntityPlayer player, BlockPos startPos, IBlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) {
if (randomizerBagItem != null) { List<IBlockState> blockStates = new ArrayList<>();
itemStack = randomizerBagItem.pickRandomStack(bagInventory);
blockState = BuildModifiers
.getBlockStateFromItem(itemStack, player, startPos, Direction.UP, new Vector3d(0, 0, 0), Hand.MAIN_HAND);
}
//blockState = blockState.getBlock().getStateForPlacement(player.world, pos, ) //find arraysettings for the player that placed the block
blockStates.add(blockState); ArraySettings a = ModifierSettingsManager.getModifierSettings(player).getArraySettings();
itemStacks.add(itemStack); if (!isEnabled(a)) return blockStates;
}
return blockStates; BlockPos pos = startPos;
} Vec3i offset = new Vec3i(a.offset.getX(), a.offset.getY(), a.offset.getZ());
public static boolean isEnabled(ArraySettings a) { //Randomizer bag synergy
if (a == null || !a.enabled) return false; IItemHandler bagInventory = null;
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemRandomizerBag) {
bagInventory = ItemRandomizerBag.getBagInventory(itemStack);
}
return a.offset.getX() != 0 || a.offset.getY() != 0 || a.offset.getZ() != 0; for (int i = 0; i < a.count; i++) {
} pos = pos.add(offset);
public static class ArraySettings { //Randomizer bag synergy
public boolean enabled = false; if (bagInventory != null) {
public BlockPos offset = BlockPos.ZERO; itemStack = ItemRandomizerBag.pickRandomStack(bagInventory);
public int count = 5; blockState = BuildModifiers
.getBlockStateFromItem(itemStack, player, startPos, EnumFacing.UP, new Vec3d(0, 0, 0), EnumHand.MAIN_HAND);
}
public ArraySettings() { //blockState = blockState.getBlock().getStateForPlacement(player.world, pos, )
} blockStates.add(blockState);
itemStacks.add(itemStack);
}
public ArraySettings(boolean enabled, BlockPos offset, int count) { return blockStates;
this.enabled = enabled; }
this.offset = offset;
this.count = count;
}
public int getReach() { public static boolean isEnabled(ArraySettings a) {
//find largest offset if (a == null || !a.enabled) return false;
int x = Math.abs(offset.getX());
int y = Math.abs(offset.getY());
int z = Math.abs(offset.getZ());
int largestOffset = Math.max(Math.max(x, y), z);
return largestOffset * count; if (a.offset.getX() == 0 && a.offset.getY() == 0 && a.offset.getZ() == 0) return false;
}
} return true;
}
} }

View File

@@ -1,50 +1,50 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.BlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import java.util.List; import java.util.List;
public class BlockSet { public class BlockSet {
private final List<BlockPos> coordinates; private List<BlockPos> coordinates;
private final List<BlockState> previousBlockStates; private List<IBlockState> previousBlockStates;
private final List<BlockState> newBlockStates; private List<IBlockState> newBlockStates;
private final Vector3d hitVec; private Vec3d hitVec;
private final BlockPos firstPos; private BlockPos firstPos;
private final BlockPos secondPos; private BlockPos secondPos;
public BlockSet(List<BlockPos> coordinates, List<BlockState> previousBlockStates, List<BlockState> newBlockStates, Vector3d hitVec, public BlockSet(List<BlockPos> coordinates, List<IBlockState> previousBlockStates, List<IBlockState> newBlockStates, Vec3d hitVec,
BlockPos firstPos, BlockPos secondPos) { BlockPos firstPos, BlockPos secondPos) {
this.coordinates = coordinates; this.coordinates = coordinates;
this.previousBlockStates = previousBlockStates; this.previousBlockStates = previousBlockStates;
this.newBlockStates = newBlockStates; this.newBlockStates = newBlockStates;
this.hitVec = hitVec; this.hitVec = hitVec;
this.firstPos = firstPos; this.firstPos = firstPos;
this.secondPos = secondPos; this.secondPos = secondPos;
} }
public List<BlockPos> getCoordinates() { public List<BlockPos> getCoordinates() {
return coordinates; return coordinates;
} }
public List<BlockState> getPreviousBlockStates() { public List<IBlockState> getPreviousBlockStates() {
return previousBlockStates; return previousBlockStates;
} }
public List<BlockState> getNewBlockStates() { public List<IBlockState> getNewBlockStates() {
return newBlockStates; return newBlockStates;
} }
public Vector3d getHitVec() { public Vec3d getHitVec() {
return hitVec; return hitVec;
} }
public BlockPos getFirstPos() { public BlockPos getFirstPos() {
return firstPos; return firstPos;
} }
public BlockPos getSecondPos() { public BlockPos getSecondPos() {
return secondPos; return secondPos;
} }
} }

View File

@@ -1,262 +1,259 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.block.Blocks; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.init.Blocks;
import net.minecraft.item.BlockItem; import net.minecraft.item.ItemBlock;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext; import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction; import net.minecraft.util.EnumHand;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World; import net.minecraft.world.World;
import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.helper.InventoryHelper; import nl.requios.effortlessbuilding.helper.InventoryHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; import nl.requios.effortlessbuilding.render.BlockPreviewRenderer;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
public class BuildModifiers { public class BuildModifiers {
//Called from BuildModes //Called from BuildModes
public static void onBlockPlaced(PlayerEntity player, List<BlockPos> startCoordinates, Direction sideHit, Vector3d hitVec, boolean placeStartPos) { public static void onBlockPlaced(EntityPlayer player, List<BlockPos> startCoordinates, EnumFacing sideHit, Vec3d hitVec, boolean placeStartPos) {
World world = player.level; World world = player.world;
AbstractRandomizerBagItem.renewRandomness(); ItemRandomizerBag.renewRandomness();
//Format hitvec to 0.x //Format hitvec to 0.x
hitVec = new Vector3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), Math.abs(hitVec.z - ((int) hitVec.z))); hitVec = new Vec3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), Math.abs(hitVec.z - ((int) hitVec.z)));
//find coordinates and blockstates //find coordinates and blockstates
List<BlockPos> coordinates = findCoordinates(player, startCoordinates); List<BlockPos> coordinates = findCoordinates(player, startCoordinates);
List<ItemStack> itemStacks = new ArrayList<>(); List<ItemStack> itemStacks = new ArrayList<>();
List<BlockState> blockStates = findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks); List<IBlockState> blockStates = findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks);
//check if valid blockstates //check if valid blockstates
if (blockStates.size() == 0 || coordinates.size() != blockStates.size()) return; if (blockStates.size() == 0 || coordinates.size() != blockStates.size()) return;
//remember previous blockstates for undo //remember previous blockstates for undo
List<BlockState> previousBlockStates = new ArrayList<>(coordinates.size()); List<IBlockState> previousBlockStates = new ArrayList<>(coordinates.size());
List<BlockState> newBlockStates = new ArrayList<>(coordinates.size()); List<IBlockState> newBlockStates = new ArrayList<>(coordinates.size());
for (BlockPos coordinate : coordinates) { for (BlockPos coordinate : coordinates) {
previousBlockStates.add(world.getBlockState(coordinate)); previousBlockStates.add(world.getBlockState(coordinate));
} }
if (world.isClientSide) { if (world.isRemote) {
BlockPreviewRenderer.onBlocksPlaced(); BlockPreviewRenderer.onBlocksPlaced();
newBlockStates = blockStates; newBlockStates = blockStates;
} else { } else {
//place blocks //place blocks
for (int i = placeStartPos ? 0 : 1; i < coordinates.size(); i++) { for (int i = placeStartPos ? 0 : 1; i < coordinates.size(); i++) {
BlockPos blockPos = coordinates.get(i); BlockPos blockPos = coordinates.get(i);
BlockState blockState = blockStates.get(i); IBlockState blockState = blockStates.get(i);
ItemStack itemStack = itemStacks.get(i); ItemStack itemStack = itemStacks.get(i);
if (world.isLoaded(blockPos)) { if (world.isBlockLoaded(blockPos, true)) {
//check itemstack empty //check itemstack empty
if (itemStack.isEmpty()) { if (itemStack.isEmpty()) {
//try to find new stack, otherwise continue //try to find new stack, otherwise continue
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock()); itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
if (itemStack.isEmpty()) continue; if (itemStack.isEmpty()) continue;
} }
SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, Direction.UP, hitVec, false, false, false); SurvivalHelper.placeBlock(world, player, blockPos, blockState, itemStack, EnumFacing.UP, hitVec, false, false, false);
} }
} }
//find actual new blockstates for undo //find actual new blockstates for undo
for (BlockPos coordinate : coordinates) { for (BlockPos coordinate : coordinates) {
newBlockStates.add(world.getBlockState(coordinate)); newBlockStates.add(world.getBlockState(coordinate));
} }
} }
//Set first previousBlockState to empty if in NORMAL mode, to make undo/redo work //Set first previousBlockState to empty if in NORMAL mode, to make undo/redo work
//(Block is placed by the time it gets here, and unplaced after this) //(Block is placed by the time it gets here, and unplaced after this)
if (!placeStartPos) previousBlockStates.set(0, Blocks.AIR.defaultBlockState()); if (!placeStartPos) previousBlockStates.set(0, Blocks.AIR.getDefaultState());
//If all new blockstates are air then no use in adding it, no block was actually placed //If all new blockstates are air then no use in adding it, no block was actually placed
//Can happen when e.g. placing one block in yourself //Can happen when e.g. placing one block in yourself
if (Collections.frequency(newBlockStates, Blocks.AIR.defaultBlockState()) != newBlockStates.size()) { if (Collections.frequency(newBlockStates, Blocks.AIR.getDefaultState()) != newBlockStates.size()) {
//add to undo stack //add to undo stack
BlockPos firstPos = startCoordinates.get(0); BlockPos firstPos = startCoordinates.get(0);
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1); BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos)); UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
} }
}
public static void onBlockBroken(PlayerEntity player, List<BlockPos> startCoordinates, boolean breakStartPos) { }
World world = player.level;
List<BlockPos> coordinates = findCoordinates(player, startCoordinates); public static void onBlockBroken(EntityPlayer player, List<BlockPos> startCoordinates, boolean breakStartPos) {
World world = player.world;
if (coordinates.isEmpty()) return; List<BlockPos> coordinates = findCoordinates(player, startCoordinates);
//remember previous blockstates for undo if (coordinates.isEmpty()) return;
List<BlockState> previousBlockStates = new ArrayList<>(coordinates.size());
List<BlockState> newBlockStates = new ArrayList<>(coordinates.size());
for (BlockPos coordinate : coordinates) {
previousBlockStates.add(world.getBlockState(coordinate));
}
if (world.isClientSide) { //remember previous blockstates for undo
BlockPreviewRenderer.onBlocksBroken(); List<IBlockState> previousBlockStates = new ArrayList<>(coordinates.size());
List<IBlockState> newBlockStates = new ArrayList<>(coordinates.size());
for (BlockPos coordinate : coordinates) {
previousBlockStates.add(world.getBlockState(coordinate));
}
//list of air blockstates if (world.isRemote) {
for (int i = 0; i < coordinates.size(); i++) { BlockPreviewRenderer.onBlocksBroken();
newBlockStates.add(Blocks.AIR.defaultBlockState());
}
} else { //list of air blockstates
for (BlockPos coordinate : coordinates) {
newBlockStates.add(Blocks.AIR.getDefaultState());
}
//If the player is going to instabreak grass or a plant, only break other instabreaking things } else {
boolean onlyInstaBreaking = !player.isCreative() &&
world.getBlockState(startCoordinates.get(0)).getDestroySpeed(world, startCoordinates.get(0)) == 0f;
//break all those blocks //If the player is going to instabreak grass or a plant, only break other instabreaking things
for (int i = breakStartPos ? 0 : 1; i < coordinates.size(); i++) { boolean onlyInstaBreaking = !player.isCreative() &&
BlockPos coordinate = coordinates.get(i); world.getBlockState(startCoordinates.get(0)).getBlockHardness(world, startCoordinates.get(0)) == 0f;
if (world.isLoaded(coordinate) && !world.isEmptyBlock(coordinate)) {
if (!onlyInstaBreaking || world.getBlockState(coordinate).getDestroySpeed(world, coordinate) == 0f) {
SurvivalHelper.breakBlock(world, player, coordinate, false);
}
}
}
//find actual new blockstates for undo //break all those blocks
for (BlockPos coordinate : coordinates) { for (int i = breakStartPos ? 0 : 1; i < coordinates.size(); i++) {
newBlockStates.add(world.getBlockState(coordinate)); BlockPos coordinate = coordinates.get(i);
} if (world.isBlockLoaded(coordinate, false)) {
} if (!onlyInstaBreaking || world.getBlockState(coordinate).getBlockHardness(world, coordinate) == 0f) {
SurvivalHelper.breakBlock(world, player, coordinate, false);
}
}
}
//Set first newBlockState to empty if in NORMAL mode, to make undo/redo work //find actual new blockstates for undo
//(Block isn't broken yet by the time it gets here, and broken after this) for (BlockPos coordinate : coordinates) {
if (!breakStartPos) newBlockStates.set(0, Blocks.AIR.defaultBlockState()); newBlockStates.add(world.getBlockState(coordinate));
}
}
//add to undo stack //Set first newBlockState to empty if in NORMAL mode, to make undo/redo work
BlockPos firstPos = startCoordinates.get(0); //(Block isn't broken yet by the time it gets here, and broken after this)
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1); if (!breakStartPos) newBlockStates.set(0, Blocks.AIR.getDefaultState());
Vector3d hitVec = new Vector3d(0.5, 0.5, 0.5);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
} //add to undo stack
BlockPos firstPos = startCoordinates.get(0);
BlockPos secondPos = startCoordinates.get(startCoordinates.size() - 1);
Vec3d hitVec = new Vec3d(0.5, 0.5, 0.5);
UndoRedo.addUndo(player, new BlockSet(coordinates, previousBlockStates, newBlockStates, hitVec, firstPos, secondPos));
public static List<BlockPos> findCoordinates(PlayerEntity player, List<BlockPos> posList) { }
List<BlockPos> coordinates = new ArrayList<>();
//Add current blocks being placed too
coordinates.addAll(posList);
//Find mirror/array/radial mirror coordinates for each blockpos public static List<BlockPos> findCoordinates(EntityPlayer player, List<BlockPos> posList) {
for (BlockPos blockPos : posList) { List<BlockPos> coordinates = new ArrayList<>();
List<BlockPos> arrayCoordinates = Array.findCoordinates(player, blockPos); //Add current blocks being placed too
coordinates.addAll(arrayCoordinates); coordinates.addAll(posList);
coordinates.addAll(Mirror.findCoordinates(player, blockPos));
coordinates.addAll(RadialMirror.findCoordinates(player, blockPos));
//get mirror for each array coordinate
for (BlockPos coordinate : arrayCoordinates) {
coordinates.addAll(Mirror.findCoordinates(player, coordinate));
coordinates.addAll(RadialMirror.findCoordinates(player, coordinate));
}
}
return coordinates; //Find mirror/array/radial mirror coordinates for each blockpos
} for (BlockPos blockPos : posList) {
List<BlockPos> arrayCoordinates = Array.findCoordinates(player, blockPos);
coordinates.addAll(arrayCoordinates);
coordinates.addAll(Mirror.findCoordinates(player, blockPos));
coordinates.addAll(RadialMirror.findCoordinates(player, blockPos));
//get mirror for each array coordinate
for (BlockPos coordinate : arrayCoordinates) {
coordinates.addAll(Mirror.findCoordinates(player, coordinate));
coordinates.addAll(RadialMirror.findCoordinates(player, coordinate));
}
}
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos blockPos) { return coordinates;
return findCoordinates(player, new ArrayList<>(Collections.singletonList(blockPos))); }
}
public static List<BlockState> findBlockStates(PlayerEntity player, List<BlockPos> posList, Vector3d hitVec, Direction facing, List<ItemStack> itemStacks) { public static List<BlockPos> findCoordinates(EntityPlayer player, BlockPos blockPos) {
List<BlockState> blockStates = new ArrayList<>(); return findCoordinates(player, new ArrayList<>(Arrays.asList(blockPos)));
itemStacks.clear(); }
//Get itemstack public static List<IBlockState> findBlockStates(EntityPlayer player, List<BlockPos> posList, Vec3d hitVec, EnumFacing facing, List<ItemStack> itemStacks) {
ItemStack itemStack = player.getItemInHand(Hand.MAIN_HAND); List<IBlockState> blockStates = new ArrayList<>();
if (itemStack.isEmpty() || !CompatHelper.isItemBlockProxy(itemStack)) { itemStacks.clear();
itemStack = player.getItemInHand(Hand.OFF_HAND);
}
if (itemStack.isEmpty() || !CompatHelper.isItemBlockProxy(itemStack)) {
return blockStates;
}
//Get ItemBlock stack //Get itemstack
ItemStack itemBlock = ItemStack.EMPTY; ItemStack itemStack = player.getHeldItem(EnumHand.MAIN_HAND);
if (itemStack.getItem() instanceof BlockItem) itemBlock = itemStack; if (itemStack.isEmpty() || !CompatHelper.isItemBlockProxy(itemStack)) {
else itemBlock = CompatHelper.getItemBlockFromStack(itemStack); itemStack = player.getHeldItem(EnumHand.OFF_HAND);
AbstractRandomizerBagItem.resetRandomness(); }
if (itemStack.isEmpty() || !CompatHelper.isItemBlockProxy(itemStack)) {
return blockStates;
}
//Add blocks in posList first //Get ItemBlock stack
for (BlockPos blockPos : posList) { ItemStack itemBlock = ItemStack.EMPTY;
if (!(itemStack.getItem() instanceof BlockItem)) itemBlock = CompatHelper.getItemBlockFromStack(itemStack); if (itemStack.getItem() instanceof ItemBlock) itemBlock = itemStack;
BlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, Hand.MAIN_HAND); else itemBlock = CompatHelper.getItemBlockFromStack(itemStack);
blockStates.add(blockState); ItemRandomizerBag.resetRandomness();
itemStacks.add(itemBlock);
}
for (BlockPos blockPos : posList) { //Add blocks in posList first
BlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, Hand.MAIN_HAND); for (BlockPos blockPos : posList) {
if (!(itemStack.getItem() instanceof ItemBlock)) itemBlock = CompatHelper.getItemBlockFromStack(itemStack);
IBlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, EnumHand.MAIN_HAND);
blockStates.add(blockState);
itemStacks.add(itemBlock);
}
List<BlockState> arrayBlockStates = Array.findBlockStates(player, blockPos, blockState, itemStack, itemStacks); for (BlockPos blockPos : posList) {
blockStates.addAll(arrayBlockStates); IBlockState blockState = getBlockStateFromItem(itemBlock, player, blockPos, facing, hitVec, EnumHand.MAIN_HAND);
blockStates.addAll(Mirror.findBlockStates(player, blockPos, blockState, itemStack, itemStacks));
blockStates.addAll(RadialMirror.findBlockStates(player, blockPos, blockState, itemStack, itemStacks));
//add mirror for each array coordinate
List<BlockPos> arrayCoordinates = Array.findCoordinates(player, blockPos);
for (int i = 0; i < arrayCoordinates.size(); i++) {
BlockPos coordinate = arrayCoordinates.get(i);
BlockState blockState1 = arrayBlockStates.get(i);
blockStates.addAll(Mirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
blockStates.addAll(RadialMirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
}
//Adjust blockstates for torches and ladders etc to place on a valid side List<IBlockState> arrayBlockStates = Array.findBlockStates(player, blockPos, blockState, itemStack, itemStacks);
//TODO optimize findCoordinates (done twice now) blockStates.addAll(arrayBlockStates);
//TODO fix mirror blockStates.addAll(Mirror.findBlockStates(player, blockPos, blockState, itemStack, itemStacks));
blockStates.addAll(RadialMirror.findBlockStates(player, blockPos, blockState, itemStack, itemStacks));
//add mirror for each array coordinate
List<BlockPos> arrayCoordinates = Array.findCoordinates(player, blockPos);
for (int i = 0; i < arrayCoordinates.size(); i++) {
BlockPos coordinate = arrayCoordinates.get(i);
IBlockState blockState1 = arrayBlockStates.get(i);
blockStates.addAll(Mirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
blockStates.addAll(RadialMirror.findBlockStates(player, coordinate, blockState1, itemStack, itemStacks));
}
//Adjust blockstates for torches and ladders etc to place on a valid side
//TODO optimize findCoordinates (done twice now)
//TODO fix mirror
// List<BlockPos> coordinates = findCoordinates(player, startPos); // List<BlockPos> coordinates = findCoordinates(player, startPos);
// for (int i = 0; i < blockStates.size(); i++) { // for (int i = 0; i < blockStates.size(); i++) {
// blockStates.set(i, blockStates.get(i).getBlock().getStateForPlacement(player.world, coordinates.get(i), facing, // blockStates.set(i, blockStates.get(i).getBlock().getStateForPlacement(player.world, coordinates.get(i), facing,
// (float) hitVec.x, (float) hitVec.y, (float) hitVec.z, itemStacks.get(i).getMetadata(), player, EnumHand.MAIN_HAND)); // (float) hitVec.x, (float) hitVec.y, (float) hitVec.z, itemStacks.get(i).getMetadata(), player, EnumHand.MAIN_HAND));
// } // }
} }
return blockStates; return blockStates;
} }
public static boolean isEnabled(ModifierSettingsManager.ModifierSettings modifierSettings, BlockPos startPos) { public static boolean isEnabled(ModifierSettingsManager.ModifierSettings modifierSettings, BlockPos startPos) {
return Mirror.isEnabled(modifierSettings.getMirrorSettings(), startPos) || return Mirror.isEnabled(modifierSettings.getMirrorSettings(), startPos) ||
Array.isEnabled(modifierSettings.getArraySettings()) || Array.isEnabled(modifierSettings.getArraySettings()) ||
RadialMirror.isEnabled(modifierSettings.getRadialMirrorSettings(), startPos) || RadialMirror.isEnabled(modifierSettings.getRadialMirrorSettings(), startPos) ||
modifierSettings.doQuickReplace(); modifierSettings.doQuickReplace();
} }
public static BlockState getBlockStateFromItem(ItemStack itemStack, PlayerEntity player, BlockPos blockPos, Direction facing, Vector3d hitVec, Hand hand) { public static IBlockState getBlockStateFromItem(ItemStack itemStack, EntityPlayer player, BlockPos blockPos, EnumFacing facing, Vec3d hitVec, EnumHand hand) {
return Block.byItem(itemStack.getItem()).getStateForPlacement(new BlockItemUseContext(new ItemUseContext(player, hand, new BlockRayTraceResult(hitVec, facing, blockPos, false)))); return Block.getBlockFromItem(itemStack.getItem()).getStateForPlacement(player.world, blockPos, facing,
} ((float) hitVec.x), ((float) hitVec.y), ((float) hitVec.z), itemStack.getMetadata(), player, hand);
}
//Returns true if equal (or both null) //Returns true if equal (or both null)
public static boolean compareCoordinates(List<BlockPos> coordinates1, List<BlockPos> coordinates2) { public static boolean compareCoordinates(List<BlockPos> coordinates1, List<BlockPos> coordinates2) {
if (coordinates1 == null && coordinates2 == null) return true; if (coordinates1 == null && coordinates2 == null) return true;
if (coordinates1 == null || coordinates2 == null) return false; if (coordinates1 == null || coordinates2 == null) return false;
//Check count, not actual values //Check count, not actual values
if (coordinates1.size() == coordinates2.size()) { if (coordinates1.size() == coordinates2.size()){
if (coordinates1.size() == 1) { if (coordinates1.size() == 1){
return coordinates1.get(0).equals(coordinates2.get(0)); return coordinates1.get(0).equals(coordinates2.get(0));
} }
return true; return true;
} else { } else {
return false; return false;
} }
// return coordinates1.equals(coordinates2); // return coordinates1.equals(coordinates2);
} }
} }

View File

@@ -1,229 +1,225 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.*; import net.minecraft.block.BlockDirectional;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.block.BlockDispenser;
import net.minecraft.block.BlockSlab;
import net.minecraft.block.BlockStairs;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.state.properties.Half; import net.minecraft.util.EnumFacing;
import net.minecraft.state.properties.SlabType; import net.minecraft.util.EnumHand;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Mirror { public class Mirror {
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos startPos) { public static class MirrorSettings {
List<BlockPos> coordinates = new ArrayList<>(); public boolean enabled = false;
public Vec3d position = new Vec3d(0.5, 64.5, 0.5);
public boolean mirrorX = true, mirrorY = false, mirrorZ = false;
public int radius = 10;
public boolean drawLines = true, drawPlanes = true;
//find mirrorsettings for the player public MirrorSettings() {
MirrorSettings m = ModifierSettingsManager.getModifierSettings(player).getMirrorSettings(); }
if (!isEnabled(m, startPos)) return coordinates;
if (m.mirrorX) coordinateMirrorX(m, startPos, coordinates); public MirrorSettings(boolean mirrorEnabled, Vec3d position, boolean mirrorX, boolean mirrorY, boolean mirrorZ, int radius, boolean drawLines, boolean drawPlanes) {
if (m.mirrorY) coordinateMirrorY(m, startPos, coordinates); this.enabled = mirrorEnabled;
if (m.mirrorZ) coordinateMirrorZ(m, startPos, coordinates); this.position = position;
this.mirrorX = mirrorX;
this.mirrorY = mirrorY;
this.mirrorZ = mirrorZ;
this.radius = radius;
this.drawLines = drawLines;
this.drawPlanes = drawPlanes;
}
return coordinates; public int getReach() {
} return radius * 2; //Change ModifierSettings#setReachUpgrade too
}
}
private static void coordinateMirrorX(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) { public static List<BlockPos> findCoordinates(EntityPlayer player, BlockPos startPos) {
//find mirror position List<BlockPos> coordinates = new ArrayList<>();
double x = m.position.x + (m.position.x - oldBlockPos.getX() - 0.5);
BlockPos newBlockPos = new BlockPos(x, oldBlockPos.getY(), oldBlockPos.getZ());
coordinates.add(newBlockPos);
if (m.mirrorY) coordinateMirrorY(m, newBlockPos, coordinates); //find mirrorsettings for the player
if (m.mirrorZ) coordinateMirrorZ(m, newBlockPos, coordinates); MirrorSettings m = ModifierSettingsManager.getModifierSettings(player).getMirrorSettings();
} if (!isEnabled(m, startPos)) return coordinates;
private static void coordinateMirrorY(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) { if (m.mirrorX) coordinateMirrorX(m, startPos, coordinates);
//find mirror position if (m.mirrorY) coordinateMirrorY(m, startPos, coordinates);
double y = m.position.y + (m.position.y - oldBlockPos.getY() - 0.5); if (m.mirrorZ) coordinateMirrorZ(m, startPos, coordinates);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), y, oldBlockPos.getZ());
coordinates.add(newBlockPos);
if (m.mirrorZ) coordinateMirrorZ(m, newBlockPos, coordinates); return coordinates;
} }
private static void coordinateMirrorZ(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) { private static void coordinateMirrorX(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) {
//find mirror position //find mirror position
double z = m.position.z + (m.position.z - oldBlockPos.getZ() - 0.5); double x = m.position.x + (m.position.x - oldBlockPos.getX() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), oldBlockPos.getY(), z); BlockPos newBlockPos = new BlockPos(x, oldBlockPos.getY(), oldBlockPos.getZ());
coordinates.add(newBlockPos); coordinates.add(newBlockPos);
}
public static List<BlockState> findBlockStates(PlayerEntity player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) { if (m.mirrorY) coordinateMirrorY(m, newBlockPos, coordinates);
List<BlockState> blockStates = new ArrayList<>(); if (m.mirrorZ) coordinateMirrorZ(m, newBlockPos, coordinates);
}
//find mirrorsettings for the player private static void coordinateMirrorY(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) {
MirrorSettings m = ModifierSettingsManager.getModifierSettings(player).getMirrorSettings(); //find mirror position
if (!isEnabled(m, startPos)) return blockStates; double y = m.position.y + (m.position.y - oldBlockPos.getY() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), y, oldBlockPos.getZ());
coordinates.add(newBlockPos);
//Randomizer bag synergy if (m.mirrorZ) coordinateMirrorZ(m, newBlockPos, coordinates);
AbstractRandomizerBagItem randomizerBagItem = null; }
IItemHandler bagInventory = null;
if (!itemStack.isEmpty() && itemStack.getItem() instanceof AbstractRandomizerBagItem) {
randomizerBagItem = (AbstractRandomizerBagItem) itemStack.getItem();
bagInventory = randomizerBagItem.getBagInventory(itemStack);
}
if (m.mirrorX) private static void coordinateMirrorZ(MirrorSettings m, BlockPos oldBlockPos, List<BlockPos> coordinates) {
blockStateMirrorX(player, m, startPos, blockState, bagInventory, itemStack, Hand.MAIN_HAND, blockStates, itemStacks); //find mirror position
if (m.mirrorY) double z = m.position.z + (m.position.z - oldBlockPos.getZ() - 0.5);
blockStateMirrorY(player, m, startPos, blockState, bagInventory, itemStack, Hand.MAIN_HAND, blockStates, itemStacks); BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), oldBlockPos.getY(), z);
if (m.mirrorZ) coordinates.add(newBlockPos);
blockStateMirrorZ(player, m, startPos, blockState, bagInventory, itemStack, Hand.MAIN_HAND, blockStates, itemStacks); }
return blockStates; public static List<IBlockState> findBlockStates(EntityPlayer player, BlockPos startPos, IBlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) {
} List<IBlockState> blockStates = new ArrayList<>();
private static void blockStateMirrorX(PlayerEntity player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState, //find mirrorsettings for the player
IItemHandler bagInventory, ItemStack itemStack, Hand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) { MirrorSettings m = ModifierSettingsManager.getModifierSettings(player).getMirrorSettings();
//find mirror position if (!isEnabled(m, startPos)) return blockStates;
double x = m.position.x + (m.position.x - oldBlockPos.getX() - 0.5);
BlockPos newBlockPos = new BlockPos(x, oldBlockPos.getY(), oldBlockPos.getZ());
//Randomizer bag synergy //Randomizer bag synergy
if (bagInventory != null) { IItemHandler bagInventory = null;
itemStack = ((AbstractRandomizerBagItem)itemStack.getItem()).pickRandomStack(bagInventory); if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemRandomizerBag) {
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vector3d(0, 0, 0), hand); bagInventory = ItemRandomizerBag.getBagInventory(itemStack);
} }
//Find blockstate if (m.mirrorX) blockStateMirrorX(player, m, startPos, blockState, bagInventory, itemStack, EnumHand.MAIN_HAND, blockStates, itemStacks);
BlockState newBlockState = oldBlockState == null ? null : oldBlockState.mirror(net.minecraft.util.Mirror.FRONT_BACK); if (m.mirrorY) blockStateMirrorY(player, m, startPos, blockState, bagInventory, itemStack, EnumHand.MAIN_HAND, blockStates, itemStacks);
if (m.mirrorZ) blockStateMirrorZ(player, m, startPos, blockState, bagInventory, itemStack, EnumHand.MAIN_HAND, blockStates, itemStacks);
//Store blockstate and itemstack return blockStates;
blockStates.add(newBlockState); }
itemStacks.add(itemStack);
if (m.mirrorY) private static void blockStateMirrorX(EntityPlayer player, MirrorSettings m, BlockPos oldBlockPos, IBlockState oldBlockState,
blockStateMirrorY(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks); IItemHandler bagInventory, ItemStack itemStack, EnumHand hand, List<IBlockState> blockStates, List<ItemStack> itemStacks) {
if (m.mirrorZ) //find mirror position
blockStateMirrorZ(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks); double x = m.position.x + (m.position.x - oldBlockPos.getX() - 0.5);
} BlockPos newBlockPos = new BlockPos(x, oldBlockPos.getY(), oldBlockPos.getZ());
private static void blockStateMirrorY(PlayerEntity player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState, //Randomizer bag synergy
IItemHandler bagInventory, ItemStack itemStack, Hand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) { if (bagInventory != null) {
//find mirror position itemStack = ItemRandomizerBag.pickRandomStack(bagInventory);
double y = m.position.y + (m.position.y - oldBlockPos.getY() - 0.5); oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, EnumFacing.UP, new Vec3d(0, 0, 0), hand);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), y, oldBlockPos.getZ()); }
//Randomizer bag synergy //Find blockstate
if (bagInventory != null) { IBlockState newBlockState = oldBlockState == null ? null : oldBlockState.withMirror(net.minecraft.util.Mirror.FRONT_BACK);
itemStack = ((AbstractRandomizerBagItem)itemStack.getItem()).pickRandomStack(bagInventory);
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vector3d(0, 0, 0), hand);
}
//Find blockstate //Store blockstate and itemstack
BlockState newBlockState = oldBlockState == null ? null : getVerticalMirror(oldBlockState); blockStates.add(newBlockState);
itemStacks.add(itemStack);
//Store blockstate and itemstack if (m.mirrorY) blockStateMirrorY(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks);
blockStates.add(newBlockState); if (m.mirrorZ) blockStateMirrorZ(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks);
itemStacks.add(itemStack); }
if (m.mirrorZ) private static void blockStateMirrorY(EntityPlayer player, MirrorSettings m, BlockPos oldBlockPos, IBlockState oldBlockState,
blockStateMirrorZ(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks); IItemHandler bagInventory, ItemStack itemStack, EnumHand hand, List<IBlockState> blockStates, List<ItemStack> itemStacks) {
} //find mirror position
double y = m.position.y + (m.position.y - oldBlockPos.getY() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), y, oldBlockPos.getZ());
private static void blockStateMirrorZ(PlayerEntity player, MirrorSettings m, BlockPos oldBlockPos, BlockState oldBlockState, //Randomizer bag synergy
IItemHandler bagInventory, ItemStack itemStack, Hand hand, List<BlockState> blockStates, List<ItemStack> itemStacks) { if (bagInventory != null) {
//find mirror position itemStack = ItemRandomizerBag.pickRandomStack(bagInventory);
double z = m.position.z + (m.position.z - oldBlockPos.getZ() - 0.5); oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, EnumFacing.UP, new Vec3d(0, 0, 0), hand);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), oldBlockPos.getY(), z); }
//Randomizer bag synergy //Find blockstate
if (bagInventory != null) { IBlockState newBlockState = oldBlockState == null ? null : getVerticalMirror(oldBlockState);
itemStack = ((AbstractRandomizerBagItem)itemStack.getItem()).pickRandomStack(bagInventory);
oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, Direction.UP, new Vector3d(0, 0, 0), hand);
}
//Find blockstate //Store blockstate and itemstack
BlockState newBlockState = oldBlockState == null ? null : oldBlockState.mirror(net.minecraft.util.Mirror.LEFT_RIGHT); blockStates.add(newBlockState);
itemStacks.add(itemStack);
//Store blockstate and itemstack if (m.mirrorZ) blockStateMirrorZ(player, m, newBlockPos, newBlockState, bagInventory, itemStack, hand, blockStates, itemStacks);
blockStates.add(newBlockState); }
itemStacks.add(itemStack);
}
public static boolean isEnabled(MirrorSettings m, BlockPos startPos) { private static void blockStateMirrorZ(EntityPlayer player, MirrorSettings m, BlockPos oldBlockPos, IBlockState oldBlockState,
if (m == null || !m.enabled || (!m.mirrorX && !m.mirrorY && !m.mirrorZ)) return false; IItemHandler bagInventory, ItemStack itemStack, EnumHand hand, List<IBlockState> blockStates, List<ItemStack> itemStacks) {
//find mirror position
double z = m.position.z + (m.position.z - oldBlockPos.getZ() - 0.5);
BlockPos newBlockPos = new BlockPos(oldBlockPos.getX(), oldBlockPos.getY(), z);
//within mirror distance //Randomizer bag synergy
return !(startPos.getX() + 0.5 < m.position.x - m.radius) && !(startPos.getX() + 0.5 > m.position.x + m.radius) && if (bagInventory != null) {
!(startPos.getY() + 0.5 < m.position.y - m.radius) && !(startPos.getY() + 0.5 > m.position.y + m.radius) && itemStack = ItemRandomizerBag.pickRandomStack(bagInventory);
!(startPos.getZ() + 0.5 < m.position.z - m.radius) && !(startPos.getZ() + 0.5 > m.position.z + m.radius); oldBlockState = BuildModifiers.getBlockStateFromItem(itemStack, player, oldBlockPos, EnumFacing.UP, new Vec3d(0, 0, 0), hand);
} }
private static BlockState getVerticalMirror(BlockState blockState) { //Find blockstate
//Stairs IBlockState newBlockState = oldBlockState == null ? null : oldBlockState.withMirror(net.minecraft.util.Mirror.LEFT_RIGHT);
if (blockState.getBlock() instanceof StairsBlock) {
if (blockState.getValue(StairsBlock.HALF) == Half.BOTTOM) {
return blockState.setValue(StairsBlock.HALF, Half.TOP);
} else {
return blockState.setValue(StairsBlock.HALF, Half.BOTTOM);
}
}
//Slabs //Store blockstate and itemstack
if (blockState.getBlock() instanceof SlabBlock) { blockStates.add(newBlockState);
if (blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE) { itemStacks.add(itemStack);
return blockState; }
} else if (blockState.getValue(SlabBlock.TYPE) == SlabType.BOTTOM) {
return blockState.setValue(SlabBlock.TYPE, SlabType.TOP);
} else {
return blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM);
}
}
//Buttons, endrod, observer, piston public static boolean isEnabled(MirrorSettings m, BlockPos startPos) {
if (blockState.getBlock() instanceof DirectionalBlock) { if (m == null || !m.enabled || (!m.mirrorX && !m.mirrorY && !m.mirrorZ)) return false;
if (blockState.getValue(DirectionalBlock.FACING) == Direction.DOWN) {
return blockState.setValue(DirectionalBlock.FACING, Direction.UP);
} else if (blockState.getValue(DirectionalBlock.FACING) == Direction.UP) {
return blockState.setValue(DirectionalBlock.FACING, Direction.DOWN);
}
}
//Dispenser, dropper //within mirror distance
if (blockState.getBlock() instanceof DispenserBlock) { if (startPos.getX() + 0.5 < m.position.x - m.radius || startPos.getX() + 0.5 > m.position.x + m.radius ||
if (blockState.getValue(DispenserBlock.FACING) == Direction.DOWN) { startPos.getY() + 0.5 < m.position.y - m.radius || startPos.getY() + 0.5 > m.position.y + m.radius ||
return blockState.setValue(DispenserBlock.FACING, Direction.UP); startPos.getZ() + 0.5 < m.position.z - m.radius || startPos.getZ() + 0.5 > m.position.z + m.radius)
} else if (blockState.getValue(DispenserBlock.FACING) == Direction.UP) { return false;
return blockState.setValue(DispenserBlock.FACING, Direction.DOWN);
}
}
return blockState; return true;
} }
public static class MirrorSettings { private static IBlockState getVerticalMirror(IBlockState blockState) {
public boolean enabled = false; //Stairs
public Vector3d position = new Vector3d(0.5, 64.5, 0.5); if (blockState.getBlock() instanceof BlockStairs) {
public boolean mirrorX = true, mirrorY = false, mirrorZ = false; if (blockState.getValue(BlockStairs.HALF) == BlockStairs.EnumHalf.BOTTOM) {
public int radius = 10; return blockState.withProperty(BlockStairs.HALF, BlockStairs.EnumHalf.TOP);
public boolean drawLines = true, drawPlanes = true; } else {
return blockState.withProperty(BlockStairs.HALF, BlockStairs.EnumHalf.BOTTOM);
}
}
public MirrorSettings() { //Slabs
} if (blockState.getBlock() instanceof BlockSlab) {
if (((BlockSlab) blockState.getBlock()).isDouble()) return blockState;
if (blockState.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM) {
return blockState.withProperty(BlockSlab.HALF, BlockSlab.EnumBlockHalf.TOP);
} else {
return blockState.withProperty(BlockSlab.HALF, BlockSlab.EnumBlockHalf.BOTTOM);
}
}
public MirrorSettings(boolean mirrorEnabled, Vector3d position, boolean mirrorX, boolean mirrorY, boolean mirrorZ, int radius, boolean drawLines, boolean drawPlanes) { //Buttons, endrod, observer, piston
this.enabled = mirrorEnabled; if (blockState.getBlock() instanceof BlockDirectional) {
this.position = position; if (blockState.getValue(BlockDirectional.FACING) == EnumFacing.DOWN) {
this.mirrorX = mirrorX; return blockState.withProperty(BlockDirectional.FACING, EnumFacing.UP);
this.mirrorY = mirrorY; } else if (blockState.getValue(BlockDirectional.FACING) == EnumFacing.UP) {
this.mirrorZ = mirrorZ; return blockState.withProperty(BlockDirectional.FACING, EnumFacing.DOWN);
this.radius = radius; }
this.drawLines = drawLines; }
this.drawPlanes = drawPlanes;
}
public int getReach() { //Dispenser, dropper
return radius * 2; //Change ModifierSettings#setReachUpgrade too if (blockState.getBlock() instanceof BlockDispenser) {
} if (blockState.getValue(BlockDispenser.FACING) == EnumFacing.DOWN) {
} return blockState.withProperty(BlockDispenser.FACING, EnumFacing.UP);
} else if (blockState.getValue(BlockDispenser.FACING) == EnumFacing.UP) {
return blockState.withProperty(BlockDispenser.FACING, EnumFacing.DOWN);
}
}
return blockState;
}
} }

View File

@@ -1,215 +1,196 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.network.PacketDistributor;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager; import nl.requios.effortlessbuilding.capability.ModifierCapabilityManager;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.network.ModifierSettingsMessage; import nl.requios.effortlessbuilding.network.ModifierSettingsMessage;
import nl.requios.effortlessbuilding.network.PacketHandler;
import javax.annotation.Nonnull;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ModifierSettingsManager { public class ModifierSettingsManager {
//Retrieves the buildsettings of a player through the modifierCapability capability //Retrieves the buildsettings of a player through the modifierCapability capability
//Never returns null //Never returns null
@Nonnull public static ModifierSettings getModifierSettings(EntityPlayer player){
public static ModifierSettings getModifierSettings(PlayerEntity player) { if (player.hasCapability(ModifierCapabilityManager.modifierCapability, null)) {
LazyOptional<ModifierCapabilityManager.IModifierCapability> modifierCapability = ModifierCapabilityManager.IModifierCapability capability = player.getCapability(
player.getCapability(ModifierCapabilityManager.modifierCapability, null); ModifierCapabilityManager.modifierCapability, null);
if (capability.getModifierData() == null) {
capability.setModifierData(new ModifierSettings());
}
return capability.getModifierData();
}
throw new IllegalArgumentException("Player does not have modifierCapability capability");
}
if (modifierCapability.isPresent()) { public static void setModifierSettings(EntityPlayer player, ModifierSettings modifierSettings) {
ModifierCapabilityManager.IModifierCapability capability = modifierCapability.orElse(null); if (player == null) {
if (capability.getModifierData() == null) { EffortlessBuilding.log("Cannot set buildsettings, player is null");
capability.setModifierData(new ModifierSettings()); return;
} }
return capability.getModifierData(); if (player.hasCapability(ModifierCapabilityManager.modifierCapability, null)) {
} ModifierCapabilityManager.IModifierCapability capability = player.getCapability(
ModifierCapabilityManager.modifierCapability, null);
capability.setModifierData(modifierSettings);
} else {
EffortlessBuilding.log(player, "Saving buildsettings failed.");
}
}
//Player does not have modifierCapability capability public static String sanitize(ModifierSettings modifierSettings, EntityPlayer player) {
//Return dummy settings int maxReach = ReachHelper.getMaxReach(player);
return new ModifierSettings(); String error = "";
// throw new IllegalArgumentException("Player does not have modifierCapability capability");
}
public static void setModifierSettings(PlayerEntity player, ModifierSettings modifierSettings) { //Mirror settings
if (player == null) { Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
EffortlessBuilding.log("Cannot set buildsettings, player is null"); if (m.radius < 1) {
return; m.radius = 1;
} error += "Mirror size has to be at least 1. This has been corrected. ";
}
if (m.getReach() > maxReach) {
m.radius = maxReach / 2;
error += "Mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to "+ (maxReach / 2) + ". ";
}
LazyOptional<ModifierCapabilityManager.IModifierCapability> modifierCapability = //Array settings
player.getCapability(ModifierCapabilityManager.modifierCapability, null); Array.ArraySettings a = modifierSettings.getArraySettings();
if (a.count < 0) {
a.count = 0;
error += "Array count may not be negative. It has been reset to 0.";
}
modifierCapability.ifPresent((capability) -> { if (a.getReach() > maxReach) {
capability.setModifierData(modifierSettings); a.count = 0;
}); error += "Array exceeds your maximum reach of " + maxReach + ". Array count has been reset to 0. ";
}
if (!modifierCapability.isPresent()) { //Radial mirror settings
EffortlessBuilding.log(player, "Saving buildsettings failed."); RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
} if (r.slices < 2) {
} r.slices = 2;
error += "Radial mirror needs to have at least 2 slices. Slices has been set to 2.";
}
public static String sanitize(ModifierSettings modifierSettings, PlayerEntity player) { if (r.radius < 1) {
int maxReach = ReachHelper.getMaxReach(player); r.radius = 1;
String error = ""; error += "Radial mirror radius has to be at least 1. This has been corrected. ";
}
if (r.getReach() > maxReach) {
r.radius = maxReach / 2;
error += "Radial mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to "+ (maxReach / 2) + ". ";
}
//Mirror settings //Other
Mirror.MirrorSettings m = modifierSettings.getMirrorSettings(); if (modifierSettings.reachUpgrade < 0) {
if (m.radius < 1) { modifierSettings.reachUpgrade = 0;
m.radius = 1; }
error += "Mirror size has to be at least 1. This has been corrected. "; if (modifierSettings.reachUpgrade > 3) {
} modifierSettings.reachUpgrade = 3;
if (m.getReach() > maxReach) { }
m.radius = maxReach / 2;
error += "Mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to " + (maxReach / 2) + ". ";
}
//Array settings return error;
Array.ArraySettings a = modifierSettings.getArraySettings(); }
if (a.count < 0) {
a.count = 0;
error += "Array count may not be negative. It has been reset to 0.";
}
if (a.getReach() > maxReach) { public static class ModifierSettings {
a.count = 0; private Mirror.MirrorSettings mirrorSettings;
error += "Array exceeds your maximum reach of " + maxReach + ". Array count has been reset to 0. "; private Array.ArraySettings arraySettings;
} private RadialMirror.RadialMirrorSettings radialMirrorSettings;
private boolean quickReplace = false;
private int reachUpgrade = 0;
//Radial mirror settings public ModifierSettings() {
RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings(); mirrorSettings = new Mirror.MirrorSettings();
if (r.slices < 2) { arraySettings = new Array.ArraySettings();
r.slices = 2; radialMirrorSettings = new RadialMirror.RadialMirrorSettings();
error += "Radial mirror needs to have at least 2 slices. Slices has been set to 2."; }
}
if (r.radius < 1) { public ModifierSettings(Mirror.MirrorSettings mirrorSettings, Array.ArraySettings arraySettings,
r.radius = 1; RadialMirror.RadialMirrorSettings radialMirrorSettings, boolean quickReplace, int reachUpgrade) {
error += "Radial mirror radius has to be at least 1. This has been corrected. "; this.mirrorSettings = mirrorSettings;
} this.arraySettings = arraySettings;
if (r.getReach() > maxReach) { this.radialMirrorSettings = radialMirrorSettings;
r.radius = maxReach / 2; this.quickReplace = quickReplace;
error += "Radial mirror exceeds your maximum reach of " + (maxReach / 2) + ". Radius has been set to " + (maxReach / 2) + ". "; this.reachUpgrade = reachUpgrade;
} }
//Other public Mirror.MirrorSettings getMirrorSettings() {
if (modifierSettings.reachUpgrade < 0) { if (this.mirrorSettings == null) this.mirrorSettings = new Mirror.MirrorSettings();
modifierSettings.reachUpgrade = 0; return this.mirrorSettings;
} }
if (modifierSettings.reachUpgrade > 3) {
modifierSettings.reachUpgrade = 3;
}
return error; public void setMirrorSettings(Mirror.MirrorSettings mirrorSettings) {
} if (mirrorSettings == null) return;
this.mirrorSettings = mirrorSettings;
}
public static void handleNewPlayer(PlayerEntity player) { public Array.ArraySettings getArraySettings() {
//Makes sure player has modifier settings (if it doesnt it will create it) if (this.arraySettings == null) this.arraySettings = new Array.ArraySettings();
getModifierSettings(player); return this.arraySettings;
}
//Only on server public void setArraySettings(Array.ArraySettings arraySettings) {
if (!player.level.isClientSide) { if (arraySettings == null) return;
//Send to client this.arraySettings = arraySettings;
ModifierSettingsMessage msg = new ModifierSettingsMessage(getModifierSettings(player)); }
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), msg);
}
}
public static class ModifierSettings { public RadialMirror.RadialMirrorSettings getRadialMirrorSettings() {
private Mirror.MirrorSettings mirrorSettings; if (this.radialMirrorSettings == null) this.radialMirrorSettings = new RadialMirror.RadialMirrorSettings();
private Array.ArraySettings arraySettings; return this.radialMirrorSettings;
private RadialMirror.RadialMirrorSettings radialMirrorSettings; }
private boolean quickReplace = false;
private int reachUpgrade = 0;
public ModifierSettings() { public void setRadialMirrorSettings(RadialMirror.RadialMirrorSettings radialMirrorSettings) {
mirrorSettings = new Mirror.MirrorSettings(); if (radialMirrorSettings == null) return;
arraySettings = new Array.ArraySettings(); this.radialMirrorSettings = radialMirrorSettings;
radialMirrorSettings = new RadialMirror.RadialMirrorSettings(); }
}
public ModifierSettings(Mirror.MirrorSettings mirrorSettings, Array.ArraySettings arraySettings, public boolean doQuickReplace() {
RadialMirror.RadialMirrorSettings radialMirrorSettings, boolean quickReplace, int reachUpgrade) { return quickReplace;
this.mirrorSettings = mirrorSettings; }
this.arraySettings = arraySettings;
this.radialMirrorSettings = radialMirrorSettings;
this.quickReplace = quickReplace;
this.reachUpgrade = reachUpgrade;
}
public Mirror.MirrorSettings getMirrorSettings() { public void setQuickReplace(boolean quickReplace) {
if (this.mirrorSettings == null) this.mirrorSettings = new Mirror.MirrorSettings(); this.quickReplace = quickReplace;
return this.mirrorSettings; }
}
public void setMirrorSettings(Mirror.MirrorSettings mirrorSettings) { public int getReachUpgrade() {
if (mirrorSettings == null) return; return reachUpgrade;
this.mirrorSettings = mirrorSettings; }
}
public Array.ArraySettings getArraySettings() { public void setReachUpgrade(int reachUpgrade) {
if (this.arraySettings == null) this.arraySettings = new Array.ArraySettings(); this.reachUpgrade = reachUpgrade;
return this.arraySettings; //Set mirror radius to max
} int reach = 10;
switch (reachUpgrade) {
case 0: reach = BuildConfig.reach.maxReachLevel0; break;
case 1: reach = BuildConfig.reach.maxReachLevel1; break;
case 2: reach = BuildConfig.reach.maxReachLevel2; break;
case 3: reach = BuildConfig.reach.maxReachLevel3; break;
}
public void setArraySettings(Array.ArraySettings arraySettings) { EffortlessBuilding.log("before "+this.mirrorSettings.radius);
if (arraySettings == null) return;
this.arraySettings = arraySettings;
}
public RadialMirror.RadialMirrorSettings getRadialMirrorSettings() { if (this.mirrorSettings != null)
if (this.radialMirrorSettings == null) this.radialMirrorSettings = new RadialMirror.RadialMirrorSettings(); this.mirrorSettings.radius = reach / 2;
return this.radialMirrorSettings; if (this.radialMirrorSettings != null)
} this.radialMirrorSettings.radius = reach / 2;
public void setRadialMirrorSettings(RadialMirror.RadialMirrorSettings radialMirrorSettings) { EffortlessBuilding.log("after "+this.mirrorSettings.radius);
if (radialMirrorSettings == null) return; }
this.radialMirrorSettings = radialMirrorSettings; }
}
public boolean doQuickReplace() { public static void handleNewPlayer(EntityPlayer player){
return quickReplace; if (getModifierSettings(player) == null) {
} setModifierSettings(player, new ModifierSettings());
}
public void setQuickReplace(boolean quickReplace) { //Only on server
this.quickReplace = quickReplace; if (!player.world.isRemote) {
} //Send to client
ModifierSettingsMessage msg = new ModifierSettingsMessage(getModifierSettings(player));
public int getReachUpgrade() { EffortlessBuilding.packetHandler.sendTo(msg, (EntityPlayerMP) player);
return reachUpgrade; }
} }
public void setReachUpgrade(int reachUpgrade) {
this.reachUpgrade = reachUpgrade;
//Set mirror radius to max
int reach = 10;
switch (reachUpgrade) {
case 0:
reach = BuildConfig.reach.maxReachLevel0.get();
break;
case 1:
reach = BuildConfig.reach.maxReachLevel1.get();
break;
case 2:
reach = BuildConfig.reach.maxReachLevel2.get();
break;
case 3:
reach = BuildConfig.reach.maxReachLevel3.get();
break;
}
if (this.mirrorSettings != null)
this.mirrorSettings.radius = reach / 2;
if (this.radialMirrorSettings != null)
this.radialMirrorSettings.radius = reach / 2;
}
}
} }

View File

@@ -1,194 +1,195 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.BlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.Hand; import net.minecraft.util.EnumHand;
import net.minecraft.util.Mirror; import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation; import net.minecraft.util.Rotation;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class RadialMirror { public class RadialMirror {
public static List<BlockPos> findCoordinates(PlayerEntity player, BlockPos startPos) { public static class RadialMirrorSettings {
List<BlockPos> coordinates = new ArrayList<>(); public boolean enabled = false;
public Vec3d position = new Vec3d(0.5, 64.5, 0.5);
public int slices = 4;
public boolean alternate = false;
public int radius = 20;
public boolean drawLines = true, drawPlanes = false;
//find radial mirror settings for the player public RadialMirrorSettings() {
RadialMirrorSettings r = ModifierSettingsManager.getModifierSettings(player).getRadialMirrorSettings(); }
if (!isEnabled(r, startPos)) return coordinates;
//get angle between slices public RadialMirrorSettings(boolean enabled, Vec3d position, int slices, boolean alternate, int radius, boolean drawLines, boolean drawPlanes) {
double sliceAngle = 2 * Math.PI / r.slices; this.enabled = enabled;
this.position = position;
this.slices = slices;
this.alternate = alternate;
this.radius = radius;
this.drawLines = drawLines;
this.drawPlanes = drawPlanes;
}
Vector3d startVec = new Vector3d(startPos.getX() + 0.5f, startPos.getY() + 0.5f, startPos.getZ() + 0.5f); public int getReach() {
Vector3d relStartVec = startVec.subtract(r.position); return radius * 2;
}
}
double startAngleToCenter = MathHelper.atan2(relStartVec.x, relStartVec.z); public static List<BlockPos> findCoordinates(EntityPlayer player, BlockPos startPos) {
if (startAngleToCenter < 0) startAngleToCenter += Math.PI; List<BlockPos> coordinates = new ArrayList<>();
double startAngleInSlice = startAngleToCenter % sliceAngle;
for (int i = 1; i < r.slices; i++) { //find radial mirror settings for the player
double curAngle = sliceAngle * i; RadialMirrorSettings r = ModifierSettingsManager.getModifierSettings(player).getRadialMirrorSettings();
if (!isEnabled(r, startPos)) return coordinates;
//alternate mirroring of slices //get angle between slices
if (r.alternate && i % 2 == 1) { double sliceAngle = 2 * Math.PI / r.slices;
curAngle = curAngle - startAngleInSlice + (sliceAngle - startAngleInSlice);
}
Vector3d relNewVec = relStartVec.yRot((float) curAngle); Vec3d startVec = new Vec3d(startPos.getX() + 0.5f, startPos.getY() + 0.5f, startPos.getZ() + 0.5f);
BlockPos newBlockPos = new BlockPos(r.position.add(relNewVec)); Vec3d relStartVec = startVec.subtract(r.position);
if (!coordinates.contains(newBlockPos) && !newBlockPos.equals(startPos)) coordinates.add(newBlockPos);
}
return coordinates; double startAngleToCenter = MathHelper.atan2(relStartVec.x, relStartVec.z);
} if (startAngleToCenter < 0) startAngleToCenter += Math.PI;
double startAngleInSlice = startAngleToCenter % sliceAngle;
public static List<BlockState> findBlockStates(PlayerEntity player, BlockPos startPos, BlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) { for (int i = 1; i < r.slices; i++) {
List<BlockState> blockStates = new ArrayList<>(); double curAngle = sliceAngle * i;
List<BlockPos> coordinates = new ArrayList<>(); //to keep track of duplicates
//find radial mirror settings for the player that placed the block //alternate mirroring of slices
RadialMirrorSettings r = ModifierSettingsManager.getModifierSettings(player).getRadialMirrorSettings(); if (r.alternate && i%2 == 1) {
if (!isEnabled(r, startPos)) return blockStates; curAngle = curAngle - startAngleInSlice + (sliceAngle - startAngleInSlice);
}
Vec3d relNewVec = relStartVec.rotateYaw((float) curAngle);
BlockPos newBlockPos = new BlockPos(r.position.add(relNewVec));
if (!coordinates.contains(newBlockPos) && !newBlockPos.equals(startPos)) coordinates.add(newBlockPos);
}
return coordinates;
}
public static List<IBlockState> findBlockStates(EntityPlayer player, BlockPos startPos, IBlockState blockState, ItemStack itemStack, List<ItemStack> itemStacks) {
List<IBlockState> blockStates = new ArrayList<>();
List<BlockPos> coordinates = new ArrayList<>(); //to keep track of duplicates
//find radial mirror settings for the player that placed the block
RadialMirrorSettings r = ModifierSettingsManager.getModifierSettings(player).getRadialMirrorSettings();
if (!isEnabled(r, startPos)) return blockStates;
//get angle between slices //get angle between slices
double sliceAngle = 2 * Math.PI / r.slices; double sliceAngle = 2 * Math.PI / r.slices;
Vector3d startVec = new Vector3d(startPos.getX() + 0.5f, startPos.getY() + 0.5f, startPos.getZ() + 0.5f); Vec3d startVec = new Vec3d(startPos.getX() + 0.5f, startPos.getY() + 0.5f, startPos.getZ() + 0.5f);
Vector3d relStartVec = startVec.subtract(r.position); Vec3d relStartVec = startVec.subtract(r.position);
double startAngleToCenter = MathHelper.atan2(relStartVec.x, relStartVec.z); double startAngleToCenter = MathHelper.atan2(relStartVec.x, relStartVec.z);
double startAngleToCenterMod = startAngleToCenter < 0 ? startAngleToCenter + Math.PI : startAngleToCenter; double startAngleToCenterMod = startAngleToCenter < 0 ? startAngleToCenter + Math.PI : startAngleToCenter;
double startAngleInSlice = startAngleToCenterMod % sliceAngle; double startAngleInSlice = startAngleToCenterMod % sliceAngle;
//Rotate the original blockstate //Rotate the original blockstate
blockState = rotateOriginalBlockState(startAngleToCenter, blockState); blockState = rotateOriginalBlockState(startAngleToCenter, blockState);
//Randomizer bag synergy //Randomizer bag synergy
AbstractRandomizerBagItem randomizerBagItem = null; IItemHandler bagInventory = null;
IItemHandler bagInventory = null; if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemRandomizerBag) {
if (!itemStack.isEmpty() && itemStack.getItem() instanceof AbstractRandomizerBagItem) { bagInventory = ItemRandomizerBag.getBagInventory(itemStack);
randomizerBagItem = (AbstractRandomizerBagItem) itemStack.getItem(); }
bagInventory = randomizerBagItem.getBagInventory(itemStack);
}
BlockState newBlockState; IBlockState newBlockState;
for (int i = 1; i < r.slices; i++) { for (int i = 1; i < r.slices; i++) {
newBlockState = blockState; newBlockState = blockState;
double curAngle = sliceAngle * i; double curAngle = sliceAngle * i;
//alternate mirroring of slices //alternate mirroring of slices
if (r.alternate && i % 2 == 1) { if (r.alternate && i%2 == 1) {
curAngle = curAngle - startAngleInSlice + (sliceAngle - startAngleInSlice); curAngle = curAngle - startAngleInSlice + (sliceAngle - startAngleInSlice);
} }
Vector3d relNewVec = relStartVec.yRot((float) curAngle); Vec3d relNewVec = relStartVec.rotateYaw((float) curAngle);
BlockPos newBlockPos = new BlockPos(r.position.add(relNewVec)); BlockPos newBlockPos = new BlockPos(r.position.add(relNewVec));
if (coordinates.contains(newBlockPos) || newBlockPos.equals(startPos)) continue; //filter out duplicates if (coordinates.contains(newBlockPos) || newBlockPos.equals(startPos)) continue; //filter out duplicates
coordinates.add(newBlockPos); coordinates.add(newBlockPos);
//Randomizer bag synergy //Randomizer bag synergy
if (bagInventory != null) { if (bagInventory != null) {
itemStack = randomizerBagItem.pickRandomStack(bagInventory); itemStack = ItemRandomizerBag.pickRandomStack(bagInventory);
newBlockState = BuildModifiers newBlockState = BuildModifiers
.getBlockStateFromItem(itemStack, player, startPos, Direction.UP, new Vector3d(0, 0, 0), Hand.MAIN_HAND); .getBlockStateFromItem(itemStack, player, startPos, EnumFacing.UP, new Vec3d(0, 0, 0), EnumHand.MAIN_HAND);
newBlockState = rotateOriginalBlockState(startAngleToCenter, newBlockState); newBlockState = rotateOriginalBlockState(startAngleToCenter, newBlockState);
} }
//rotate //rotate
newBlockState = rotateBlockState(relNewVec, newBlockState, r.alternate && i % 2 == 1); newBlockState = rotateBlockState(relNewVec, newBlockState, r.alternate && i%2 == 1);
blockStates.add(newBlockState); blockStates.add(newBlockState);
itemStacks.add(itemStack); itemStacks.add(itemStack);
} }
return blockStates; return blockStates;
} }
private static BlockState rotateOriginalBlockState(double startAngleToCenter, BlockState blockState) { private static IBlockState rotateOriginalBlockState(double startAngleToCenter, IBlockState blockState) {
BlockState newBlockState = blockState; IBlockState newBlockState = blockState;
if (startAngleToCenter < -0.751 * Math.PI || startAngleToCenter > 0.749 * Math.PI) { if (startAngleToCenter < -0.751 * Math.PI || startAngleToCenter > 0.749 * Math.PI) {
newBlockState = blockState.rotate(Rotation.CLOCKWISE_180); newBlockState = blockState.withRotation(Rotation.CLOCKWISE_180);
} else if (startAngleToCenter < -0.251 * Math.PI) { } else if (startAngleToCenter < -0.251 * Math.PI) {
newBlockState = blockState.rotate(Rotation.COUNTERCLOCKWISE_90); newBlockState = blockState.withRotation(Rotation.COUNTERCLOCKWISE_90);
} else if (startAngleToCenter > 0.249 * Math.PI) { } else if (startAngleToCenter > 0.249 * Math.PI) {
newBlockState = blockState.rotate(Rotation.CLOCKWISE_90); newBlockState = blockState.withRotation(Rotation.CLOCKWISE_90);
} }
return newBlockState; return newBlockState;
} }
private static BlockState rotateBlockState(Vector3d relVec, BlockState blockState, boolean alternate) { private static IBlockState rotateBlockState(Vec3d relVec, IBlockState blockState, boolean alternate) {
BlockState newBlockState; IBlockState newBlockState;
double angleToCenter = MathHelper.atan2(relVec.x, relVec.z); //between -PI and PI double angleToCenter = MathHelper.atan2(relVec.x, relVec.z); //between -PI and PI
if (angleToCenter < -0.751 * Math.PI || angleToCenter > 0.749 * Math.PI) { if (angleToCenter < -0.751 * Math.PI || angleToCenter > 0.749 * Math.PI) {
newBlockState = blockState.rotate(Rotation.CLOCKWISE_180); newBlockState = blockState.withRotation(Rotation.CLOCKWISE_180);
if (alternate) { if (alternate) {
newBlockState = newBlockState.mirror(Mirror.FRONT_BACK); newBlockState = newBlockState.withMirror(Mirror.FRONT_BACK);
} }
} else if (angleToCenter < -0.251 * Math.PI) { } else if (angleToCenter < -0.251 * Math.PI) {
newBlockState = blockState.rotate(Rotation.CLOCKWISE_90); newBlockState = blockState.withRotation(Rotation.CLOCKWISE_90);
if (alternate) { if (alternate) {
newBlockState = newBlockState.mirror(Mirror.LEFT_RIGHT); newBlockState = newBlockState.withMirror(Mirror.LEFT_RIGHT);
} }
} else if (angleToCenter > 0.249 * Math.PI) { } else if (angleToCenter > 0.249 * Math.PI) {
newBlockState = blockState.rotate(Rotation.COUNTERCLOCKWISE_90); newBlockState = blockState.withRotation(Rotation.COUNTERCLOCKWISE_90);
if (alternate) { if (alternate) {
newBlockState = newBlockState.mirror(Mirror.LEFT_RIGHT); newBlockState = newBlockState.withMirror(Mirror.LEFT_RIGHT);
} }
} else { } else {
newBlockState = blockState; newBlockState = blockState;
if (alternate) { if (alternate) {
newBlockState = newBlockState.mirror(Mirror.FRONT_BACK); newBlockState = newBlockState.withMirror(Mirror.FRONT_BACK);
} }
} }
return newBlockState; return newBlockState;
} }
public static boolean isEnabled(RadialMirrorSettings r, BlockPos startPos) { public static boolean isEnabled(RadialMirrorSettings r, BlockPos startPos) {
if (r == null || !r.enabled) return false; if (r == null || !r.enabled) return false;
return !(new Vector3d(startPos.getX() + 0.5, startPos.getY() + 0.5, startPos.getZ() + 0.5).subtract(r.position).lengthSqr() > if (new Vec3d(startPos.getX() + 0.5, startPos.getY() + 0.5, startPos.getZ() + 0.5).subtract(r.position).lengthSquared() >
r.radius * r.radius); r.radius * r.radius)
} return false;
public static class RadialMirrorSettings { return true;
public boolean enabled = false; }
public Vector3d position = new Vector3d(0.5, 64.5, 0.5);
public int slices = 4;
public boolean alternate = false;
public int radius = 20;
public boolean drawLines = true, drawPlanes = false;
public RadialMirrorSettings() {
}
public RadialMirrorSettings(boolean enabled, Vector3d position, int slices, boolean alternate, int radius, boolean drawLines, boolean drawPlanes) {
this.enabled = enabled;
this.position = position;
this.slices = slices;
this.alternate = alternate;
this.radius = radius;
this.drawLines = drawLines;
this.drawPlanes = drawPlanes;
}
public int getReach() {
return radius * 2;
}
}
} }

View File

@@ -1,15 +1,15 @@
package nl.requios.effortlessbuilding.buildmodifier; package nl.requios.effortlessbuilding.buildmodifier;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.block.Blocks; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.init.Blocks;
import net.minecraft.item.BlockItem; import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.world.server.ServerWorld;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.helper.FixedStack; import nl.requios.effortlessbuilding.helper.FixedStack;
@@ -21,26 +21,26 @@ import java.util.*;
public class UndoRedo { public class UndoRedo {
//Undo and redo stacks per player //Undo and redo stacks per player
//Gets added to twice in singleplayer (server and client) if not careful. So separate stacks. //Gets added to twice in singleplayer (server and client) if not careful. So separate stacks.
private static final Map<UUID, FixedStack<BlockSet>> undoStacksClient = new HashMap<>(); private static Map<UUID, FixedStack<BlockSet>> undoStacksClient = new HashMap<>();
private static final Map<UUID, FixedStack<BlockSet>> undoStacksServer = new HashMap<>(); private static Map<UUID, FixedStack<BlockSet>> undoStacksServer = new HashMap<>();
private static final Map<UUID, FixedStack<BlockSet>> redoStacksClient = new HashMap<>(); private static Map<UUID, FixedStack<BlockSet>> redoStacksClient = new HashMap<>();
private static final Map<UUID, FixedStack<BlockSet>> redoStacksServer = new HashMap<>(); private static Map<UUID, FixedStack<BlockSet>> redoStacksServer = new HashMap<>();
//add to undo stack //add to undo stack
public static void addUndo(PlayerEntity player, BlockSet blockSet) { public static void addUndo(EntityPlayer player, BlockSet blockSet) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer; Map<UUID, FixedStack<BlockSet>> undoStacks = player.world.isRemote ? undoStacksClient : undoStacksServer;
//Assert coordinates is as long as previous and new blockstate lists //Assert coordinates is as long as previous and new blockstate lists
if (blockSet.getCoordinates().size() != blockSet.getPreviousBlockStates().size() || if (blockSet.getCoordinates().size() != blockSet.getPreviousBlockStates().size() ||
blockSet.getCoordinates().size() != blockSet.getNewBlockStates().size()) { blockSet.getCoordinates().size() != blockSet.getNewBlockStates().size()) {
EffortlessBuilding.logger.error("Coordinates and blockstate lists are not equal length. Coordinates: {}. Previous blockstates: {}. New blockstates: {}.", EffortlessBuilding.logger.error("Coordinates and blockstate lists are not equal length. Coordinates: {}. Previous blockstates: {}. New blockstates: {}.",
blockSet.getCoordinates().size(), blockSet.getPreviousBlockStates().size(), blockSet.getNewBlockStates().size()); blockSet.getCoordinates().size(), blockSet.getPreviousBlockStates().size(), blockSet.getNewBlockStates().size());
} }
//Warn if previous and new blockstate are equal //Warn if previous and new blockstate are equal
//Can happen in a lot of valid cases //Can happen in a lot of valid cases
// for (int i = 0; i < blockSet.getCoordinates().size(); i++) { // for (int i = 0; i < blockSet.getCoordinates().size(); i++) {
// if (blockSet.getPreviousBlockStates().get(i).equals(blockSet.getNewBlockStates().get(i))) { // if (blockSet.getPreviousBlockStates().get(i).equals(blockSet.getNewBlockStates().get(i))) {
// EffortlessBuilding.logger.warn("Previous and new blockstates are equal at index {}. Blockstate: {}.", // EffortlessBuilding.logger.warn("Previous and new blockstates are equal at index {}. Blockstate: {}.",
@@ -48,192 +48,183 @@ public class UndoRedo {
// } // }
// } // }
//If no stack exists, make one //If no stack exists, make one
if (!undoStacks.containsKey(player.getUUID())) { if (!undoStacks.containsKey(player.getUniqueID())) {
undoStacks.put(player.getUUID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize.get()])); undoStacks.put(player.getUniqueID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize]));
} }
undoStacks.get(player.getUUID()).push(blockSet);
}
private static void addRedo(PlayerEntity player, BlockSet blockSet) {
Map<UUID, FixedStack<BlockSet>> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer;
//(No asserts necessary, it's private)
//If no stack exists, make one
if (!redoStacks.containsKey(player.getUUID())) {
redoStacks.put(player.getUUID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize.get()]));
}
redoStacks.get(player.getUUID()).push(blockSet);
}
public static boolean undo(PlayerEntity player) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer;
if (!undoStacks.containsKey(player.getUUID())) return false;
FixedStack<BlockSet> undoStack = undoStacks.get(player.getUUID());
if (undoStack.isEmpty()) return false;
BlockSet blockSet = undoStack.pop();
List<BlockPos> coordinates = blockSet.getCoordinates();
List<BlockState> previousBlockStates = blockSet.getPreviousBlockStates();
List<BlockState> newBlockStates = blockSet.getNewBlockStates();
Vector3d hitVec = blockSet.getHitVec();
//Find up to date itemstacks in player inventory
List<ItemStack> itemStacks = findItemStacksInInventory(player, previousBlockStates);
if (player.level.isClientSide) {
BlockPreviewRenderer.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos());
} else {
//break all those blocks, reset to what they were
for (int i = 0; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue;
//get blockstate from itemstack
BlockState previousBlockState = Blocks.AIR.defaultBlockState();
if (itemStack.getItem() instanceof BlockItem) {
previousBlockState = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
}
if (player.level.isLoaded(coordinate)) {
//check itemstack empty
if (itemStack.isEmpty()) {
itemStack = findItemStackInInventory(player, previousBlockStates.get(i));
//get blockstate from new itemstack
if (!itemStack.isEmpty() && itemStack.getItem() instanceof BlockItem) {
previousBlockState = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
} else {
if (previousBlockStates.get(i).getBlock() != Blocks.AIR)
EffortlessBuilding.logTranslate(player, "", previousBlockStates.get(i).getBlock().getDescriptionId(), " not found in inventory", true);
previousBlockState = Blocks.AIR.defaultBlockState();
}
}
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.level, player, coordinate, true);
//if previousBlockState is air, placeBlock will set it to air
SurvivalHelper.placeBlock(player.level, player, coordinate, previousBlockState, itemStack, Direction.UP, hitVec, true, false, false);
}
}
}
//add to redo
addRedo(player, blockSet);
return true;
}
public static boolean redo(PlayerEntity player) {
Map<UUID, FixedStack<BlockSet>> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer;
if (!redoStacks.containsKey(player.getUUID())) return false;
FixedStack<BlockSet> redoStack = redoStacks.get(player.getUUID());
if (redoStack.isEmpty()) return false;
BlockSet blockSet = redoStack.pop();
List<BlockPos> coordinates = blockSet.getCoordinates();
List<BlockState> previousBlockStates = blockSet.getPreviousBlockStates();
List<BlockState> newBlockStates = blockSet.getNewBlockStates();
Vector3d hitVec = blockSet.getHitVec();
//Find up to date itemstacks in player inventory
List<ItemStack> itemStacks = findItemStacksInInventory(player, newBlockStates);
if (player.level.isClientSide) {
BlockPreviewRenderer.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos());
} else {
//place blocks
for (int i = 0; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue;
//get blockstate from itemstack
BlockState newBlockState = Blocks.AIR.defaultBlockState();
if (itemStack.getItem() instanceof BlockItem) {
newBlockState = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
}
if (player.level.isLoaded(coordinate)) {
//check itemstack empty
if (itemStack.isEmpty()) {
itemStack = findItemStackInInventory(player, newBlockStates.get(i));
//get blockstate from new itemstack
if (!itemStack.isEmpty() && itemStack.getItem() instanceof BlockItem) {
newBlockState = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState();
} else {
if (newBlockStates.get(i).getBlock() != Blocks.AIR)
EffortlessBuilding.logTranslate(player, "", newBlockStates.get(i).getBlock().getDescriptionId(), " not found in inventory", true);
newBlockState = Blocks.AIR.defaultBlockState();
}
}
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.level, player, coordinate, true);
SurvivalHelper.placeBlock(player.level, player, coordinate, newBlockState, itemStack, Direction.UP, hitVec, true, false, false);
}
}
}
//add to undo
addUndo(player, blockSet);
return true;
}
public static void clear(PlayerEntity player) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.level.isClientSide ? undoStacksClient : undoStacksServer;
Map<UUID, FixedStack<BlockSet>> redoStacks = player.level.isClientSide ? redoStacksClient : redoStacksServer;
if (undoStacks.containsKey(player.getUUID())) {
undoStacks.get(player.getUUID()).clear();
}
if (redoStacks.containsKey(player.getUUID())) {
redoStacks.get(player.getUUID()).clear();
}
}
private static List<ItemStack> findItemStacksInInventory(PlayerEntity player, List<BlockState> blockStates) {
List<ItemStack> itemStacks = new ArrayList<>(blockStates.size());
for (BlockState blockState : blockStates) {
itemStacks.add(findItemStackInInventory(player, blockState));
}
return itemStacks;
}
private static ItemStack findItemStackInInventory(PlayerEntity player, BlockState blockState) {
ItemStack itemStack = ItemStack.EMPTY;
if (blockState == null) return itemStack;
//First try previousBlockStates
//TODO try to find itemstack with right blockstate first
// then change line 103 back (get state from item)
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
//then anything it drops undoStacks.get(player.getUniqueID()).push(blockSet);
if (itemStack.isEmpty()) { }
//Cannot check drops on clientside because loot tables are server only
if (!player.level.isClientSide) {
List<ItemStack> itemsDropped = Block.getDrops(blockState, (ServerWorld) player.level, BlockPos.ZERO, null);
for (ItemStack itemStackDropped : itemsDropped) {
if (itemStackDropped.getItem() instanceof BlockItem) {
Block block = ((BlockItem) itemStackDropped.getItem()).getBlock();
itemStack = InventoryHelper.findItemStackInInventory(player, block);
}
}
}
}
//then air private static void addRedo(EntityPlayer player, BlockSet blockSet) {
//(already empty) Map<UUID, FixedStack<BlockSet>> redoStacks = player.world.isRemote ? redoStacksClient : redoStacksServer;
return itemStack; //(No asserts necessary, it's private)
}
//If no stack exists, make one
if (!redoStacks.containsKey(player.getUniqueID())) {
redoStacks.put(player.getUniqueID(), new FixedStack<>(new BlockSet[BuildConfig.survivalBalancers.undoStackSize]));
}
redoStacks.get(player.getUniqueID()).push(blockSet);
}
public static boolean undo(EntityPlayer player) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.world.isRemote ? undoStacksClient : undoStacksServer;
if (!undoStacks.containsKey(player.getUniqueID())) return false;
FixedStack<BlockSet> undoStack = undoStacks.get(player.getUniqueID());
if (undoStack.isEmpty()) return false;
BlockSet blockSet = undoStack.pop();
List<BlockPos> coordinates = blockSet.getCoordinates();
List<IBlockState> previousBlockStates = blockSet.getPreviousBlockStates();
List<IBlockState> newBlockStates = blockSet.getNewBlockStates();
Vec3d hitVec = blockSet.getHitVec();
//Find up to date itemstacks in player inventory
List<ItemStack> itemStacks = findItemStacksInInventory(player, previousBlockStates);
if (player.world.isRemote) {
BlockPreviewRenderer.onBlocksBroken(coordinates, itemStacks, newBlockStates, blockSet.getSecondPos(), blockSet.getFirstPos());
} else {
//break all those blocks, reset to what they were
for (int i = 0; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue;
//get blockstate from itemstack
IBlockState previousBlockState = Blocks.AIR.getDefaultState();
if (itemStack.getItem() instanceof ItemBlock) {
previousBlockState = previousBlockStates.get(i);//((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
}
if (player.world.isBlockLoaded(coordinate, true)) {
//check itemstack empty
if (itemStack.isEmpty()) {
itemStack = findItemStackInInventory(player, previousBlockStates.get(i));
//get blockstate from new itemstack
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemBlock) {
previousBlockState = previousBlockStates.get(i);//((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
} else {
previousBlockState = Blocks.AIR.getDefaultState();
}
}
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.world, player, coordinate, true);
//if previousBlockState is air, placeBlock will set it to air
SurvivalHelper.placeBlock(player.world, player, coordinate, previousBlockState, itemStack, EnumFacing.UP, hitVec, true, false, false);
}
}
}
//add to redo
addRedo(player, blockSet);
return true;
}
public static boolean redo(EntityPlayer player) {
Map<UUID, FixedStack<BlockSet>> redoStacks = player.world.isRemote ? redoStacksClient : redoStacksServer;
if (!redoStacks.containsKey(player.getUniqueID())) return false;
FixedStack<BlockSet> redoStack = redoStacks.get(player.getUniqueID());
if (redoStack.isEmpty()) return false;
BlockSet blockSet = redoStack.pop();
List<BlockPos> coordinates = blockSet.getCoordinates();
List<IBlockState> previousBlockStates = blockSet.getPreviousBlockStates();
List<IBlockState> newBlockStates = blockSet.getNewBlockStates();
Vec3d hitVec = blockSet.getHitVec();
//Find up to date itemstacks in player inventory
List<ItemStack> itemStacks = findItemStacksInInventory(player, newBlockStates);
if (player.world.isRemote) {
BlockPreviewRenderer.onBlocksPlaced(coordinates, itemStacks, newBlockStates, blockSet.getFirstPos(), blockSet.getSecondPos());
} else {
//place blocks
for (int i = 0; i < coordinates.size(); i++) {
BlockPos coordinate = coordinates.get(i);
ItemStack itemStack = itemStacks.get(i);
if (previousBlockStates.get(i).equals(newBlockStates.get(i))) continue;
//get blockstate from itemstack
IBlockState newBlockState = Blocks.AIR.getDefaultState();
if (itemStack.getItem() instanceof ItemBlock) {
newBlockState = newBlockStates.get(i);//((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
}
if (player.world.isBlockLoaded(coordinate, true)) {
//check itemstack empty
if (itemStack.isEmpty()) {
itemStack = findItemStackInInventory(player, newBlockStates.get(i));
//get blockstate from new itemstack
if (!itemStack.isEmpty() && itemStack.getItem() instanceof ItemBlock) {
newBlockState = newBlockStates.get(i);//((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
} else {
newBlockState = Blocks.AIR.getDefaultState();
}
}
if (itemStack.isEmpty()) SurvivalHelper.breakBlock(player.world, player, coordinate, true);
SurvivalHelper.placeBlock(player.world, player, coordinate, newBlockState, itemStack, EnumFacing.UP, hitVec, true, false, false);
}
}
}
//add to undo
addUndo(player, blockSet);
return true;
}
public static void clear(EntityPlayer player) {
Map<UUID, FixedStack<BlockSet>> undoStacks = player.world.isRemote ? undoStacksClient : undoStacksServer;
Map<UUID, FixedStack<BlockSet>> redoStacks = player.world.isRemote ? redoStacksClient : redoStacksServer;
if (undoStacks.containsKey(player.getUniqueID())) {
undoStacks.get(player.getUniqueID()).clear();
}
if (redoStacks.containsKey(player.getUniqueID())) {
redoStacks.get(player.getUniqueID()).clear();
}
}
private static List<ItemStack> findItemStacksInInventory(EntityPlayer player, List<IBlockState> blockStates) {
List<ItemStack> itemStacks = new ArrayList<>(blockStates.size());
for (IBlockState blockState : blockStates) {
itemStacks.add(findItemStackInInventory(player, blockState));
}
return itemStacks;
}
private static ItemStack findItemStackInInventory(EntityPlayer player, IBlockState blockState) {
ItemStack itemStack = ItemStack.EMPTY;
if (blockState == null) return itemStack;
//First try previousBlockStates
//TODO try to find itemstack with right blockstate first
// then change line 103 back (get state from item)
itemStack = InventoryHelper.findItemStackInInventory(player, blockState.getBlock());
//then anything it drops
if (itemStack.isEmpty()) {
Item itemDropped = blockState.getBlock().getItemDropped(blockState, player.world.rand, 10);
if (itemDropped instanceof ItemBlock) {
Block block = ((ItemBlock) itemDropped).getBlock();
itemStack = InventoryHelper.findItemStackInInventory(player, block);
}
}
//then air
//(already empty)
return itemStack;
}
} }

View File

@@ -1,38 +1,42 @@
package nl.requios.effortlessbuilding.capability; package nl.requios.effortlessbuilding.capability;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler; import net.minecraftforge.items.ItemStackHandler;
import nl.requios.effortlessbuilding.item.RandomizerBagItem; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
public class ItemHandlerCapabilityProvider implements ICapabilitySerializable<CompoundNBT> { public class ItemHandlerCapabilityProvider implements ICapabilitySerializable<NBTTagCompound> {
IItemHandler itemHandler; IItemHandler itemHandler = new ItemStackHandler(ItemRandomizerBag.INV_SIZE);
public ItemHandlerCapabilityProvider(int size) { @Override
itemHandler = new ItemStackHandler(size); public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing) {
} if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return true;
return false;
}
@Nonnull @Nullable
@Override @Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { public <T> T getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) {
return CapabilityItemHandler.ITEM_HANDLER_CAPABILITY.orEmpty(cap, LazyOptional.of(() -> itemHandler)); if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
} return (T) itemHandler;
return null;
}
@Override @Override
public CompoundNBT serializeNBT() { public NBTTagCompound serializeNBT() {
return ((ItemStackHandler) itemHandler).serializeNBT(); return ((ItemStackHandler) itemHandler).serializeNBT();
} }
@Override @Override
public void deserializeNBT(CompoundNBT nbt) { public void deserializeNBT(NBTTagCompound nbt) {
((ItemStackHandler) itemHandler).deserializeNBT(nbt); ((ItemStackHandler) itemHandler).deserializeNBT(nbt);
} }
} }

View File

@@ -1,105 +1,104 @@
package nl.requios.effortlessbuilding.capability; package nl.requios.effortlessbuilding.capability;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.INBT; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings; import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.*;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ModeCapabilityManager { public class ModeCapabilityManager {
@CapabilityInject(IModeCapability.class) @CapabilityInject(IModeCapability.class)
public final static Capability<IModeCapability> modeCapability = null; public final static Capability<IModeCapability> modeCapability = null;
// Allows for the capability to persist after death. public interface IModeCapability {
@SubscribeEvent ModeSettings getModeData();
public static void clonePlayer(PlayerEvent.Clone event) {
LazyOptional<IModeCapability> original = event.getOriginal().getCapability(modeCapability, null);
LazyOptional<IModeCapability> clone = event.getEntity().getCapability(modeCapability, null);
clone.ifPresent(cloneModeCapability ->
original.ifPresent(originalModeCapability ->
cloneModeCapability.setModeData(originalModeCapability.getModeData())));
}
public interface IModeCapability { void setModeData(ModeSettings modeSettings);
ModeSettings getModeData(); }
void setModeData(ModeSettings modeSettings); public static class ModeCapability implements IModeCapability {
} private ModeSettings modeSettings;
public static class ModeCapability implements IModeCapability { @Override
private ModeSettings modeSettings; public ModeSettings getModeData() {
return modeSettings;
}
@Override @Override
public ModeSettings getModeData() { public void setModeData(ModeSettings modeSettings) {
return modeSettings; this.modeSettings = modeSettings;
} }
}
@Override public static class Storage implements Capability.IStorage<IModeCapability> {
public void setModeData(ModeSettings modeSettings) { @Override
this.modeSettings = modeSettings; public NBTBase writeNBT(Capability<IModeCapability> capability, IModeCapability instance, EnumFacing side) {
} NBTTagCompound compound = new NBTTagCompound();
} ModeSettings modeSettings = instance.getModeData();
if (modeSettings == null) modeSettings = new ModeSettings();
public static class Storage implements Capability.IStorage<IModeCapability> { //compound.setInteger("buildMode", modeSettings.getBuildMode().ordinal());
@Override
public INBT writeNBT(Capability<IModeCapability> capability, IModeCapability instance, Direction side) {
CompoundNBT compound = new CompoundNBT();
ModeSettings modeSettings = instance.getModeData();
if (modeSettings == null) modeSettings = new ModeSettings();
//compound.putInteger("buildMode", modeSettings.getBuildMode().ordinal()); //TODO add mode settings
//TODO add mode settings return compound;
}
return compound; @Override
} public void readNBT(Capability<IModeCapability> capability, IModeCapability instance, EnumFacing side, NBTBase nbt) {
NBTTagCompound compound = (NBTTagCompound) nbt;
@Override //BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.values()[compound.getInteger("buildMode")];
public void readNBT(Capability<IModeCapability> capability, IModeCapability instance, Direction side, INBT nbt) {
CompoundNBT compound = (CompoundNBT) nbt;
//BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.values()[compound.getInteger("buildMode")]; //TODO add mode settings
//TODO add mode settings ModeSettings modeSettings = new ModeSettings(BuildModes.BuildModeEnum.NORMAL);
instance.setModeData(modeSettings);
}
}
ModeSettings modeSettings = new ModeSettings(BuildModes.BuildModeEnum.NORMAL); public static class Provider implements ICapabilitySerializable<NBTBase> {
instance.setModeData(modeSettings); IModeCapability inst = modeCapability.getDefaultInstance();
}
}
public static class Provider implements ICapabilitySerializable<INBT> { @Override
IModeCapability inst = modeCapability.getDefaultInstance(); public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing) {
return capability == modeCapability;
}
@Nonnull @Override
@Override public <T> T getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) {
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { if (capability == modeCapability) return modeCapability.<T>cast(inst);
return modeCapability.orEmpty(cap, LazyOptional.of(() -> inst)); return null;
} }
@Override @Override
public INBT serializeNBT() { public NBTBase serializeNBT() {
return modeCapability.getStorage().writeNBT(modeCapability, inst, null); return modeCapability.getStorage().writeNBT(modeCapability, inst, null);
} }
@Override @Override
public void deserializeNBT(INBT nbt) { public void deserializeNBT(NBTBase nbt) {
modeCapability.getStorage().readNBT(modeCapability, inst, null, nbt); modeCapability.getStorage().readNBT(modeCapability, inst, null, nbt);
} }
}
} // Allows for the capability to persist after death.
@SubscribeEvent
public static void clonePlayer(PlayerEvent.Clone event) {
IModeCapability original = event.getOriginal().getCapability(modeCapability, null);
IModeCapability clone = event.getEntity().getCapability(modeCapability, null);
clone.setModeData(original.getModeData());
}
} }

View File

@@ -1,17 +1,16 @@
package nl.requios.effortlessbuilding.capability; package nl.requios.effortlessbuilding.capability;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.INBT; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.ICapabilitySerializable; import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.event.entity.player.PlayerEvent; import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import nl.requios.effortlessbuilding.buildmodifier.Array; import nl.requios.effortlessbuilding.buildmodifier.Array;
import nl.requios.effortlessbuilding.buildmodifier.Mirror; import nl.requios.effortlessbuilding.buildmodifier.Mirror;
import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
@@ -19,165 +18,164 @@ import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings; import static nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.*;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
@Mod.EventBusSubscriber @Mod.EventBusSubscriber
public class ModifierCapabilityManager { public class ModifierCapabilityManager {
@CapabilityInject(IModifierCapability.class) @CapabilityInject(IModifierCapability.class)
public final static Capability<IModifierCapability> modifierCapability = null; public final static Capability<IModifierCapability> modifierCapability = null;
// Allows for the capability to persist after death. public interface IModifierCapability {
@SubscribeEvent ModifierSettings getModifierData();
public static void clonePlayer(PlayerEvent.Clone event) {
LazyOptional<IModifierCapability> original = event.getOriginal().getCapability(modifierCapability, null);
LazyOptional<IModifierCapability> clone = event.getEntity().getCapability(modifierCapability, null);
clone.ifPresent(cloneModifierCapability ->
original.ifPresent(originalModifierCapability ->
cloneModifierCapability.setModifierData(originalModifierCapability.getModifierData())));
}
public interface IModifierCapability { void setModifierData(ModifierSettings modifierSettings);
ModifierSettings getModifierData(); }
void setModifierData(ModifierSettings modifierSettings); public static class ModifierCapability implements IModifierCapability {
} private ModifierSettings modifierSettings;
public static class ModifierCapability implements IModifierCapability { @Override
private ModifierSettings modifierSettings; public ModifierSettings getModifierData() {
return modifierSettings;
}
@Override @Override
public ModifierSettings getModifierData() { public void setModifierData(ModifierSettings modifierSettings) {
return modifierSettings; this.modifierSettings = modifierSettings;
} }
}
@Override public static class Storage implements Capability.IStorage<IModifierCapability> {
public void setModifierData(ModifierSettings modifierSettings) { @Override
this.modifierSettings = modifierSettings; public NBTBase writeNBT(Capability<IModifierCapability> capability, IModifierCapability instance, EnumFacing side) {
} NBTTagCompound compound = new NBTTagCompound();
} ModifierSettings modifierSettings = instance.getModifierData();
if (modifierSettings == null) modifierSettings = new ModifierSettings();
public static class Storage implements Capability.IStorage<IModifierCapability> { //MIRROR
@Override Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
public INBT writeNBT(Capability<IModifierCapability> capability, IModifierCapability instance, Direction side) { if (m == null) m = new Mirror.MirrorSettings();
CompoundNBT compound = new CompoundNBT(); compound.setBoolean("mirrorEnabled", m.enabled);
ModifierSettings modifierSettings = instance.getModifierData(); compound.setDouble("mirrorPosX", m.position.x);
if (modifierSettings == null) modifierSettings = new ModifierSettings(); compound.setDouble("mirrorPosY", m.position.y);
compound.setDouble("mirrorPosZ", m.position.z);
compound.setBoolean("mirrorX", m.mirrorX);
compound.setBoolean("mirrorY", m.mirrorY);
compound.setBoolean("mirrorZ", m.mirrorZ);
compound.setInteger("mirrorRadius", m.radius);
compound.setBoolean("mirrorDrawLines", m.drawLines);
compound.setBoolean("mirrorDrawPlanes", m.drawPlanes);
//MIRROR //ARRAY
Mirror.MirrorSettings m = modifierSettings.getMirrorSettings(); Array.ArraySettings a = modifierSettings.getArraySettings();
if (m == null) m = new Mirror.MirrorSettings(); if (a == null) a = new Array.ArraySettings();
compound.putBoolean("mirrorEnabled", m.enabled); compound.setBoolean("arrayEnabled", a.enabled);
compound.putDouble("mirrorPosX", m.position.x); compound.setInteger("arrayOffsetX", a.offset.getX());
compound.putDouble("mirrorPosY", m.position.y); compound.setInteger("arrayOffsetY", a.offset.getY());
compound.putDouble("mirrorPosZ", m.position.z); compound.setInteger("arrayOffsetZ", a.offset.getZ());
compound.putBoolean("mirrorX", m.mirrorX); compound.setInteger("arrayCount", a.count);
compound.putBoolean("mirrorY", m.mirrorY);
compound.putBoolean("mirrorZ", m.mirrorZ);
compound.putInt("mirrorRadius", m.radius);
compound.putBoolean("mirrorDrawLines", m.drawLines);
compound.putBoolean("mirrorDrawPlanes", m.drawPlanes);
//ARRAY compound.setInteger("reachUpgrade", modifierSettings.getReachUpgrade());
Array.ArraySettings a = modifierSettings.getArraySettings();
if (a == null) a = new Array.ArraySettings();
compound.putBoolean("arrayEnabled", a.enabled);
compound.putInt("arrayOffsetX", a.offset.getX());
compound.putInt("arrayOffsetY", a.offset.getY());
compound.putInt("arrayOffsetZ", a.offset.getZ());
compound.putInt("arrayCount", a.count);
compound.putInt("reachUpgrade", modifierSettings.getReachUpgrade()); //compound.setBoolean("quickReplace", buildSettings.doQuickReplace()); dont save quickreplace
//compound.putBoolean("quickReplace", buildSettings.doQuickReplace()); dont save quickreplace //RADIAL MIRROR
RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
if (r == null) r = new RadialMirror.RadialMirrorSettings();
compound.setBoolean("radialMirrorEnabled", r.enabled);
compound.setDouble("radialMirrorPosX", r.position.x);
compound.setDouble("radialMirrorPosY", r.position.y);
compound.setDouble("radialMirrorPosZ", r.position.z);
compound.setInteger("radialMirrorSlices", r.slices);
compound.setBoolean("radialMirrorAlternate", r.alternate);
compound.setInteger("radialMirrorRadius", r.radius);
compound.setBoolean("radialMirrorDrawLines", r.drawLines);
compound.setBoolean("radialMirrorDrawPlanes", r.drawPlanes);
//RADIAL MIRROR return compound;
RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings(); }
if (r == null) r = new RadialMirror.RadialMirrorSettings();
compound.putBoolean("radialMirrorEnabled", r.enabled);
compound.putDouble("radialMirrorPosX", r.position.x);
compound.putDouble("radialMirrorPosY", r.position.y);
compound.putDouble("radialMirrorPosZ", r.position.z);
compound.putInt("radialMirrorSlices", r.slices);
compound.putBoolean("radialMirrorAlternate", r.alternate);
compound.putInt("radialMirrorRadius", r.radius);
compound.putBoolean("radialMirrorDrawLines", r.drawLines);
compound.putBoolean("radialMirrorDrawPlanes", r.drawPlanes);
return compound; @Override
} public void readNBT(Capability<IModifierCapability> capability, IModifierCapability instance, EnumFacing side, NBTBase nbt) {
NBTTagCompound compound = (NBTTagCompound) nbt;
@Override //MIRROR
public void readNBT(Capability<IModifierCapability> capability, IModifierCapability instance, Direction side, INBT nbt) { boolean mirrorEnabled = compound.getBoolean("mirrorEnabled");
CompoundNBT compound = (CompoundNBT) nbt; Vec3d mirrorPosition = new Vec3d(
compound.getDouble("mirrorPosX"),
compound.getDouble("mirrorPosY"),
compound.getDouble("mirrorPosZ"));
boolean mirrorX = compound.getBoolean("mirrorX");
boolean mirrorY = compound.getBoolean("mirrorY");
boolean mirrorZ = compound.getBoolean("mirrorZ");
int mirrorRadius = compound.getInteger("mirrorRadius");
boolean mirrorDrawLines = compound.getBoolean("mirrorDrawLines");
boolean mirrorDrawPlanes = compound.getBoolean("mirrorDrawPlanes");
Mirror.MirrorSettings mirrorSettings = new Mirror.MirrorSettings(mirrorEnabled, mirrorPosition, mirrorX, mirrorY, mirrorZ, mirrorRadius, mirrorDrawLines, mirrorDrawPlanes);
//MIRROR //ARRAY
boolean mirrorEnabled = compound.getBoolean("mirrorEnabled"); boolean arrayEnabled = compound.getBoolean("arrayEnabled");
Vector3d mirrorPosition = new Vector3d( BlockPos arrayOffset = new BlockPos(
compound.getDouble("mirrorPosX"), compound.getInteger("arrayOffsetX"),
compound.getDouble("mirrorPosY"), compound.getInteger("arrayOffsetY"),
compound.getDouble("mirrorPosZ")); compound.getInteger("arrayOffsetZ"));
boolean mirrorX = compound.getBoolean("mirrorX"); int arrayCount = compound.getInteger("arrayCount");
boolean mirrorY = compound.getBoolean("mirrorY"); Array.ArraySettings arraySettings = new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount);
boolean mirrorZ = compound.getBoolean("mirrorZ");
int mirrorRadius = compound.getInt("mirrorRadius");
boolean mirrorDrawLines = compound.getBoolean("mirrorDrawLines");
boolean mirrorDrawPlanes = compound.getBoolean("mirrorDrawPlanes");
Mirror.MirrorSettings mirrorSettings = new Mirror.MirrorSettings(mirrorEnabled, mirrorPosition, mirrorX, mirrorY, mirrorZ, mirrorRadius, mirrorDrawLines, mirrorDrawPlanes);
//ARRAY int reachUpgrade = compound.getInteger("reachUpgrade");
boolean arrayEnabled = compound.getBoolean("arrayEnabled");
BlockPos arrayOffset = new BlockPos(
compound.getInt("arrayOffsetX"),
compound.getInt("arrayOffsetY"),
compound.getInt("arrayOffsetZ"));
int arrayCount = compound.getInt("arrayCount");
Array.ArraySettings arraySettings = new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount);
int reachUpgrade = compound.getInt("reachUpgrade"); //boolean quickReplace = compound.getBoolean("quickReplace"); //dont load quickreplace
//boolean quickReplace = compound.getBoolean("quickReplace"); //dont load quickreplace //RADIAL MIRROR
boolean radialMirrorEnabled = compound.getBoolean("radialMirrorEnabled");
Vec3d radialMirrorPosition = new Vec3d(
compound.getDouble("radialMirrorPosX"),
compound.getDouble("radialMirrorPosY"),
compound.getDouble("radialMirrorPosZ"));
int radialMirrorSlices = compound.getInteger("radialMirrorSlices");
boolean radialMirrorAlternate = compound.getBoolean("radialMirrorAlternate");
int radialMirrorRadius = compound.getInteger("radialMirrorRadius");
boolean radialMirrorDrawLines = compound.getBoolean("radialMirrorDrawLines");
boolean radialMirrorDrawPlanes = compound.getBoolean("radialMirrorDrawPlanes");
RadialMirror.RadialMirrorSettings radialMirrorSettings = new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPosition,
radialMirrorSlices, radialMirrorAlternate, radialMirrorRadius, radialMirrorDrawLines, radialMirrorDrawPlanes);
//RADIAL MIRROR ModifierSettings modifierSettings = new ModifierSettings(mirrorSettings, arraySettings, radialMirrorSettings, false, reachUpgrade);
boolean radialMirrorEnabled = compound.getBoolean("radialMirrorEnabled"); instance.setModifierData(modifierSettings);
Vector3d radialMirrorPosition = new Vector3d( }
compound.getDouble("radialMirrorPosX"), }
compound.getDouble("radialMirrorPosY"),
compound.getDouble("radialMirrorPosZ"));
int radialMirrorSlices = compound.getInt("radialMirrorSlices");
boolean radialMirrorAlternate = compound.getBoolean("radialMirrorAlternate");
int radialMirrorRadius = compound.getInt("radialMirrorRadius");
boolean radialMirrorDrawLines = compound.getBoolean("radialMirrorDrawLines");
boolean radialMirrorDrawPlanes = compound.getBoolean("radialMirrorDrawPlanes");
RadialMirror.RadialMirrorSettings radialMirrorSettings = new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPosition,
radialMirrorSlices, radialMirrorAlternate, radialMirrorRadius, radialMirrorDrawLines, radialMirrorDrawPlanes);
ModifierSettings modifierSettings = new ModifierSettings(mirrorSettings, arraySettings, radialMirrorSettings, false, reachUpgrade); public static class Provider implements ICapabilitySerializable<NBTBase> {
instance.setModifierData(modifierSettings); IModifierCapability inst = modifierCapability.getDefaultInstance();
}
}
public static class Provider implements ICapabilitySerializable<INBT> { @Override
public boolean hasCapability(@Nonnull Capability<?> capability, @Nullable EnumFacing facing) {
return capability == modifierCapability;
}
IModifierCapability inst = modifierCapability.getDefaultInstance(); @Override
public <T> T getCapability(@Nonnull Capability<T> capability, @Nullable EnumFacing facing) {
if (capability == modifierCapability) return modifierCapability.<T>cast(inst);
return null;
}
@Nonnull @Override
@Override public NBTBase serializeNBT() {
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { return modifierCapability.getStorage().writeNBT(modifierCapability, inst, null);
return modifierCapability.orEmpty(cap, LazyOptional.of(() -> inst)); }
}
@Override @Override
public INBT serializeNBT() { public void deserializeNBT(NBTBase nbt) {
return modifierCapability.getStorage().writeNBT(modifierCapability, inst, null); modifierCapability.getStorage().readNBT(modifierCapability, inst, null, nbt);
} }
}
@Override // Allows for the capability to persist after death.
public void deserializeNBT(INBT nbt) { @SubscribeEvent
modifierCapability.getStorage().readNBT(modifierCapability, inst, null, nbt); public static void clonePlayer(PlayerEvent.Clone event) {
} IModifierCapability original = event.getOriginal().getCapability(modifierCapability, null);
IModifierCapability clone = event.getEntity().getCapability(modifierCapability, null);
} clone.setModifierData(original.getModifierData());
}
} }

View File

@@ -1,43 +1,46 @@
package nl.requios.effortlessbuilding.command; package nl.requios.effortlessbuilding.command;
import com.mojang.brigadier.CommandDispatcher; import net.minecraft.command.CommandBase;
import com.mojang.brigadier.arguments.IntegerArgumentType; import net.minecraft.command.CommandException;
import net.minecraft.command.CommandSource; import net.minecraft.command.ICommandSender;
import net.minecraft.command.Commands; import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.StringTextComponent; import net.minecraft.server.MinecraftServer;
import net.minecraftforge.fml.network.PacketDistributor; import net.minecraft.util.text.TextComponentString;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.network.ModifierSettingsMessage; import nl.requios.effortlessbuilding.network.ModifierSettingsMessage;
import nl.requios.effortlessbuilding.network.PacketHandler;
public class CommandReach { public class CommandReach extends CommandBase {
@Override
public String getName() {
return "reach";
}
public static void register(CommandDispatcher<CommandSource> dispatcher) { @Override
dispatcher.register(Commands.literal("reach").then(Commands.literal("set").then(Commands.argument("level", IntegerArgumentType.integer(0, 3)).executes((context) -> { public String getUsage(ICommandSender sender) {
return setReachLevel(context.getSource().getPlayerOrException(), IntegerArgumentType.getInteger(context, "level")); return "commands.reach.usage";
}))).then(Commands.literal("get").executes((context -> { }
return getReachLevel(context.getSource().getPlayerOrException());
}))));
}
private static int setReachLevel(ServerPlayerEntity player, int level) { @Override
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
modifierSettings.setReachUpgrade(level); EntityPlayerMP player = (EntityPlayerMP) sender;
ModifierSettingsManager.setModifierSettings(player, modifierSettings); if (args.length != 1) {
//Send to client int reachUpgrade = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade();
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), new ModifierSettingsMessage(modifierSettings)); EffortlessBuilding.log(player, "Current reach: level "+reachUpgrade);
throw new WrongUsageException("commands.reach.usage");
}
player.sendMessage(new StringTextComponent("Reach level of " + player.getName().getString() + " set to " + modifierSettings.getReachUpgrade()), player.getUUID()); if (sender instanceof EntityPlayerMP) {
//Set reach level to args[0]
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setReachUpgrade(Integer.valueOf(args[0]));
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
//Send to client
EffortlessBuilding.packetHandler.sendTo(new ModifierSettingsMessage(modifierSettings), player);
return 1; sender.sendMessage(new TextComponentString("Reach level of " + sender.getName() + " set to " + modifierSettings
} .getReachUpgrade()));
}
private static int getReachLevel(ServerPlayerEntity player) { }
int reachUpgrade = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade();
EffortlessBuilding.log(player, "Current reach: level " + reachUpgrade);
return 1;
}
} }

View File

@@ -0,0 +1,13 @@
package nl.requios.effortlessbuilding.compatibility;
import mod.chiselsandbits.core.ClientSide;
import mod.chiselsandbits.helpers.ChiselToolType;
import net.minecraft.util.EnumHand;
public class ActiveChiselsAndBitsProxy implements IChiselsAndBitsProxy {
@Override
public boolean isHoldingChiselTool(EnumHand hand) {
ChiselToolType toolType = ClientSide.instance.getHeldToolType(hand);
return toolType != null && toolType.hasMenu();
}
}

View File

@@ -1,62 +1,117 @@
package nl.requios.effortlessbuilding.compatibility; package nl.requios.effortlessbuilding.compatibility;
import net.minecraft.block.BlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.item.BlockItem; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.item.AbstractRandomizerBagItem; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
public class CompatHelper { public class CompatHelper {
// Get a handle to the dank null item instance. This will remain null if the mod doesn't load
// and all checks will fail, so it works.
@GameRegistry.ObjectHolder("danknull:dank_null")
public static final Item dankNullItem = null;
public static void setup() { public static IChiselsAndBitsProxy chiselsAndBitsProxy;
} public static void postInit() {
if (Loader.isModLoaded("chiselsandbits")) {
// reflection to avoid hard dependency
try {
chiselsAndBitsProxy = Class.forName("nl.requios.effortlessbuilding.compatibility.ActiveChiselsAndBitsProxy").asSubclass(ActiveChiselsAndBitsProxy.class).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
} else {
chiselsAndBitsProxy = new DummyChiselsAndBitsProxy();
}
}
// Check if the item given is a proxy for blocks. For now, we check for the randomizer bag, // Check if the item given is a proxy for blocks. For now, we check for the randomizer bag,
// /dank/null, or plain old blocks. // /dank/null, or plain old blocks.
public static boolean isItemBlockProxy(ItemStack stack) { public static boolean isItemBlockProxy(ItemStack stack) {
Item item = stack.getItem(); Item item = stack.getItem();
if (item instanceof BlockItem) if (item instanceof ItemBlock)
return true; return true;
return item instanceof AbstractRandomizerBagItem; if ((item instanceof ItemRandomizerBag))
} return true;
if (item == dankNullItem)
return true;
return false;
}
// Get the block to be placed by this proxy. For the /dank/null, it's the slot stack // Get the block to be placed by this proxy. For the /dank/null, it's the slot stack
// pointed to by nbt integer selectedIndex. // pointed to by nbt integer selectedIndex.
public static ItemStack getItemBlockFromStack(ItemStack proxy) { public static ItemStack getItemBlockFromStack(ItemStack proxy) {
Item proxyItem = proxy.getItem(); Item proxyItem = proxy.getItem();
if (proxyItem instanceof BlockItem) if (proxyItem instanceof ItemBlock)
return proxy; return proxy;
//Randomizer Bag //Randomizer Bag
if (proxyItem instanceof AbstractRandomizerBagItem) { if (proxyItem instanceof ItemRandomizerBag) {
ItemStack itemStack = proxy; ItemStack itemStack = proxy;
while (!(itemStack.getItem() instanceof BlockItem || itemStack.isEmpty())) { while (!(itemStack.getItem() instanceof ItemBlock || itemStack.isEmpty())) {
if (itemStack.getItem() instanceof AbstractRandomizerBagItem) { if (itemStack.getItem() instanceof ItemRandomizerBag)
AbstractRandomizerBagItem randomizerBagItem = (AbstractRandomizerBagItem) itemStack.getItem(); itemStack = ItemRandomizerBag.pickRandomStack(ItemRandomizerBag.getBagInventory(itemStack));
itemStack = randomizerBagItem.pickRandomStack(randomizerBagItem.getBagInventory(itemStack)); }
} return itemStack;
} }
return itemStack;
}
return ItemStack.EMPTY; //Dank Null
} if (proxyItem == dankNullItem) {
int index = 0;
if (proxy.hasTagCompound() && proxy.getTagCompound().hasKey("selectedIndex"))
index = proxy.getTagCompound().getInteger("selectedIndex");
return proxy.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(index);
}
public static ItemStack getItemBlockByState(ItemStack stack, BlockState state) { return ItemStack.EMPTY;
if (state == null) return ItemStack.EMPTY; }
Item blockItem = Item.byBlock(state.getBlock()); public static ItemStack getItemBlockByState(ItemStack stack, IBlockState state) {
if (stack.getItem() instanceof BlockItem) Item blockItem = Item.getItemFromBlock(state.getBlock());
return stack; if (stack.getItem() instanceof ItemBlock)
else if (stack.getItem() instanceof AbstractRandomizerBagItem) { return stack;
AbstractRandomizerBagItem randomizerBagItem = (AbstractRandomizerBagItem) stack.getItem(); else if (stack.getItem() instanceof ItemRandomizerBag) {
IItemHandler bagInventory = randomizerBagItem.getBagInventory(stack); IItemHandler bagInventory = ItemRandomizerBag.getBagInventory(stack);
return randomizerBagItem.findStack(bagInventory, blockItem); return ItemRandomizerBag.findStack(bagInventory, blockItem);
} } else if (stack.getItem() == dankNullItem) {
int index = itemHandlerSlotForItem(stack, blockItem);
if (index >= 0)
return stack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).getStackInSlot(index);
}
return ItemStack.EMPTY;
}
// Handle IItemHandler slot stacks not being modifiable. We must call IItemHandler#extractItem,
// because the ItemStack returned by IItemHandler#getStackInSlot isn't modifiable.
public static void shrinkStack(ItemStack origStack, ItemStack curStack, EntityPlayer player) {
//Hacky way to get the origstack, because given origStack is itemblock stack and never a proxy
origStack = player.getHeldItem(EnumHand.MAIN_HAND);
if (origStack.getItem() == dankNullItem) {
int index = itemHandlerSlotForItem(origStack, curStack.getItem());
origStack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).extractItem(index, 1, false);
} else
curStack.shrink(1);
}
private static int itemHandlerSlotForItem(ItemStack stack, Item blockItem) {
IItemHandler handler = stack.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
for (int i = 0; i < handler.getSlots(); i++) {
ItemStack ref = handler.getStackInSlot(i);
if (ref.getItem() instanceof ItemBlock)
if (ref.getItem() == blockItem)
return i;
}
return -1;
}
return ItemStack.EMPTY;
}
} }

View File

@@ -0,0 +1,10 @@
package nl.requios.effortlessbuilding.compatibility;
import net.minecraft.util.EnumHand;
public class DummyChiselsAndBitsProxy implements IChiselsAndBitsProxy {
@Override
public boolean isHoldingChiselTool(EnumHand hand) {
return false;
}
}

View File

@@ -0,0 +1,7 @@
package nl.requios.effortlessbuilding.compatibility;
import net.minecraft.util.EnumHand;
public interface IChiselsAndBitsProxy {
boolean isHoldingChiselTool(EnumHand hand);
}

View File

@@ -1,149 +0,0 @@
package nl.requios.effortlessbuilding.gui;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.Hand;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.SlotItemHandler;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.item.DiamondRandomizerBagItem;
public class DiamondRandomizerBagContainer extends Container {
private static final int INV_START = DiamondRandomizerBagItem.INV_SIZE,
INV_END = INV_START + 26,
HOTBAR_START = INV_END + 1,
HOTBAR_END = HOTBAR_START + 8;
private final IItemHandler bagInventory;
public DiamondRandomizerBagContainer(ContainerType<?> type, int id){
super(type, id);
bagInventory = null;
}
//Client
public DiamondRandomizerBagContainer(int id, PlayerInventory playerInventory, PacketBuffer packetBuffer) {
this(id, playerInventory);
}
//Server?
public DiamondRandomizerBagContainer(int containerId, PlayerInventory playerInventory) {
this(containerId, playerInventory, new ItemStackHandler(DiamondRandomizerBagItem.INV_SIZE));
}
public DiamondRandomizerBagContainer(int containerId, PlayerInventory playerInventory, IItemHandler inventory) {
super(EffortlessBuilding.DIAMOND_RANDOMIZER_BAG_CONTAINER.get(), containerId);
bagInventory = inventory;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 9; ++j) {
this.addSlot(new SlotItemHandler(bagInventory, j + i * 9, 8 + j * 18, 18 + i * 18));
}
}
// add player inventory slots
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 9; ++j) {
addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18));
}
}
// add hotbar slots
for (int i = 0; i < 9; ++i) {
addSlot(new Slot(playerInventory, i, 8 + i * 18, 142));
}
}
@Override
public boolean stillValid(PlayerEntity playerIn) {
return true;
}
@Override
public Slot getSlot(int parSlotIndex) {
if (parSlotIndex >= slots.size())
parSlotIndex = slots.size() - 1;
return super.getSlot(parSlotIndex);
}
@Override
public ItemStack quickMoveStack(PlayerEntity playerIn, int slotIndex) {
ItemStack itemstack = ItemStack.EMPTY;
Slot slot = this.slots.get(slotIndex);
if (slot != null && slot.hasItem()) {
ItemStack itemstack1 = slot.getItem();
itemstack = itemstack1.copy();
// If item is in our custom inventory
if (slotIndex < INV_START) {
// try to place in player inventory / action bar
if (!this.moveItemStackTo(itemstack1, INV_START, HOTBAR_END + 1, true)) {
return ItemStack.EMPTY;
}
slot.onQuickCraft(itemstack1, itemstack);
}
// Item is in inventory / hotbar, try to place in custom inventory or armor slots
else {
/**
* Implementation number 1: Shift-click into your custom inventory
*/
if (slotIndex >= INV_START) {
// place in custom inventory
if (!this.moveItemStackTo(itemstack1, 0, INV_START, false)) {
return ItemStack.EMPTY;
}
}
}
if (itemstack1.getCount() == 0) {
slot.set(ItemStack.EMPTY);
} else {
slot.setChanged();
}
if (itemstack1.getCount() == itemstack.getCount()) {
return ItemStack.EMPTY;
}
slot.onTake(playerIn, itemstack1);
}
return itemstack;
}
/**
* You should override this method to prevent the player from moving the stack that
* opened the inventory, otherwise if the player moves it, the inventory will not
* be able to save properly
* @return
*/
@Override
public ItemStack clicked(int slot, int dragType, ClickType clickTypeIn, PlayerEntity player) {
// this will prevent the player from interacting with the item that opened the inventory:
if (slot >= 0 && getSlot(slot) != null && getSlot(slot).getItem().equals(player.getItemInHand(Hand.MAIN_HAND))) {
//Do nothing;
return ItemStack.EMPTY;
}
return super.clicked(slot, dragType, clickTypeIn, player);
}
/**
* Callback for when the crafting gui is closed.
*/
@Override
public void removed(PlayerEntity player) {
super.removed(player);
if (!player.level.isClientSide) {
broadcastChanges();
}
}
}

View File

@@ -1,47 +0,0 @@
package nl.requios.effortlessbuilding.gui;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import javax.annotation.ParametersAreNonnullByDefault;
@OnlyIn(Dist.CLIENT)
@ParametersAreNonnullByDefault
public class DiamondRandomizerBagScreen extends ContainerScreen<DiamondRandomizerBagContainer> {
private static final ResourceLocation guiTextures =
new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/container/diamondrandomizerbag.png");
public DiamondRandomizerBagScreen(DiamondRandomizerBagContainer randomizerBagContainer, PlayerInventory playerInventory, ITextComponent title) {
super(randomizerBagContainer, playerInventory, title);
imageHeight = 167;
}
@Override
public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) {
renderBackground(ms);
super.render(ms, mouseX, mouseY, partialTicks);
this.renderTooltip(ms, mouseX, mouseY);
}
@Override
protected void renderLabels(MatrixStack ms, int mouseX, int mouseY) {
font.draw(ms, this.title, 8, 6, 0x404040);
font.draw(ms, inventory.getDisplayName(), 8, imageHeight - 96 + 2, 0x404040);
}
@Override
protected void renderBg(MatrixStack ms, float partialTicks, int mouseX, int mouseY) {
RenderSystem.color3f(1.0F, 1.0F, 1.0F);
minecraft.getTextureManager().bind(guiTextures);
int marginHorizontal = (width - imageWidth) / 2;
int marginVertical = (height - imageHeight) / 2;
blit(ms, marginHorizontal, marginVertical, 0, 0, imageWidth, imageHeight);
}
}

View File

@@ -1,147 +0,0 @@
package nl.requios.effortlessbuilding.gui;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.Hand;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.SlotItemHandler;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.item.GoldenRandomizerBagItem;
public class GoldenRandomizerBagContainer extends Container {
private static final int INV_START = GoldenRandomizerBagItem.INV_SIZE,
INV_END = INV_START + 26,
HOTBAR_START = INV_END + 1,
HOTBAR_END = HOTBAR_START + 8;
private final IItemHandler bagInventory;
public GoldenRandomizerBagContainer(ContainerType<?> type, int id){
super(type, id);
bagInventory = null;
}
//Client
public GoldenRandomizerBagContainer(int id, PlayerInventory playerInventory, PacketBuffer packetBuffer) {
this(id, playerInventory);
}
//Server?
public GoldenRandomizerBagContainer(int containerId, PlayerInventory playerInventory) {
this(containerId, playerInventory, new ItemStackHandler(GoldenRandomizerBagItem.INV_SIZE));
}
public GoldenRandomizerBagContainer(int containerId, PlayerInventory playerInventory, IItemHandler inventory) {
super(EffortlessBuilding.GOLDEN_RANDOMIZER_BAG_CONTAINER.get(), containerId);
bagInventory = inventory;
for (int i = 0; i < GoldenRandomizerBagItem.INV_SIZE; ++i) {
this.addSlot(new SlotItemHandler(bagInventory, i, 8 + (18 * i), 20));
}
// add player inventory slots
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 9; ++j) {
addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 51 + i * 18));
}
}
// add hotbar slots
for (int i = 0; i < 9; ++i) {
addSlot(new Slot(playerInventory, i, 8 + i * 18, 109));
}
}
@Override
public boolean stillValid(PlayerEntity playerIn) {
return true;
}
@Override
public Slot getSlot(int parSlotIndex) {
if (parSlotIndex >= slots.size())
parSlotIndex = slots.size() - 1;
return super.getSlot(parSlotIndex);
}
@Override
public ItemStack quickMoveStack(PlayerEntity playerIn, int slotIndex) {
ItemStack itemstack = ItemStack.EMPTY;
Slot slot = this.slots.get(slotIndex);
if (slot != null && slot.hasItem()) {
ItemStack itemstack1 = slot.getItem();
itemstack = itemstack1.copy();
// If item is in our custom inventory
if (slotIndex < INV_START) {
// try to place in player inventory / action bar
if (!this.moveItemStackTo(itemstack1, INV_START, HOTBAR_END + 1, true)) {
return ItemStack.EMPTY;
}
slot.onQuickCraft(itemstack1, itemstack);
}
// Item is in inventory / hotbar, try to place in custom inventory or armor slots
else {
/**
* Implementation number 1: Shift-click into your custom inventory
*/
if (slotIndex >= INV_START) {
// place in custom inventory
if (!this.moveItemStackTo(itemstack1, 0, INV_START, false)) {
return ItemStack.EMPTY;
}
}
}
if (itemstack1.getCount() == 0) {
slot.set(ItemStack.EMPTY);
} else {
slot.setChanged();
}
if (itemstack1.getCount() == itemstack.getCount()) {
return ItemStack.EMPTY;
}
slot.onTake(playerIn, itemstack1);
}
return itemstack;
}
/**
* You should override this method to prevent the player from moving the stack that
* opened the inventory, otherwise if the player moves it, the inventory will not
* be able to save properly
* @return
*/
@Override
public ItemStack clicked(int slot, int dragType, ClickType clickTypeIn, PlayerEntity player) {
// this will prevent the player from interacting with the item that opened the inventory:
if (slot >= 0 && getSlot(slot) != null && getSlot(slot).getItem().equals(player.getItemInHand(Hand.MAIN_HAND))) {
//Do nothing;
return ItemStack.EMPTY;
}
return super.clicked(slot, dragType, clickTypeIn, player);
}
/**
* Callback for when the crafting gui is closed.
*/
@Override
public void removed(PlayerEntity player) {
super.removed(player);
if (!player.level.isClientSide) {
broadcastChanges();
}
}
}

View File

@@ -1,47 +0,0 @@
package nl.requios.effortlessbuilding.gui;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import javax.annotation.ParametersAreNonnullByDefault;
@OnlyIn(Dist.CLIENT)
@ParametersAreNonnullByDefault
public class GoldenRandomizerBagScreen extends ContainerScreen<GoldenRandomizerBagContainer> {
private static final ResourceLocation guiTextures =
new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/container/goldenrandomizerbag.png");
public GoldenRandomizerBagScreen(GoldenRandomizerBagContainer randomizerBagContainer, PlayerInventory playerInventory, ITextComponent title) {
super(randomizerBagContainer, playerInventory, title);
imageHeight = 134;
}
@Override
public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) {
renderBackground(ms);
super.render(ms, mouseX, mouseY, partialTicks);
this.renderTooltip(ms, mouseX, mouseY);
}
@Override
protected void renderLabels(MatrixStack ms, int mouseX, int mouseY) {
font.draw(ms, this.title, 8, 6, 0x404040);
font.draw(ms, inventory.getDisplayName(), 8, imageHeight - 96 + 2, 0x404040);
}
@Override
protected void renderBg(MatrixStack ms, float partialTicks, int mouseX, int mouseY) {
RenderSystem.color3f(1.0F, 1.0F, 1.0F);
minecraft.getTextureManager().bind(guiTextures);
int marginHorizontal = (width - imageWidth) / 2;
int marginVertical = (height - imageHeight) / 2;
blit(ms, marginHorizontal, marginVertical, 0, 0, imageWidth, imageHeight);
}
}

View File

@@ -1,147 +1,130 @@
package nl.requios.effortlessbuilding.gui; package nl.requios.effortlessbuilding.gui;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.container.ClickType; import net.minecraft.inventory.ClickType;
import net.minecraft.inventory.container.Container; import net.minecraft.inventory.Container;
import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.Slot;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer; import net.minecraft.util.EnumHand;
import net.minecraft.util.Hand;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.SlotItemHandler; import net.minecraftforge.items.SlotItemHandler;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.item.RandomizerBagItem;
public class RandomizerBagContainer extends Container { public class RandomizerBagContainer extends Container {
private static final int INV_START = RandomizerBagItem.INV_SIZE, private final IItemHandler bagInventory;
INV_END = INV_START + 26, private final int sizeInventory;
HOTBAR_START = INV_END + 1,
HOTBAR_END = HOTBAR_START + 8;
private final IItemHandler bagInventory;
public RandomizerBagContainer(ContainerType<?> type, int id){ private static final int INV_START = ItemRandomizerBag.INV_SIZE, INV_END = INV_START + 26,
super(type, id); HOTBAR_START = INV_END + 1, HOTBAR_END = HOTBAR_START + 8;
bagInventory = null;
}
//Client public RandomizerBagContainer(InventoryPlayer parInventoryPlayer, IItemHandler parIInventory) {
public RandomizerBagContainer(int id, PlayerInventory playerInventory, PacketBuffer packetBuffer) { bagInventory = parIInventory;
this(id, playerInventory); sizeInventory = bagInventory.getSlots();
} for (int i = 0; i < sizeInventory; ++i) {
this.addSlotToContainer(new SlotItemHandler(bagInventory, i, 44 + (18 * i), 20));
}
//Server? // add player inventory slots
public RandomizerBagContainer(int containerId, PlayerInventory playerInventory) { int i;
this(containerId, playerInventory, new ItemStackHandler(RandomizerBagItem.INV_SIZE)); for (i = 0; i < 3; ++i) {
} for (int j = 0; j < 9; ++j) {
addSlotToContainer(new Slot(parInventoryPlayer, j + i * 9 + 9, 8 + j * 18, 51 + i * 18));
}
}
public RandomizerBagContainer(int containerId, PlayerInventory playerInventory, IItemHandler inventory) { // add hotbar slots
super(EffortlessBuilding.RANDOMIZER_BAG_CONTAINER.get(), containerId); for (i = 0; i < 9; ++i) {
bagInventory = inventory; addSlotToContainer(new Slot(parInventoryPlayer, i, 8 + i * 18, 109));
}
}
for (int i = 0; i < RandomizerBagItem.INV_SIZE; ++i) { @Override
this.addSlot(new SlotItemHandler(bagInventory, i, 44 + (18 * i), 20)); public boolean canInteractWith(EntityPlayer playerIn) {
} return true;
}
// add player inventory slots @Override
for (int i = 0; i < 3; ++i) { public Slot getSlot(int parSlotIndex)
for (int j = 0; j < 9; ++j) { {
addSlot(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 51 + i * 18)); if(parSlotIndex >= inventorySlots.size())
} parSlotIndex = inventorySlots.size() - 1;
} return super.getSlot(parSlotIndex);
}
// add hotbar slots @Override
for (int i = 0; i < 9; ++i) { public ItemStack transferStackInSlot(EntityPlayer playerIn, int slotIndex) {
addSlot(new Slot(playerInventory, i, 8 + i * 18, 109)); ItemStack itemstack = ItemStack.EMPTY;
} Slot slot = this.inventorySlots.get(slotIndex);
}
@Override if (slot != null && slot.getHasStack()) {
public boolean stillValid(PlayerEntity playerIn) { ItemStack itemstack1 = slot.getStack();
return true; itemstack = itemstack1.copy();
}
@Override // If item is in our custom inventory
public Slot getSlot(int parSlotIndex) { if (slotIndex < INV_START) {
if (parSlotIndex >= slots.size()) // try to place in player inventory / action bar
parSlotIndex = slots.size() - 1; if (!this.mergeItemStack(itemstack1, INV_START, HOTBAR_END + 1, true)) {
return super.getSlot(parSlotIndex); return ItemStack.EMPTY;
} }
@Override slot.onSlotChange(itemstack1, itemstack);
public ItemStack quickMoveStack(PlayerEntity playerIn, int slotIndex) { }
ItemStack itemstack = ItemStack.EMPTY; // Item is in inventory / hotbar, try to place in custom inventory or armor slots
Slot slot = this.slots.get(slotIndex); else {
/**
* Implementation number 1: Shift-click into your custom inventory
*/
if (slotIndex >= INV_START) {
// place in custom inventory
if (!this.mergeItemStack(itemstack1, 0, INV_START, false)) {
return ItemStack.EMPTY;
}
}
if (slot != null && slot.hasItem()) { }
ItemStack itemstack1 = slot.getItem();
itemstack = itemstack1.copy();
// If item is in our custom inventory if (itemstack1.getCount() == 0) {
if (slotIndex < INV_START) { slot.putStack(ItemStack.EMPTY);
// try to place in player inventory / action bar } else {
if (!this.moveItemStackTo(itemstack1, INV_START, HOTBAR_END + 1, true)) { slot.onSlotChanged();
return ItemStack.EMPTY; }
}
slot.onQuickCraft(itemstack1, itemstack); if (itemstack1.getCount() == itemstack.getCount()) {
} return ItemStack.EMPTY;
// Item is in inventory / hotbar, try to place in custom inventory or armor slots }
else {
/**
* Implementation number 1: Shift-click into your custom inventory
*/
if (slotIndex >= INV_START) {
// place in custom inventory
if (!this.moveItemStackTo(itemstack1, 0, INV_START, false)) {
return ItemStack.EMPTY;
}
}
}
if (itemstack1.getCount() == 0) { slot.onTake(playerIn, itemstack1);
slot.set(ItemStack.EMPTY); }
} else {
slot.setChanged();
}
if (itemstack1.getCount() == itemstack.getCount()) { return itemstack;
return ItemStack.EMPTY; }
}
slot.onTake(playerIn, itemstack1); /**
} * You should override this method to prevent the player from moving the stack that
* opened the inventory, otherwise if the player moves it, the inventory will not
* be able to save properly
*/
@Override
public ItemStack slotClick(int slot, int dragType, ClickType clickTypeIn, EntityPlayer player) {
// this will prevent the player from interacting with the item that opened the inventory:
if (slot >= 0 && getSlot(slot) != null && getSlot(slot).getStack().equals(player.getHeldItem(EnumHand.MAIN_HAND))) {
return ItemStack.EMPTY;
}
return super.slotClick(slot, dragType, clickTypeIn, player);
}
return itemstack; /**
} * Callback for when the crafting gui is closed.
*/
/** @Override
* You should override this method to prevent the player from moving the stack that public void onContainerClosed(EntityPlayer player)
* opened the inventory, otherwise if the player moves it, the inventory will not {
* be able to save properly super.onContainerClosed(player);
* @return if(!player.world.isRemote)
*/ {
@Override detectAndSendChanges();
public ItemStack clicked(int slot, int dragType, ClickType clickTypeIn, PlayerEntity player) { }
// this will prevent the player from interacting with the item that opened the inventory: }
if (slot >= 0 && getSlot(slot) != null && getSlot(slot).getItem().equals(player.getItemInHand(Hand.MAIN_HAND))) {
//Do nothing;
return ItemStack.EMPTY;
}
return super.clicked(slot, dragType, clickTypeIn, player);
}
/**
* Callback for when the crafting gui is closed.
*/
@Override
public void removed(PlayerEntity player) {
super.removed(player);
if (!player.level.isClientSide) {
broadcastChanges();
}
}
} }

View File

@@ -0,0 +1,49 @@
package nl.requios.effortlessbuilding.gui;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.EffortlessBuilding;
@SideOnly(Side.CLIENT)
public class RandomizerBagGuiContainer extends GuiContainer {
private static final ResourceLocation guiTextures =
new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/container/randomizerbag.png");
private final InventoryPlayer inventoryPlayer;
private final IItemHandler inventoryBag;
public RandomizerBagGuiContainer(InventoryPlayer inventoryPlayer, IItemHandler inventoryBag) {
super(new RandomizerBagContainer(inventoryPlayer, inventoryBag));
this.inventoryPlayer = inventoryPlayer;
this.inventoryBag = inventoryBag;
ySize = 134;
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
drawDefaultBackground();
super.drawScreen(mouseX, mouseY, partialTicks);
this.renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
String s = "Randomizer Bag";
fontRenderer.drawString(s, 8, 6, 0x404040);
fontRenderer.drawString(inventoryPlayer.getDisplayName().getUnformattedText(), 8, ySize - 96 + 2, 0x404040);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
mc.getTextureManager().bindTexture(guiTextures);
int marginHorizontal = (width - xSize) / 2;
int marginVertical = (height - ySize) / 2;
drawTexturedModalRect(marginHorizontal, marginVertical, 0, 0, xSize, ySize);
}
}

View File

@@ -0,0 +1,41 @@
package nl.requios.effortlessbuilding.gui;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.network.IGuiHandler;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import javax.annotation.Nullable;
public class RandomizerBagGuiHandler implements IGuiHandler {
@Nullable
@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
if (ID == EffortlessBuilding.RANDOMIZER_BAG_GUI) {
// Use the player's held item to create the container
IItemHandler capability = player.getHeldItemMainhand().hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null) ?
player.getHeldItemMainhand().getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null) :
player.getHeldItemOffhand().getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
return new RandomizerBagContainer(player.inventory, capability);
}
return null;
}
@Nullable
@Override
@SideOnly(Side.CLIENT)
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
if (ID == EffortlessBuilding.RANDOMIZER_BAG_GUI) {
// Use the player's held item to create the client-side gui container
IItemHandler capability = player.getHeldItemMainhand().hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null) ?
player.getHeldItemMainhand().getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null) :
player.getHeldItemOffhand().getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
return new RandomizerBagGuiContainer(player.inventory, capability);
}
return null;
}
}

View File

@@ -1,47 +0,0 @@
package nl.requios.effortlessbuilding.gui;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import javax.annotation.ParametersAreNonnullByDefault;
@OnlyIn(Dist.CLIENT)
@ParametersAreNonnullByDefault
public class RandomizerBagScreen extends ContainerScreen<RandomizerBagContainer> {
private static final ResourceLocation guiTextures =
new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/container/randomizerbag.png");
public RandomizerBagScreen(RandomizerBagContainer randomizerBagContainer, PlayerInventory playerInventory, ITextComponent title) {
super(randomizerBagContainer, playerInventory, title);//new TranslationTextComponent("effortlessbuilding.screen.randomizer_bag"));
imageHeight = 134;
}
@Override
public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) {
renderBackground(ms);
super.render(ms, mouseX, mouseY, partialTicks);
this.renderTooltip(ms, mouseX, mouseY);
}
@Override
protected void renderLabels(MatrixStack ms, int mouseX, int mouseY) {
font.draw(ms, this.title, 8, 6, 0x404040);
font.draw(ms, inventory.getDisplayName(), 8, imageHeight - 96 + 2, 0x404040);
}
@Override
protected void renderBg(MatrixStack ms, float partialTicks, int mouseX, int mouseY) {
RenderSystem.color3f(1.0F, 1.0F, 1.0F);
minecraft.getTextureManager().bind(guiTextures);
int marginHorizontal = (width - imageWidth) / 2;
int marginVertical = (height - imageHeight) / 2;
blit(ms, marginHorizontal, marginVertical, 0, 0, imageWidth, imageHeight);
}
}

View File

@@ -1,311 +0,0 @@
package nl.requios.effortlessbuilding.gui.buildmode;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SimpleSound;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.client.gui.widget.list.ExtendedList;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.client.gui.widget.ExtendedButton;
import net.minecraftforge.fml.client.gui.widget.Slider;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import javax.annotation.ParametersAreNonnullByDefault;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class PlayerSettingsGui extends Screen {
protected int left, right, top, bottom;
protected boolean showShaderList = false;
private Button shaderTypeButton;
private ShaderTypeList shaderTypeList;
private Button closeButton;
public PlayerSettingsGui() {
super(new TranslationTextComponent("effortlessbuilding.screen.player_settings"));
}
@Override
protected void init() {
left = this.width / 2 - 140;
right = this.width / 2 + 140;
top = this.height / 2 - 100;
bottom = this.height / 2 + 100;
int yy = top;
shaderTypeList = new ShaderTypeList(this.minecraft);
this.children.add(shaderTypeList);
//TODO set selected name
ITextComponent currentShaderName = ShaderType.DISSOLVE_BLUE.name;
shaderTypeButton = new ExtendedButton(right - 180, yy, 180, 20, currentShaderName, (button) -> {
showShaderList = !showShaderList;
});
addButton(shaderTypeButton);
yy += 50;
Slider slider = new Slider(right - 200, yy, 200, 20, StringTextComponent.EMPTY, StringTextComponent.EMPTY, 0.5, 2.0, 1.0, true, true, (button) -> {
});
addButton(slider);
closeButton = new ExtendedButton(left + 50, bottom - 20, 180, 20, new StringTextComponent("Done"), (button) -> this.minecraft.player.closeContainer());
addButton(closeButton);
}
@Override
public void tick() {
super.tick();
}
@Override
public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) {
this.renderBackground(ms);
int yy = top;
font.draw(ms, "Shader type", left, yy + 5, 0xFFFFFF);
yy += 50;
font.draw(ms, "Shader speed", left, yy + 5, 0xFFFFFF);
super.render(ms, mouseX, mouseY, partialTicks);
if (showShaderList)
this.shaderTypeList.render(ms, mouseX, mouseY, partialTicks);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) {
super.mouseClicked(mouseX, mouseY, mouseButton);
if (showShaderList) {
if (!shaderTypeList.isMouseOver(mouseX, mouseY) && !shaderTypeButton.isMouseOver(mouseX, mouseY))
showShaderList = false;
}
return true;
}
@Override
public void removed() {
ShaderTypeList.ShaderTypeEntry selectedShader = shaderTypeList.getSelected();
//TODO save and remove
}
public enum ShaderType {
DISSOLVE_BLUE("Dissolve Blue"),
DISSOLVE_ORANGE("Dissolve Orange");
public ITextComponent name;
ShaderType(ITextComponent name) {
this.name = name;
}
ShaderType(String name) {
this.name = new StringTextComponent(name);
}
}
//Inspired by LanguageScreen
@OnlyIn(Dist.CLIENT)
class ShaderTypeList extends ExtendedList<PlayerSettingsGui.ShaderTypeList.ShaderTypeEntry> {
public ShaderTypeList(Minecraft mcIn) {
super(mcIn, 180, 140, top + 20, top + 100, 18);
this.setLeftPos(right - width);
for (int i = 0; i < 40; i++) {
for (ShaderType shaderType : ShaderType.values()) {
ShaderTypeEntry shaderTypeEntry = new ShaderTypeEntry(shaderType);
addEntry(shaderTypeEntry);
//TODO setSelected to this if appropriate
}
}
if (this.getSelected() != null) {
this.centerScrollOn(this.getSelected());
}
}
@Override
public int getRowWidth() {
return width;
}
@Override
public void setSelected(PlayerSettingsGui.ShaderTypeList.ShaderTypeEntry selected) {
super.setSelected(selected);
Minecraft.getInstance().getSoundManager().play(SimpleSound.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
EffortlessBuilding.log("Selected shader " + selected.shaderType.name);
shaderTypeButton.setMessage(selected.shaderType.name);
// showShaderList = false;
}
@Override
public boolean mouseClicked(double p_mouseClicked_1_, double p_mouseClicked_3_, int p_mouseClicked_5_) {
if (!showShaderList) return false;
return super.mouseClicked(p_mouseClicked_1_, p_mouseClicked_3_, p_mouseClicked_5_);
}
@Override
public boolean mouseReleased(double p_mouseReleased_1_, double p_mouseReleased_3_, int p_mouseReleased_5_) {
if (!showShaderList) return false;
return super.mouseReleased(p_mouseReleased_1_, p_mouseReleased_3_, p_mouseReleased_5_);
}
@Override
public boolean mouseDragged(double p_mouseDragged_1_, double p_mouseDragged_3_, int p_mouseDragged_5_, double p_mouseDragged_6_, double p_mouseDragged_8_) {
if (!showShaderList) return false;
return super.mouseDragged(p_mouseDragged_1_, p_mouseDragged_3_, p_mouseDragged_5_, p_mouseDragged_6_, p_mouseDragged_8_);
}
@Override
public boolean mouseScrolled(double p_mouseScrolled_1_, double p_mouseScrolled_3_, double p_mouseScrolled_5_) {
if (!showShaderList) return false;
return super.mouseScrolled(p_mouseScrolled_1_, p_mouseScrolled_3_, p_mouseScrolled_5_);
}
@Override
public boolean isMouseOver(double p_isMouseOver_1_, double p_isMouseOver_3_) {
if (!showShaderList) return false;
return super.isMouseOver(p_isMouseOver_1_, p_isMouseOver_3_);
}
protected boolean isFocused() {
return PlayerSettingsGui.this.getFocused() == this;
}
@Override
protected int getScrollbarPosition() {
return right - 6;
}
//From AbstractList, disabled parts
@Override
public void render(MatrixStack ms, int p_render_1_, int p_render_2_, float p_render_3_) {
this.renderBackground(ms);
int i = this.getScrollbarPosition();
int j = i + 6;
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferbuilder = tessellator.getBuilder();
// this.minecraft.getTextureManager().bindTexture(AbstractGui.BACKGROUND_LOCATION);
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE);
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
float f = 32.0F;
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_COLOR);
bufferbuilder.vertex(this.x0, this.y1, 0.0D).color(20, 20, 20, 180).endVertex();
bufferbuilder.vertex(this.x1, this.y1, 0.0D).color(20, 20, 20, 180).endVertex();
bufferbuilder.vertex(this.x1, this.y0, 0.0D).color(20, 20, 20, 180).endVertex();
bufferbuilder.vertex(this.x0, this.y0, 0.0D).color(20, 20, 20, 180).endVertex();
tessellator.end();
int k = this.getRowLeft();
int l = this.y0 + 4 - (int) this.getScrollAmount();
if (this.renderHeader) {
this.renderHeader(ms, k, l, tessellator);
}
this.renderList(ms, k, l, p_render_1_, p_render_2_, p_render_3_);
RenderSystem.disableDepthTest();
// this.renderHoleBackground(0, this.y0, 255, 255);
// this.renderHoleBackground(this.y1, this.height, 255, 255);
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE);
RenderSystem.disableAlphaTest();
RenderSystem.shadeModel(7425);
RenderSystem.disableTexture();
// int i1 = 4;
// bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
// bufferbuilder.pos((double)this.x0, (double)(this.y0 + 4), 0.0D).tex(0.0F, 1.0F).color(0, 0, 0, 0).endVertex();
// bufferbuilder.pos((double)this.x1, (double)(this.y0 + 4), 0.0D).tex(1.0F, 1.0F).color(0, 0, 0, 0).endVertex();
// bufferbuilder.pos((double)this.x1, (double)this.y0, 0.0D).tex(1.0F, 0.0F).color(0, 0, 0, 255).endVertex();
// bufferbuilder.pos((double)this.x0, (double)this.y0, 0.0D).tex(0.0F, 0.0F).color(0, 0, 0, 255).endVertex();
// tessellator.draw();
// bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
// bufferbuilder.pos((double)this.x0, (double)this.y1, 0.0D).tex(0.0F, 1.0F).color(0, 0, 0, 255).endVertex();
// bufferbuilder.pos((double)this.x1, (double)this.y1, 0.0D).tex(1.0F, 1.0F).color(0, 0, 0, 255).endVertex();
// bufferbuilder.pos((double)this.x1, (double)(this.y1 - 4), 0.0D).tex(1.0F, 0.0F).color(0, 0, 0, 0).endVertex();
// bufferbuilder.pos((double)this.x0, (double)(this.y1 - 4), 0.0D).tex(0.0F, 0.0F).color(0, 0, 0, 0).endVertex();
// tessellator.draw();
//SCROLLBAR
int j1 = this.getMaxScroll();
if (j1 > 0) {
int k1 = (int) ((float) ((this.y1 - this.y0) * (this.y1 - this.y0)) / (float) this.getMaxPosition());
k1 = MathHelper.clamp(k1, 32, this.y1 - this.y0 - 8);
int l1 = (int) this.getScrollAmount() * (this.y1 - this.y0 - k1) / j1 + this.y0;
if (l1 < this.y0) {
l1 = this.y0;
}
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
bufferbuilder.vertex(i, this.y1, 0.0D).uv(0.0F, 1.0F).color(0, 0, 0, 255).endVertex();
bufferbuilder.vertex(j, this.y1, 0.0D).uv(1.0F, 1.0F).color(0, 0, 0, 255).endVertex();
bufferbuilder.vertex(j, this.y0, 0.0D).uv(1.0F, 0.0F).color(0, 0, 0, 255).endVertex();
bufferbuilder.vertex(i, this.y0, 0.0D).uv(0.0F, 0.0F).color(0, 0, 0, 255).endVertex();
tessellator.end();
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
bufferbuilder.vertex(i, l1 + k1, 0.0D).uv(0.0F, 1.0F).color(128, 128, 128, 255).endVertex();
bufferbuilder.vertex(j, l1 + k1, 0.0D).uv(1.0F, 1.0F).color(128, 128, 128, 255).endVertex();
bufferbuilder.vertex(j, l1, 0.0D).uv(1.0F, 0.0F).color(128, 128, 128, 255).endVertex();
bufferbuilder.vertex(i, l1, 0.0D).uv(0.0F, 0.0F).color(128, 128, 128, 255).endVertex();
tessellator.end();
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
bufferbuilder.vertex(i, l1 + k1 - 1, 0.0D).uv(0.0F, 1.0F).color(192, 192, 192, 255).endVertex();
bufferbuilder.vertex(j - 1, l1 + k1 - 1, 0.0D).uv(1.0F, 1.0F).color(192, 192, 192, 255).endVertex();
bufferbuilder.vertex(j - 1, l1, 0.0D).uv(1.0F, 0.0F).color(192, 192, 192, 255).endVertex();
bufferbuilder.vertex(i, l1, 0.0D).uv(0.0F, 0.0F).color(192, 192, 192, 255).endVertex();
tessellator.end();
}
// this.renderDecorations(p_render_1_, p_render_2_);
RenderSystem.enableTexture();
RenderSystem.shadeModel(7424);
RenderSystem.enableAlphaTest();
RenderSystem.disableBlend();
}
public int getMaxScroll() {
return Math.max(0, this.getMaxPosition() - (this.y1 - this.y0 - 4));
}
@OnlyIn(Dist.CLIENT)
public class ShaderTypeEntry extends ExtendedList.AbstractListEntry<ShaderTypeEntry> {
private final ShaderType shaderType;
public ShaderTypeEntry(ShaderType shaderType) {
this.shaderType = shaderType;
}
@Override
public void render(MatrixStack ms, int itemIndex, int rowTop, int rowLeft, int rowWidth, int rowHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) {
if (rowTop + 10 > ShaderTypeList.this.y0 && rowTop + rowHeight - 5 < ShaderTypeList.this.y1)
drawString(ms, font, shaderType.name, ShaderTypeList.this.x0 + 8, rowTop + 4, 0xFFFFFF);
}
@Override
public boolean mouseClicked(double p_mouseClicked_1_, double p_mouseClicked_3_, int p_mouseClicked_5_) {
if (p_mouseClicked_5_ == 0) {
setSelected(this);
return true;
} else {
return false;
}
}
}
}
}

View File

@@ -1,201 +1,214 @@
package nl.requios.effortlessbuilding.gui.buildmodifier; package nl.requios.effortlessbuilding.gui.buildmodifier;
import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.widget.Widget;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.client.config.GuiCheckBox;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.Array; import nl.requios.effortlessbuilding.buildmodifier.Array;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.gui.elements.GuiCheckBoxFixed;
import nl.requios.effortlessbuilding.gui.elements.GuiCollapsibleScrollEntry; import nl.requios.effortlessbuilding.gui.elements.GuiCollapsibleScrollEntry;
import nl.requios.effortlessbuilding.gui.elements.GuiNumberField; import nl.requios.effortlessbuilding.gui.elements.GuiNumberField;
import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane; import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@OnlyIn(Dist.CLIENT)
public class ArraySettingsGui extends GuiCollapsibleScrollEntry { public class ArraySettingsGui extends GuiCollapsibleScrollEntry {
protected List<GuiNumberField> arrayNumberFieldList = new ArrayList<>(); protected List<GuiNumberField> arrayNumberFieldList = new ArrayList<>();
private GuiCheckBoxFixed buttonArrayEnabled; private GuiCheckBox buttonArrayEnabled;
private GuiNumberField textArrayOffsetX, textArrayOffsetY, textArrayOffsetZ, textArrayCount; private GuiNumberField textArrayOffsetX, textArrayOffsetY, textArrayOffsetZ, textArrayCount;
public ArraySettingsGui(GuiScrollPane scrollPane) { public ArraySettingsGui(GuiScrollPane scrollPane) {
super(scrollPane); super(scrollPane);
} }
@Override @Override
public void init(List<Widget> buttons) { public int initGui(int id, List<GuiButton> buttonList) {
super.init(buttons); id = super.initGui(id, buttonList);
int y = top; int y = top;
buttonArrayEnabled = new GuiCheckBoxFixed(left - 15 + 8, y, "", false) { buttonArrayEnabled = new GuiCheckBox(id++, left - 15 + 8, y, "", false);
@Override buttonList.add(buttonArrayEnabled);
public void onClick(double mouseX, double mouseY) {
super.onClick(mouseX, mouseY);
setCollapsed(!buttonArrayEnabled.isChecked());
}
};
buttons.add(buttonArrayEnabled);
y = top + 20; y = top + 20;
textArrayOffsetX = new GuiNumberField(font, buttons, left + 70, y, 50, 18); textArrayOffsetX = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 70, y, 50, 18);
textArrayOffsetX.setNumber(0); textArrayOffsetX.setNumber(0);
textArrayOffsetX.setTooltip(new StringTextComponent("How much each copy is shifted.")); textArrayOffsetX.setTooltip("How much each copy is shifted.");
arrayNumberFieldList.add(textArrayOffsetX); arrayNumberFieldList.add(textArrayOffsetX);
textArrayOffsetY = new GuiNumberField(font, buttons, left + 140, y, 50, 18); textArrayOffsetY = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 140, y, 50, 18);
textArrayOffsetY.setNumber(0); textArrayOffsetY.setNumber(0);
textArrayOffsetY.setTooltip(new StringTextComponent("How much each copy is shifted.")); textArrayOffsetY.setTooltip("How much each copy is shifted.");
arrayNumberFieldList.add(textArrayOffsetY); arrayNumberFieldList.add(textArrayOffsetY);
textArrayOffsetZ = new GuiNumberField(font, buttons, left + 210, y, 50, 18); textArrayOffsetZ = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 210, y, 50, 18);
textArrayOffsetZ.setNumber(0); textArrayOffsetZ.setNumber(0);
textArrayOffsetZ.setTooltip(new StringTextComponent("How much each copy is shifted.")); textArrayOffsetZ.setTooltip("How much each copy is shifted.");
arrayNumberFieldList.add(textArrayOffsetZ); arrayNumberFieldList.add(textArrayOffsetZ);
y = top + 50; y = top + 50;
textArrayCount = new GuiNumberField(font, buttons, left + 55, y, 50, 18); textArrayCount = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 55, y, 50, 18);
textArrayCount.setNumber(5); textArrayCount.setNumber(5);
textArrayCount.setTooltip(new StringTextComponent("How many copies should be made.")); textArrayCount.setTooltip("How many copies should be made.");
arrayNumberFieldList.add(textArrayCount); arrayNumberFieldList.add(textArrayCount);
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player); ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player);
if (modifierSettings != null) { if (modifierSettings != null) {
Array.ArraySettings a = modifierSettings.getArraySettings(); Array.ArraySettings a = modifierSettings.getArraySettings();
buttonArrayEnabled.setIsChecked(a.enabled); buttonArrayEnabled.setIsChecked(a.enabled);
textArrayOffsetX.setNumber(a.offset.getX()); textArrayOffsetX.setNumber(a.offset.getX());
textArrayOffsetY.setNumber(a.offset.getY()); textArrayOffsetY.setNumber(a.offset.getY());
textArrayOffsetZ.setNumber(a.offset.getZ()); textArrayOffsetZ.setNumber(a.offset.getZ());
textArrayCount.setNumber(a.count); textArrayCount.setNumber(a.count);
} }
setCollapsed(!buttonArrayEnabled.isChecked()); setCollapsed(!buttonArrayEnabled.isChecked());
}
public void updateScreen() { return id;
arrayNumberFieldList.forEach(GuiNumberField::update); }
}
@Override @Override
public void drawEntry(MatrixStack ms, int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, public void updateScreen() {
boolean isSelected, float partialTicks) { super.updateScreen();
int yy = y; arrayNumberFieldList.forEach(GuiNumberField::update);
int offset = 8; }
buttonArrayEnabled.render(ms, mouseX, mouseY, partialTicks); @Override
if (buttonArrayEnabled.isChecked()) { public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY,
buttonArrayEnabled.y = yy; boolean isSelected, float partialTicks) {
font.draw(ms, "Array enabled", left + offset, yy + 2, 0xFFFFFF); super.drawEntry(slotIndex, x, y, listWidth, slotHeight, mouseX, mouseY, isSelected, partialTicks);
yy = y + 20; int yy = y;
font.draw(ms, "Offset", left + offset, yy + 5, 0xFFFFFF); int offset = 8;
font.draw(ms, "X", left + 50 + offset, yy + 5, 0xFFFFFF);
textArrayOffsetX.y = yy;
font.draw(ms, "Y", left + 120 + offset, yy + 5, 0xFFFFFF);
textArrayOffsetY.y = yy;
font.draw(ms, "Z", left + 190 + offset, yy + 5, 0xFFFFFF);
textArrayOffsetZ.y = yy;
yy = y + 50; buttonArrayEnabled.drawButton(this.mc, mouseX, mouseY, partialTicks);
font.draw(ms, "Count", left + offset, yy + 5, 0xFFFFFF); if (buttonArrayEnabled.isChecked()) {
textArrayCount.y = yy; buttonArrayEnabled.y = yy;
fontRenderer.drawString("Array enabled", left + offset, yy + 2, 0xFFFFFF, true);
int currentReach = Math.max(-1, getArrayReach()); yy = y + 20;
int maxReach = ReachHelper.getMaxReach(mc.player); fontRenderer.drawString("Offset", left + offset, yy + 5, 0xFFFFFF, true);
TextFormatting reachColor = isCurrentReachValid(currentReach, maxReach) ? TextFormatting.GRAY : TextFormatting.RED; fontRenderer.drawString("X", left + 50 + offset, yy + 5, 0xFFFFFF, true);
String reachText = "Reach: " + reachColor + currentReach + TextFormatting.GRAY + "/" + TextFormatting.GRAY + maxReach; textArrayOffsetX.y = yy;
font.draw(ms, reachText, left + 176 + offset, yy + 5, 0xFFFFFF); fontRenderer.drawString("Y", left + 120 + offset, yy + 5, 0xFFFFFF, true);
textArrayOffsetY.y = yy;
fontRenderer.drawString("Z", left + 190 + offset, yy + 5, 0xFFFFFF, true);
textArrayOffsetZ.y = yy;
arrayNumberFieldList.forEach(numberField -> numberField.drawNumberField(ms, mouseX, mouseY, partialTicks)); yy = y + 50;
} else { fontRenderer.drawString("Count", left + offset, yy + 5, 0xFFFFFF, true);
buttonArrayEnabled.y = yy; textArrayCount.y = yy;
font.draw(ms, "Array disabled", left + offset, yy + 2, 0x999999);
}
} int currentReach = Math.max(-1, getArrayReach());
int maxReach = ReachHelper.getMaxReach(mc.player);
TextFormatting reachColor = isCurrentReachValid(currentReach, maxReach) ? TextFormatting.GRAY : TextFormatting.RED;
String reachText = "Reach: " + reachColor + currentReach + TextFormatting.GRAY + "/" + TextFormatting.GRAY + maxReach;
fontRenderer.drawString(reachText, left + 176 + offset, yy + 5, 0xFFFFFF, true);
public void drawTooltip(MatrixStack ms, Screen guiScreen, int mouseX, int mouseY) { arrayNumberFieldList.forEach(numberField -> numberField.drawNumberField(this.mc, mouseX, mouseY, partialTicks));
//Draw tooltips last } else {
if (buttonArrayEnabled.isChecked()) { buttonArrayEnabled.y = yy;
arrayNumberFieldList.forEach(numberField -> numberField.drawTooltip(ms, scrollPane.parent, mouseX, mouseY)); fontRenderer.drawString("Array disabled", left + offset, yy + 2, 0x999999, true);
} }
}
@Override }
public boolean charTyped(char typedChar, int keyCode) {
super.charTyped(typedChar, keyCode);
for (GuiNumberField numberField : arrayNumberFieldList) {
numberField.charTyped(typedChar, keyCode);
}
return true;
}
@Override public void drawTooltip(GuiScreen guiScreen, int mouseX, int mouseY) {
public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) { //Draw tooltips last
arrayNumberFieldList.forEach(numberField -> numberField.mouseClicked(mouseX, mouseY, mouseEvent)); if (buttonArrayEnabled.isChecked())
{
arrayNumberFieldList.forEach(numberField -> numberField.drawTooltip(scrollPane.parent, mouseX, mouseY));
}
}
boolean insideArrayEnabledLabel = mouseX >= left && mouseX < right && relativeY >= -2 && relativeY < 12; @Override
public void updatePosition(int slotIndex, int x, int y, float partialTicks) {
super.updatePosition(slotIndex, x, y, partialTicks);
}
if (insideArrayEnabledLabel) { @Override
buttonArrayEnabled.playDownSound(this.mc.getSoundManager()); public void keyTyped(char typedChar, int keyCode) throws IOException {
buttonArrayEnabled.onClick(mouseX, mouseY); super.keyTyped(typedChar, keyCode);
} for (GuiNumberField numberField : arrayNumberFieldList) {
numberField.keyTyped(typedChar, keyCode);
}
}
return true; @Override
} public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) {
super.mousePressed(slotIndex, mouseX, mouseY, mouseEvent, relativeX, relativeY);
arrayNumberFieldList.forEach(numberField -> numberField.mouseClicked(mouseX, mouseY, mouseEvent));
public Array.ArraySettings getArraySettings() { boolean insideArrayEnabledLabel = mouseX >= left && mouseX < right && relativeY >= -2 && relativeY < 12;
boolean arrayEnabled = buttonArrayEnabled.isChecked();
BlockPos arrayOffset = new BlockPos(0, 0, 0);
try {
arrayOffset = new BlockPos(textArrayOffsetX.getNumber(), textArrayOffsetY.getNumber(), textArrayOffsetZ.getNumber());
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Array offset not a valid number.");
}
int arrayCount = 5; if (insideArrayEnabledLabel) {
try { buttonArrayEnabled.setIsChecked(!buttonArrayEnabled.isChecked());
arrayCount = (int) textArrayCount.getNumber(); buttonArrayEnabled.playPressSound(this.mc.getSoundHandler());
} catch (NumberFormatException | NullPointerException ex) { actionPerformed(buttonArrayEnabled);
EffortlessBuilding.log(mc.player, "Array count not a valid number."); }
}
return new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount); return true;
} }
@Override @Override
protected String getName() { public void actionPerformed(GuiButton button) {
return "Array"; super.actionPerformed(button);
} if (button == buttonArrayEnabled) {
setCollapsed(!buttonArrayEnabled.isChecked());
}
arrayNumberFieldList.forEach(numberField -> numberField.actionPerformed(button));
}
@Override public Array.ArraySettings getArraySettings() {
protected int getExpandedHeight() { boolean arrayEnabled = buttonArrayEnabled.isChecked();
return 80; BlockPos arrayOffset = new BlockPos(0, 0, 0);
} try {
arrayOffset = new BlockPos(textArrayOffsetX.getNumber(), textArrayOffsetY.getNumber(), textArrayOffsetZ.getNumber());
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Array offset not a valid number.");
}
private int getArrayReach() { int arrayCount = 5;
try { try {
//find largest offset arrayCount = (int) textArrayCount.getNumber();
double x = Math.abs(textArrayOffsetX.getNumber()); } catch (NumberFormatException | NullPointerException ex) {
double y = Math.abs(textArrayOffsetY.getNumber()); EffortlessBuilding.log(mc.player, "Array count not a valid number.");
double z = Math.abs(textArrayOffsetZ.getNumber()); }
double largestOffset = Math.max(Math.max(x, y), z);
return (int) (largestOffset * textArrayCount.getNumber());
} catch (NumberFormatException | NullPointerException ex) {
return -1;
}
}
private boolean isCurrentReachValid(int currentReach, int maxReach) { return new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount);
return currentReach <= maxReach && currentReach > -1; }
}
@Override
protected String getName() {
return "Array";
}
@Override
protected int getExpandedHeight() {
return 80;
}
private int getArrayReach() {
try
{
//find largest offset
double x = Math.abs(textArrayOffsetX.getNumber());
double y = Math.abs(textArrayOffsetY.getNumber());
double z = Math.abs(textArrayOffsetZ.getNumber());
double largestOffset = Math.max(Math.max(x, y), z);
return (int) (largestOffset * textArrayCount.getNumber());
} catch (NumberFormatException | NullPointerException ex) {
return -1;
}
}
private boolean isCurrentReachValid(int currentReach, int maxReach) {
return currentReach <= maxReach && currentReach > -1;
}
} }

View File

@@ -1,284 +1,299 @@
package nl.requios.effortlessbuilding.gui.buildmodifier; package nl.requios.effortlessbuilding.gui.buildmodifier;
import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.widget.Widget;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.client.config.GuiCheckBox;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.Mirror; import nl.requios.effortlessbuilding.buildmodifier.Mirror;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.gui.elements.*; import nl.requios.effortlessbuilding.gui.elements.GuiCollapsibleScrollEntry;
import nl.requios.effortlessbuilding.gui.elements.GuiIconButton;
import nl.requios.effortlessbuilding.gui.elements.GuiNumberField;
import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@SuppressWarnings("Duplicates")
@OnlyIn(Dist.CLIENT)
public class MirrorSettingsGui extends GuiCollapsibleScrollEntry { public class MirrorSettingsGui extends GuiCollapsibleScrollEntry {
protected static final ResourceLocation BUILDING_ICONS = new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/building_icons.png"); protected static final ResourceLocation BUILDING_ICONS = new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/building_icons.png");
protected List<Button> mirrorButtonList = new ArrayList<>(); protected List<GuiButton> mirrorButtonList = new ArrayList<>();
protected List<GuiIconButton> mirrorIconButtonList = new ArrayList<>(); protected List<GuiIconButton> mirrorIconButtonList = new ArrayList<>();
protected List<GuiNumberField> mirrorNumberFieldList = new ArrayList<>(); protected List<GuiNumberField> mirrorNumberFieldList = new ArrayList<>();
private GuiNumberField textMirrorPosX, textMirrorPosY, textMirrorPosZ, textMirrorRadius; private GuiNumberField textMirrorPosX, textMirrorPosY, textMirrorPosZ, textMirrorRadius;
private GuiCheckBoxFixed buttonMirrorEnabled, buttonMirrorX, buttonMirrorY, buttonMirrorZ; private GuiCheckBox buttonMirrorEnabled, buttonMirrorX, buttonMirrorY, buttonMirrorZ;
private GuiIconButton buttonCurrentPosition, buttonToggleOdd, buttonDrawPlanes, buttonDrawLines; private GuiIconButton buttonCurrentPosition, buttonToggleOdd, buttonDrawPlanes, buttonDrawLines;
private boolean drawPlanes, drawLines, toggleOdd; private boolean drawPlanes, drawLines, toggleOdd;
public MirrorSettingsGui(GuiScrollPane scrollPane) { public MirrorSettingsGui(GuiScrollPane scrollPane) {
super(scrollPane); super(scrollPane);
} }
@Override @Override
public void init(List<Widget> buttonList) { public int initGui(int id, List<GuiButton> buttonList) {
super.init(buttonList); id = super.initGui(id, buttonList);
int y = top - 2; int y = top - 2;
buttonMirrorEnabled = new GuiCheckBoxFixed(left - 15 + 8, y, "", false) { buttonMirrorEnabled = new GuiCheckBox(id++, left - 15 + 8, y, "", false);
@Override buttonList.add(buttonMirrorEnabled);
public void onClick(double mouseX, double mouseY) {
super.onClick(mouseX, mouseY);
setCollapsed(!buttonMirrorEnabled.isChecked());
}
};
buttonList.add(buttonMirrorEnabled);
y = top + 18; y = top + 18;
textMirrorPosX = new GuiNumberField(font, buttonList, left + 58, y, 62, 18); textMirrorPosX = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 58, y, 62, 18);
textMirrorPosX.setNumber(0); textMirrorPosX.setNumber(0);
textMirrorPosX.setTooltip( textMirrorPosX.setTooltip(
Arrays.asList(new StringTextComponent("The position of the mirror."), new StringTextComponent("For odd numbered builds add 0.5.").withStyle(TextFormatting.GRAY))); Arrays.asList("The position of the mirror.", TextFormatting.GRAY + "For odd numbered builds add 0.5."));
mirrorNumberFieldList.add(textMirrorPosX); mirrorNumberFieldList.add(textMirrorPosX);
textMirrorPosY = new GuiNumberField(font, buttonList, left + 138, y, 62, 18); textMirrorPosY = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 138, y, 62, 18);
textMirrorPosY.setNumber(64); textMirrorPosY.setNumber(64);
textMirrorPosY.setTooltip(Arrays.asList(new StringTextComponent("The position of the mirror."), new StringTextComponent("For odd numbered builds add 0.5.").withStyle(TextFormatting.GRAY))); textMirrorPosY.setTooltip(Arrays.asList("The position of the mirror.", TextFormatting.GRAY + "For odd numbered builds add 0.5."));
mirrorNumberFieldList.add(textMirrorPosY); mirrorNumberFieldList.add(textMirrorPosY);
textMirrorPosZ = new GuiNumberField(font, buttonList, left + 218, y, 62, 18); textMirrorPosZ = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 218, y, 62, 18);
textMirrorPosZ.setNumber(0); textMirrorPosZ.setNumber(0);
textMirrorPosZ.setTooltip(Arrays.asList(new StringTextComponent("The position of the mirror."), new StringTextComponent("For odd numbered builds add 0.5.").withStyle(TextFormatting.GRAY))); textMirrorPosZ.setTooltip(Arrays.asList("The position of the mirror.", TextFormatting.GRAY + "For odd numbered builds add 0.5."));
mirrorNumberFieldList.add(textMirrorPosZ); mirrorNumberFieldList.add(textMirrorPosZ);
y = top + 50; y = top + 50;
buttonMirrorX = new GuiCheckBoxFixed(left + 60, y, " X", true); buttonMirrorX = new GuiCheckBox(id++, left + 60, y, " X", true);
mirrorButtonList.add(buttonMirrorX); mirrorButtonList.add(buttonMirrorX);
buttonMirrorY = new GuiCheckBoxFixed(left + 100, y, " Y", false); buttonMirrorY = new GuiCheckBox(id++, left + 100, y, " Y", false);
mirrorButtonList.add(buttonMirrorY); mirrorButtonList.add(buttonMirrorY);
buttonMirrorZ = new GuiCheckBoxFixed(left + 140, y, " Z", false); buttonMirrorZ = new GuiCheckBox(id++, left + 140, y, " Z", false);
mirrorButtonList.add(buttonMirrorZ); mirrorButtonList.add(buttonMirrorZ);
y = top + 47; y = top + 47;
textMirrorRadius = new GuiNumberField(font, buttonList, left + 218, y, 62, 18); textMirrorRadius = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 218, y, 62, 18);
textMirrorRadius.setNumber(50); textMirrorRadius.setNumber(50);
//TODO change to diameter (remove /2) //TODO change to diameter (remove /2)
textMirrorRadius.setTooltip(Arrays.asList(new StringTextComponent("How far the mirror reaches in any direction."), textMirrorRadius.setTooltip(Arrays.asList("How far the mirror reaches in any direction.",
new StringTextComponent("Max: ").withStyle(TextFormatting.GRAY).append(new StringTextComponent(String.valueOf(ReachHelper.getMaxReach(mc.player) / 2)).withStyle(TextFormatting.GOLD)), TextFormatting.GRAY + "Max: " + TextFormatting.GOLD + ReachHelper.getMaxReach(mc.player) / 2,
new StringTextComponent("Upgradeable in survival with reach upgrades.").withStyle(TextFormatting.GRAY))); TextFormatting.GRAY + "Upgradeable in survival with reach upgrades."));
mirrorNumberFieldList.add(textMirrorRadius); mirrorNumberFieldList.add(textMirrorRadius);
y = top + 72; y = top + 72;
buttonCurrentPosition = new GuiIconButton(left + 5, y, 0, 0, BUILDING_ICONS, button -> { buttonCurrentPosition = new GuiIconButton(id++, left + 5, y, 0, 0, BUILDING_ICONS);
Vector3d pos = new Vector3d(Math.floor(mc.player.getX()) + 0.5, Math.floor(mc.player.getY()) + 0.5, Math.floor(mc.player.getZ()) + 0.5); buttonCurrentPosition.setTooltip("Set mirror position to current player position");
textMirrorPosX.setNumber(pos.x); mirrorIconButtonList.add(buttonCurrentPosition);
textMirrorPosY.setNumber(pos.y);
textMirrorPosZ.setNumber(pos.z);
});
buttonCurrentPosition.setTooltip(new StringTextComponent("Set mirror position to current player position"));
mirrorIconButtonList.add(buttonCurrentPosition);
buttonToggleOdd = new GuiIconButton(left + 35, y, 0, 20, BUILDING_ICONS, button -> { buttonToggleOdd = new GuiIconButton(id++, left + 35, y, 0, 20, BUILDING_ICONS);
toggleOdd = !toggleOdd; buttonToggleOdd.setTooltip(Arrays.asList("Set mirror position to middle of block", "for odd numbered builds"));
buttonToggleOdd.setUseAlternateIcon(toggleOdd); mirrorIconButtonList.add(buttonToggleOdd);
if (toggleOdd) {
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set mirror position to corner of block"), new StringTextComponent("for even numbered builds")));
textMirrorPosX.setNumber(textMirrorPosX.getNumber() + 0.5);
textMirrorPosY.setNumber(textMirrorPosY.getNumber() + 0.5);
textMirrorPosZ.setNumber(textMirrorPosZ.getNumber() + 0.5);
} else {
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set mirror position to middle of block"), new StringTextComponent("for odd numbered builds")));
textMirrorPosX.setNumber(Math.floor(textMirrorPosX.getNumber()));
textMirrorPosY.setNumber(Math.floor(textMirrorPosY.getNumber()));
textMirrorPosZ.setNumber(Math.floor(textMirrorPosZ.getNumber()));
}
});
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set mirror position to middle of block"), new StringTextComponent("for odd numbered builds")));
mirrorIconButtonList.add(buttonToggleOdd);
buttonDrawLines = new GuiIconButton(left + 65, y, 0, 40, BUILDING_ICONS, button -> { buttonDrawLines = new GuiIconButton(id++, left + 65, y, 0, 40, BUILDING_ICONS);
drawLines = !drawLines; buttonDrawLines.setTooltip("Show lines");
buttonDrawLines.setUseAlternateIcon(drawLines); mirrorIconButtonList.add(buttonDrawLines);
buttonDrawLines.setTooltip(new StringTextComponent(drawLines ? "Hide lines" : "Show lines"));
});
buttonDrawLines.setTooltip(new StringTextComponent("Show lines"));
mirrorIconButtonList.add(buttonDrawLines);
buttonDrawPlanes = new GuiIconButton(left + 95, y, 0, 60, BUILDING_ICONS, button -> { buttonDrawPlanes = new GuiIconButton(id++, left + 95, y, 0, 60, BUILDING_ICONS);
drawPlanes = !drawPlanes; buttonDrawPlanes.setTooltip("Show area");
buttonDrawPlanes.setUseAlternateIcon(drawPlanes); mirrorIconButtonList.add(buttonDrawPlanes);
buttonDrawPlanes.setTooltip(new StringTextComponent(drawPlanes ? "Hide area" : "Show area"));
});
buttonDrawPlanes.setTooltip(new StringTextComponent("Show area"));
mirrorIconButtonList.add(buttonDrawPlanes);
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player); ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player);
if (modifierSettings != null) { if (modifierSettings != null) {
Mirror.MirrorSettings m = modifierSettings.getMirrorSettings(); Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
buttonMirrorEnabled.setIsChecked(m.enabled); buttonMirrorEnabled.setIsChecked(m.enabled);
textMirrorPosX.setNumber(m.position.x); textMirrorPosX.setNumber(m.position.x);
textMirrorPosY.setNumber(m.position.y); textMirrorPosY.setNumber(m.position.y);
textMirrorPosZ.setNumber(m.position.z); textMirrorPosZ.setNumber(m.position.z);
buttonMirrorX.setIsChecked(m.mirrorX); buttonMirrorX.setIsChecked(m.mirrorX);
buttonMirrorY.setIsChecked(m.mirrorY); buttonMirrorY.setIsChecked(m.mirrorY);
buttonMirrorZ.setIsChecked(m.mirrorZ); buttonMirrorZ.setIsChecked(m.mirrorZ);
textMirrorRadius.setNumber(m.radius); textMirrorRadius.setNumber(m.radius);
drawLines = m.drawLines; drawLines = m.drawLines;
drawPlanes = m.drawPlanes; drawPlanes = m.drawPlanes;
buttonDrawLines.setUseAlternateIcon(drawLines); buttonDrawLines.setUseAlternateIcon(drawLines);
buttonDrawPlanes.setUseAlternateIcon(drawPlanes); buttonDrawPlanes.setUseAlternateIcon(drawPlanes);
buttonDrawLines.setTooltip(new StringTextComponent(drawLines ? "Hide lines" : "Show lines")); buttonDrawLines.setTooltip(drawLines ? "Hide lines" : "Show lines");
buttonDrawPlanes.setTooltip(new StringTextComponent(drawPlanes ? "Hide area" : "Show area")); buttonDrawPlanes.setTooltip(drawPlanes ? "Hide area" : "Show area");
if (textMirrorPosX.getNumber() == Math.floor(textMirrorPosX.getNumber())) { if (textMirrorPosX.getNumber() == Math.floor(textMirrorPosX.getNumber())) {
toggleOdd = false; toggleOdd = false;
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set mirror position to middle of block"), new StringTextComponent("for odd numbered builds"))); buttonToggleOdd.setTooltip(Arrays.asList("Set mirror position to middle of block", "for odd numbered builds"));
} else { } else {
toggleOdd = true; toggleOdd = true;
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set mirror position to corner of block"), new StringTextComponent("for even numbered builds"))); buttonToggleOdd.setTooltip(Arrays.asList("Set mirror position to corner of block", "for even numbered builds"));
} }
buttonToggleOdd.setUseAlternateIcon(toggleOdd); buttonToggleOdd.setUseAlternateIcon(toggleOdd);
} }
buttonList.addAll(mirrorButtonList); buttonList.addAll(mirrorButtonList);
buttonList.addAll(mirrorIconButtonList); buttonList.addAll(mirrorIconButtonList);
setCollapsed(!buttonMirrorEnabled.isChecked()); setCollapsed(!buttonMirrorEnabled.isChecked());
}
@Override return id;
public void updateScreen() { }
super.updateScreen();
mirrorNumberFieldList.forEach(GuiNumberField::update);
}
@Override @Override
public void drawEntry(MatrixStack ms, int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, public void updateScreen() {
boolean isSelected, float partialTicks) { super.updateScreen();
mirrorNumberFieldList.forEach(GuiNumberField::update);
}
int yy = y; @Override
int offset = 8; public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY,
boolean isSelected, float partialTicks) {
super.drawEntry(slotIndex, x, y, listWidth, slotHeight, mouseX, mouseY, isSelected, partialTicks);
buttonMirrorEnabled.render(ms, mouseX, mouseY, partialTicks); int yy = y;
if (buttonMirrorEnabled.isChecked()) { int offset = 8;
buttonMirrorEnabled.y = yy;
font.draw(ms, "Mirror enabled", left + offset, yy + 2, 0xFFFFFF);
yy = y + 18; buttonMirrorEnabled.drawButton(this.mc, mouseX, mouseY, partialTicks);
font.draw(ms, "Position", left + offset, yy + 5, 0xFFFFFF); if (buttonMirrorEnabled.isChecked()) {
font.draw(ms, "X", left + 40 + offset, yy + 5, 0xFFFFFF); buttonMirrorEnabled.y = yy;
textMirrorPosX.y = yy; fontRenderer.drawString("Mirror enabled", left + offset, yy + 2, 0xFFFFFF, true);
font.draw(ms, "Y", left + 120 + offset, yy + 5, 0xFFFFFF);
textMirrorPosY.y = yy;
font.draw(ms, "Z", left + 200 + offset, yy + 5, 0xFFFFFF);
textMirrorPosZ.y = yy;
yy = y + 50; yy = y + 18;
font.draw(ms, "Direction", left + offset, yy + 2, 0xFFFFFF); fontRenderer.drawString("Position", left + offset, yy + 5, 0xFFFFFF, true);
buttonMirrorX.y = yy; fontRenderer.drawString("X", left + 40 + offset, yy + 5, 0xFFFFFF, true);
buttonMirrorY.y = yy; textMirrorPosX.y = yy;
buttonMirrorZ.y = yy; fontRenderer.drawString("Y", left + 120 + offset, yy + 5, 0xFFFFFF, true);
font.draw(ms, "Radius", left + 176 + offset, yy + 2, 0xFFFFFF); textMirrorPosY.y = yy;
textMirrorRadius.y = yy - 3; fontRenderer.drawString("Z", left + 200 + offset, yy + 5, 0xFFFFFF, true);
textMirrorPosZ.y = yy;
yy = y + 72; yy = y + 50;
buttonCurrentPosition.y = yy; fontRenderer.drawString("Direction", left + offset, yy + 2, 0xFFFFFF, true);
buttonToggleOdd.y = yy; buttonMirrorX.y = yy;
buttonDrawLines.y = yy; buttonMirrorY.y = yy;
buttonDrawPlanes.y = yy; buttonMirrorZ.y = yy;
fontRenderer.drawString("Radius", left + 176 + offset, yy + 2, 0xFFFFFF, true);
textMirrorRadius.y = yy - 3;
mirrorButtonList.forEach(button -> button.render(ms, mouseX, mouseY, partialTicks)); yy = y + 72;
mirrorIconButtonList.forEach(button -> button.render(ms, mouseX, mouseY, partialTicks)); buttonCurrentPosition.y = yy;
mirrorNumberFieldList.forEach(numberField -> numberField.drawNumberField(ms, mouseX, mouseY, partialTicks)); buttonToggleOdd.y = yy;
} else { buttonDrawLines.y = yy;
buttonMirrorEnabled.y = yy; buttonDrawPlanes.y = yy;
font.draw(ms, "Mirror disabled", left + offset, yy + 2, 0x999999);
}
} mirrorButtonList.forEach(button -> button.drawButton(this.mc, mouseX, mouseY, partialTicks));
mirrorIconButtonList.forEach(button -> button.drawButton(this.mc, mouseX, mouseY, partialTicks));
mirrorNumberFieldList.forEach(numberField -> numberField.drawNumberField(this.mc, mouseX, mouseY, partialTicks));
} else {
buttonMirrorEnabled.y = yy;
fontRenderer.drawString("Mirror disabled", left + offset, yy + 2, 0x999999, true);
}
public void drawTooltip(MatrixStack ms, Screen guiScreen, int mouseX, int mouseY) { }
//Draw tooltips last
if (buttonMirrorEnabled.isChecked()) {
mirrorIconButtonList.forEach(iconButton -> iconButton.drawTooltip(ms, scrollPane.parent, mouseX, mouseY));
mirrorNumberFieldList.forEach(numberField -> numberField.drawTooltip(ms, scrollPane.parent, mouseX, mouseY));
}
}
@Override public void drawTooltip(GuiScreen guiScreen, int mouseX, int mouseY) {
public boolean charTyped(char typedChar, int keyCode) { //Draw tooltips last
super.charTyped(typedChar, keyCode); if (buttonMirrorEnabled.isChecked())
for (GuiNumberField numberField : mirrorNumberFieldList) { {
numberField.charTyped(typedChar, keyCode); mirrorIconButtonList.forEach(iconButton -> iconButton.drawTooltip(scrollPane.parent, mouseX, mouseY));
} mirrorNumberFieldList.forEach(numberField -> numberField.drawTooltip(scrollPane.parent, mouseX, mouseY));
return true; }
} }
@Override @Override
public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) { public void updatePosition(int slotIndex, int x, int y, float partialTicks) {
mirrorNumberFieldList.forEach(numberField -> numberField.mouseClicked(mouseX, mouseY, mouseEvent)); super.updatePosition(slotIndex, x, y, partialTicks);
}
boolean insideMirrorEnabledLabel = mouseX >= left && mouseX < right && relativeY >= -2 && relativeY < 12; @Override
public void keyTyped(char typedChar, int keyCode) throws IOException {
super.keyTyped(typedChar, keyCode);
for (GuiNumberField numberField : mirrorNumberFieldList) {
numberField.keyTyped(typedChar, keyCode);
}
}
if (insideMirrorEnabledLabel) { @Override
buttonMirrorEnabled.playDownSound(this.mc.getSoundManager()); public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) {
buttonMirrorEnabled.onClick(mouseX, mouseY); super.mousePressed(slotIndex, mouseX, mouseY, mouseEvent, relativeX, relativeY);
} mirrorNumberFieldList.forEach(numberField -> numberField.mouseClicked(mouseX, mouseY, mouseEvent));
return true; boolean insideMirrorEnabledLabel = mouseX >= left && mouseX < right && relativeY >= -2 && relativeY < 12;
}
public Mirror.MirrorSettings getMirrorSettings() { if (insideMirrorEnabledLabel) {
boolean mirrorEnabled = buttonMirrorEnabled.isChecked(); buttonMirrorEnabled.setIsChecked(!buttonMirrorEnabled.isChecked());
buttonMirrorEnabled.playPressSound(this.mc.getSoundHandler());
actionPerformed(buttonMirrorEnabled);
}
Vector3d mirrorPos = new Vector3d(0, 64, 0); return true;
try { }
mirrorPos = new Vector3d(textMirrorPosX.getNumber(), textMirrorPosY.getNumber(), textMirrorPosZ.getNumber());
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Mirror position not a valid number.");
}
boolean mirrorX = buttonMirrorX.isChecked(); @Override
boolean mirrorY = buttonMirrorY.isChecked(); public void actionPerformed(GuiButton button) {
boolean mirrorZ = buttonMirrorZ.isChecked(); super.actionPerformed(button);
if (button == buttonMirrorEnabled) {
setCollapsed(!buttonMirrorEnabled.isChecked());
}
if (button == buttonCurrentPosition) {
Vec3d pos = new Vec3d(Math.floor(mc.player.posX) + 0.5, Math.floor(mc.player.posY) + 0.5, Math.floor(mc.player.posZ) + 0.5);
textMirrorPosX.setNumber(pos.x);
textMirrorPosY.setNumber(pos.y);
textMirrorPosZ.setNumber(pos.z);
}
if (button == buttonToggleOdd) {
toggleOdd = !toggleOdd;
buttonToggleOdd.setUseAlternateIcon(toggleOdd);
if (toggleOdd) {
buttonToggleOdd.setTooltip(Arrays.asList("Set mirror position to corner of block", "for even numbered builds"));
textMirrorPosX.setNumber(textMirrorPosX.getNumber() + 0.5);
textMirrorPosY.setNumber(textMirrorPosY.getNumber() + 0.5);
textMirrorPosZ.setNumber(textMirrorPosZ.getNumber() + 0.5);
} else {
buttonToggleOdd.setTooltip(Arrays.asList("Set mirror position to middle of block", "for odd numbered builds"));
textMirrorPosX.setNumber(Math.floor(textMirrorPosX.getNumber()));
textMirrorPosY.setNumber(Math.floor(textMirrorPosY.getNumber()));
textMirrorPosZ.setNumber(Math.floor(textMirrorPosZ.getNumber()));
}
}
if (button == buttonDrawLines) {
drawLines = !drawLines;
buttonDrawLines.setUseAlternateIcon(drawLines);
buttonDrawLines.setTooltip(drawLines ? "Hide lines" : "Show lines");
}
if (button == buttonDrawPlanes) {
drawPlanes = !drawPlanes;
buttonDrawPlanes.setUseAlternateIcon(drawPlanes);
buttonDrawPlanes.setTooltip(drawPlanes ? "Hide area" : "Show area");
}
mirrorNumberFieldList.forEach(numberField -> numberField.actionPerformed(button));
}
int mirrorRadius = 50; public Mirror.MirrorSettings getMirrorSettings() {
try { boolean mirrorEnabled = buttonMirrorEnabled.isChecked();
mirrorRadius = (int) textMirrorRadius.getNumber();
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Mirror radius not a valid number.");
}
return new Mirror.MirrorSettings(mirrorEnabled, mirrorPos, mirrorX, mirrorY, mirrorZ, mirrorRadius, drawLines, drawPlanes); Vec3d mirrorPos = new Vec3d(0, 64, 0);
} try {
mirrorPos = new Vec3d(textMirrorPosX.getNumber(), textMirrorPosY.getNumber(), textMirrorPosZ.getNumber());
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Mirror position not a valid number.");
}
@Override boolean mirrorX = buttonMirrorX.isChecked();
protected String getName() { boolean mirrorY = buttonMirrorY.isChecked();
return "Mirror"; boolean mirrorZ = buttonMirrorZ.isChecked();
}
@Override int mirrorRadius = 50;
protected int getExpandedHeight() { try {
return 100; mirrorRadius = (int) textMirrorRadius.getNumber();
} } catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Mirror radius not a valid number.");
}
return new Mirror.MirrorSettings(mirrorEnabled, mirrorPos, mirrorX, mirrorY, mirrorZ, mirrorRadius, drawLines, drawPlanes);
}
@Override
protected String getName() {
return "Mirror";
}
@Override
protected int getExpandedHeight() {
return 100;
}
} }

View File

@@ -1,13 +1,7 @@
package nl.requios.effortlessbuilding.gui.buildmodifier; package nl.requios.effortlessbuilding.gui.buildmodifier;
import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.Array; import nl.requios.effortlessbuilding.buildmodifier.Array;
import nl.requios.effortlessbuilding.buildmodifier.Mirror; import nl.requios.effortlessbuilding.buildmodifier.Mirror;
@@ -15,129 +9,129 @@ import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane; import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane;
import nl.requios.effortlessbuilding.network.ModifierSettingsMessage; import nl.requios.effortlessbuilding.network.ModifierSettingsMessage;
import nl.requios.effortlessbuilding.network.PacketHandler;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.ClientProxy;
@OnlyIn(Dist.CLIENT) import java.io.IOException;
public class ModifierSettingsGui extends Screen {
private GuiScrollPane scrollPane; public class ModifierSettingsGui extends GuiScreen {
private Button buttonClose;
private MirrorSettingsGui mirrorSettingsGui; private GuiScrollPane scrollPane;
private ArraySettingsGui arraySettingsGui; private GuiButton buttonClose;
private RadialMirrorSettingsGui radialMirrorSettingsGui;
public ModifierSettingsGui() { private MirrorSettingsGui mirrorSettingsGui;
super(new TranslationTextComponent("effortlessbuilding.screen.modifier_settings")); private ArraySettingsGui arraySettingsGui;
} private RadialMirrorSettingsGui radialMirrorSettingsGui;
@Override @Override
//Create buttons and labels and add them to buttonList/labelList //Create buttons and labels and add them to buttonList/labelList
protected void init() { public void initGui() {
scrollPane = new GuiScrollPane(this, font, 8, height - 30); int id = 0;
mirrorSettingsGui = new MirrorSettingsGui(scrollPane); scrollPane = new GuiScrollPane(this, fontRenderer, 8, height - 30);
scrollPane.AddListEntry(mirrorSettingsGui);
arraySettingsGui = new ArraySettingsGui(scrollPane); mirrorSettingsGui = new MirrorSettingsGui(scrollPane);
scrollPane.AddListEntry(arraySettingsGui); scrollPane.listEntries.add(mirrorSettingsGui);
radialMirrorSettingsGui = new RadialMirrorSettingsGui(scrollPane); arraySettingsGui = new ArraySettingsGui(scrollPane);
scrollPane.AddListEntry(radialMirrorSettingsGui); scrollPane.listEntries.add(arraySettingsGui);
scrollPane.init(buttons); radialMirrorSettingsGui = new RadialMirrorSettingsGui(scrollPane);
scrollPane.listEntries.add(radialMirrorSettingsGui);
//Close button id = scrollPane.initGui(id, buttonList);
int y = height - 26;
buttonClose = new Button(width / 2 - 100, y, 200, 20, new StringTextComponent("Close"), (button) -> {
Minecraft.getInstance().player.closeContainer();
});
buttons.add(buttonClose);
}
@Override //Close button
//Process general logic, i.e. hide buttons int y = height - 26;
public void tick() { buttonClose = new GuiButton(id++, width / 2 - 100, y, "Close");
scrollPane.updateScreen(); buttonList.add(buttonClose);
handleMouseInput(); }
}
@Override @Override
//Set colors using GL11, use the fontObj field to display text //Process general logic, i.e. hide buttons
//Use drawTexturedModalRect() to transfers areas of a texture resource to the screen public void updateScreen() {
public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { scrollPane.updateScreen();
this.renderBackground(ms); }
scrollPane.render(ms, mouseX, mouseY, partialTicks); @Override
//Set colors using GL11, use the fontRendererObj field to display text
//Use drawTexturedModalRect() to transfers areas of a texture resource to the screen
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
this.drawDefaultBackground();
buttonClose.render(ms, mouseX, mouseY, partialTicks); scrollPane.drawScreen(mouseX, mouseY, partialTicks);
scrollPane.drawTooltip(ms, this, mouseX, mouseY); buttonClose.drawButton(this.mc, mouseX, mouseY, partialTicks);
}
scrollPane.drawTooltip(this, mouseX, mouseY);
}
@Override @Override
public boolean charTyped(char typedChar, int keyCode) { protected void keyTyped(char typedChar, int keyCode) throws IOException {
super.charTyped(typedChar, keyCode); super.keyTyped(typedChar, keyCode);
scrollPane.charTyped(typedChar, keyCode); scrollPane.keyTyped(typedChar, keyCode);
if (keyCode == ClientProxy.keyBindings[0].getKey().getValue()) { if (keyCode == ClientProxy.keyBindings[0].getKeyCode()) {
minecraft.player.closeContainer(); mc.player.closeScreen();
} }
return false; }
}
@Override @Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) { protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
super.mouseClicked(mouseX, mouseY, mouseButton); super.mouseClicked(mouseX, mouseY, mouseButton);
buttons.forEach(button -> button.mouseClicked(mouseX, mouseY, mouseButton)); scrollPane.mouseClicked(mouseX, mouseY, mouseButton);
return scrollPane.mouseClicked(mouseX, mouseY, mouseButton); }
}
@Override @Override
public boolean mouseReleased(double mouseX, double mouseY, int state) { protected void mouseReleased(int mouseX, int mouseY, int state) {
if (state != 0 || !scrollPane.mouseReleased(mouseX, mouseY, state)) { if (state != 0 || !scrollPane.mouseReleased(mouseX, mouseY, state))
return super.mouseReleased(mouseX, mouseY, state); {
} super.mouseReleased(mouseX, mouseY, state);
return false; }
} }
public void handleMouseInput() { @Override
//super.handleMouseInput(); public void handleMouseInput() throws IOException {
scrollPane.handleMouseInput(); super.handleMouseInput();
scrollPane.handleMouseInput();
//Scrolling numbers //Scrolling numbers
// int mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth; // int mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth;
// int mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; // int mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1;
// numberFieldList.forEach(numberField -> numberField.handleMouseInput(mouseX, mouseY)); // numberFieldList.forEach(numberField -> numberField.handleMouseInput(mouseX, mouseY));
} }
@Override @Override
public void removed() { protected void actionPerformed(GuiButton button) {
scrollPane.onGuiClosed(); //check what button and action type (left/right click)
if (button == buttonClose) {
mc.player.closeScreen();
}
scrollPane.actionPerformed(button);
}
//save everything @Override
Mirror.MirrorSettings m = mirrorSettingsGui.getMirrorSettings(); public void onGuiClosed() {
Array.ArraySettings a = arraySettingsGui.getArraySettings(); scrollPane.onGuiClosed();
RadialMirror.RadialMirrorSettings r = radialMirrorSettingsGui.getRadialMirrorSettings();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(minecraft.player); //save everything
if (modifierSettings == null) modifierSettings = new ModifierSettingsManager.ModifierSettings(); Mirror.MirrorSettings m = mirrorSettingsGui.getMirrorSettings();
modifierSettings.setMirrorSettings(m); Array.ArraySettings a = arraySettingsGui.getArraySettings();
modifierSettings.setArraySettings(a); RadialMirror.RadialMirrorSettings r = radialMirrorSettingsGui.getRadialMirrorSettings();
modifierSettings.setRadialMirrorSettings(r);
//Sanitize ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player);
String error = ModifierSettingsManager.sanitize(modifierSettings, minecraft.player); if (modifierSettings == null) modifierSettings = new ModifierSettingsManager.ModifierSettings();
if (!error.isEmpty()) EffortlessBuilding.log(minecraft.player, error); modifierSettings.setMirrorSettings(m);
modifierSettings.setArraySettings(a);
modifierSettings.setRadialMirrorSettings(r);
ModifierSettingsManager.setModifierSettings(minecraft.player, modifierSettings); //Sanitize
String error = ModifierSettingsManager.sanitize(modifierSettings, mc.player);
if (!error.isEmpty()) EffortlessBuilding.log(mc.player, error);
//Send to server ModifierSettingsManager.setModifierSettings(mc.player, modifierSettings);
PacketHandler.INSTANCE.sendToServer(new ModifierSettingsMessage(modifierSettings));
Minecraft.getInstance().mouseHandler.grabMouse(); //Send to server
} EffortlessBuilding.packetHandler.sendToServer(new ModifierSettingsMessage(modifierSettings));
}
} }

View File

@@ -1,289 +1,306 @@
package nl.requios.effortlessbuilding.gui.buildmodifier; package nl.requios.effortlessbuilding.gui.buildmodifier;
import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.widget.Widget;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.client.config.GuiCheckBox;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
import nl.requios.effortlessbuilding.gui.elements.*; import nl.requios.effortlessbuilding.gui.elements.GuiCollapsibleScrollEntry;
import nl.requios.effortlessbuilding.gui.elements.GuiIconButton;
import nl.requios.effortlessbuilding.gui.elements.GuiNumberField;
import nl.requios.effortlessbuilding.gui.elements.GuiScrollPane;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@SuppressWarnings("Duplicates")
@OnlyIn(Dist.CLIENT)
public class RadialMirrorSettingsGui extends GuiCollapsibleScrollEntry { public class RadialMirrorSettingsGui extends GuiCollapsibleScrollEntry {
protected static final ResourceLocation BUILDING_ICONS = new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/building_icons.png"); protected static final ResourceLocation BUILDING_ICONS = new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/building_icons.png");
protected List<Button> radialMirrorButtonList = new ArrayList<>(); protected List<GuiButton> radialMirrorButtonList = new ArrayList<>();
protected List<GuiIconButton> radialMirrorIconButtonList = new ArrayList<>(); protected List<GuiIconButton> radialMirrorIconButtonList = new ArrayList<>();
protected List<GuiNumberField> radialMirrorNumberFieldList = new ArrayList<>(); protected List<GuiNumberField> radialMirrorNumberFieldList = new ArrayList<>();
private GuiNumberField textRadialMirrorPosX, textRadialMirrorPosY, textRadialMirrorPosZ, textRadialMirrorSlices, textRadialMirrorRadius; private GuiNumberField textRadialMirrorPosX, textRadialMirrorPosY, textRadialMirrorPosZ, textRadialMirrorSlices, textRadialMirrorRadius;
private GuiCheckBoxFixed buttonRadialMirrorEnabled, buttonRadialMirrorAlternate; private GuiCheckBox buttonRadialMirrorEnabled, buttonRadialMirrorAlternate;
private GuiIconButton buttonCurrentPosition, buttonToggleOdd, buttonDrawPlanes, buttonDrawLines; private GuiIconButton buttonCurrentPosition, buttonToggleOdd, buttonDrawPlanes, buttonDrawLines;
private boolean drawPlanes, drawLines, toggleOdd; private boolean drawPlanes, drawLines, toggleOdd;
public RadialMirrorSettingsGui(GuiScrollPane scrollPane) { public RadialMirrorSettingsGui(GuiScrollPane scrollPane) {
super(scrollPane); super(scrollPane);
} }
@Override @Override
public void init(List<Widget> buttonList) { public int initGui(int id, List<GuiButton> buttonList) {
super.init(buttonList); id = super.initGui(id, buttonList);
int y = top - 2; int y = top - 2;
buttonRadialMirrorEnabled = new GuiCheckBoxFixed(left - 15 + 8, y, "", false) { buttonRadialMirrorEnabled = new GuiCheckBox(id++, left - 15 + 8, y, "", false);
@Override buttonList.add(buttonRadialMirrorEnabled);
public void onClick(double mouseX, double mouseY) {
super.onClick(mouseX, mouseY);
setCollapsed(!buttonRadialMirrorEnabled.isChecked());
}
};
buttonList.add(buttonRadialMirrorEnabled);
y = top + 18; y = top + 18;
textRadialMirrorPosX = new GuiNumberField(font, buttonList, left + 58, y, 62, 18); textRadialMirrorPosX = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 58, y, 62, 18);
textRadialMirrorPosX.setNumber(0); textRadialMirrorPosX.setNumber(0);
textRadialMirrorPosX.setTooltip( textRadialMirrorPosX.setTooltip(
Arrays.asList(new StringTextComponent("The position of the radial mirror."), new StringTextComponent("For odd numbered builds add 0.5.").withStyle(TextFormatting.GRAY))); Arrays.asList("The position of the radial mirror.", TextFormatting.GRAY + "For odd numbered builds add 0.5."));
radialMirrorNumberFieldList.add(textRadialMirrorPosX); radialMirrorNumberFieldList.add(textRadialMirrorPosX);
textRadialMirrorPosY = new GuiNumberField(font, buttonList, left + 138, y, 62, 18); textRadialMirrorPosY = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 138, y, 62, 18);
textRadialMirrorPosY.setNumber(64); textRadialMirrorPosY.setNumber(64);
textRadialMirrorPosY.setTooltip(Arrays.asList(new StringTextComponent("The position of the radial mirror."), new StringTextComponent("For odd numbered builds add 0.5.").withStyle(TextFormatting.GRAY))); textRadialMirrorPosY.setTooltip(Arrays.asList("The position of the radial mirror.", TextFormatting.GRAY + "For odd numbered builds add 0.5."));
radialMirrorNumberFieldList.add(textRadialMirrorPosY); radialMirrorNumberFieldList.add(textRadialMirrorPosY);
textRadialMirrorPosZ = new GuiNumberField(font, buttonList, left + 218, y, 62, 18); textRadialMirrorPosZ = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 218, y, 62, 18);
textRadialMirrorPosZ.setNumber(0); textRadialMirrorPosZ.setNumber(0);
textRadialMirrorPosZ.setTooltip(Arrays.asList(new StringTextComponent("The position of the radial mirror."), new StringTextComponent("For odd numbered builds add 0.5.").withStyle(TextFormatting.GRAY))); textRadialMirrorPosZ.setTooltip(Arrays.asList("The position of the radial mirror.", TextFormatting.GRAY + "For odd numbered builds add 0.5."));
radialMirrorNumberFieldList.add(textRadialMirrorPosZ); radialMirrorNumberFieldList.add(textRadialMirrorPosZ);
y = top + 47; y = top + 47;
textRadialMirrorSlices = new GuiNumberField(font, buttonList, left + 55, y, 50, 18); textRadialMirrorSlices = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 55, y, 50, 18);
textRadialMirrorSlices.setNumber(4); textRadialMirrorSlices.setNumber(4);
textRadialMirrorSlices.setTooltip(Arrays.asList(new StringTextComponent("The number of repeating slices."), new StringTextComponent("Minimally 2.").withStyle(TextFormatting.GRAY))); textRadialMirrorSlices.setTooltip(Arrays.asList("The number of repeating slices.", TextFormatting.GRAY + "Minimally 2."));
radialMirrorNumberFieldList.add(textRadialMirrorSlices); radialMirrorNumberFieldList.add(textRadialMirrorSlices);
textRadialMirrorRadius = new GuiNumberField(font, buttonList, left + 218, y, 62, 18); textRadialMirrorRadius = new GuiNumberField(id++, id++, id++, fontRenderer, buttonList, left + 218, y, 62, 18);
textRadialMirrorRadius.setNumber(50); textRadialMirrorRadius.setNumber(50);
//TODO change to diameter (remove /2) //TODO change to diameter (remove /2)
textRadialMirrorRadius.setTooltip(Arrays.asList(new StringTextComponent("How far the radial mirror reaches from its center position."), textRadialMirrorRadius.setTooltip(Arrays.asList("How far the radial mirror reaches from its center position.",
new StringTextComponent("Max: ").withStyle(TextFormatting.GRAY).append(new StringTextComponent(String.valueOf(ReachHelper.getMaxReach(mc.player) / 2)).withStyle(TextFormatting.GOLD)), TextFormatting.GRAY + "Max: " + TextFormatting.GOLD + ReachHelper.getMaxReach(mc.player) / 2,
new StringTextComponent("Upgradeable in survival with reach upgrades.").withStyle(TextFormatting.GRAY))); TextFormatting.GRAY + "Upgradeable in survival with reach upgrades."));
radialMirrorNumberFieldList.add(textRadialMirrorRadius); radialMirrorNumberFieldList.add(textRadialMirrorRadius);
y = top + 72;
buttonCurrentPosition = new GuiIconButton(left + 5, y, 0, 0, BUILDING_ICONS, button -> {
Vector3d pos = new Vector3d(Math.floor(mc.player.getX()) + 0.5, Math.floor(mc.player.getY()) + 0.5, Math.floor(mc.player.getZ()) + 0.5);
textRadialMirrorPosX.setNumber(pos.x);
textRadialMirrorPosY.setNumber(pos.y);
textRadialMirrorPosZ.setNumber(pos.z);
});
buttonCurrentPosition.setTooltip(new StringTextComponent("Set radial mirror position to current player position"));
radialMirrorIconButtonList.add(buttonCurrentPosition);
buttonToggleOdd = new GuiIconButton(left + 35, y, 0, 20, BUILDING_ICONS, button -> {
toggleOdd = !toggleOdd;
buttonToggleOdd.setUseAlternateIcon(toggleOdd);
if (toggleOdd) {
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set mirror position to corner of block"), new StringTextComponent("for even numbered builds")));
textRadialMirrorPosX.setNumber(textRadialMirrorPosX.getNumber() + 0.5);
textRadialMirrorPosY.setNumber(textRadialMirrorPosY.getNumber() + 0.5);
textRadialMirrorPosZ.setNumber(textRadialMirrorPosZ.getNumber() + 0.5);
} else {
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set mirror position to middle of block"), new StringTextComponent("for odd numbered builds")));
textRadialMirrorPosX.setNumber(Math.floor(textRadialMirrorPosX.getNumber()));
textRadialMirrorPosY.setNumber(Math.floor(textRadialMirrorPosY.getNumber()));
textRadialMirrorPosZ.setNumber(Math.floor(textRadialMirrorPosZ.getNumber()));
}
});
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set radial mirror position to middle of block"), new StringTextComponent("for odd numbered builds")));
radialMirrorIconButtonList.add(buttonToggleOdd);
buttonDrawLines = new GuiIconButton(left + 65, y, 0, 40, BUILDING_ICONS, button -> {
drawLines = !drawLines;
buttonDrawLines.setUseAlternateIcon(drawLines);
buttonDrawLines.setTooltip(new StringTextComponent(drawLines ? "Hide lines" : "Show lines"));
});
buttonDrawLines.setTooltip(new StringTextComponent("Show lines"));
radialMirrorIconButtonList.add(buttonDrawLines);
buttonDrawPlanes = new GuiIconButton(left + 95, y, 0, 60, BUILDING_ICONS, button -> {
drawPlanes = !drawPlanes;
buttonDrawPlanes.setUseAlternateIcon(drawPlanes);
buttonDrawPlanes.setTooltip(new StringTextComponent(drawPlanes ? "Hide area" : "Show area"));
});
buttonDrawPlanes.setTooltip(new StringTextComponent("Show area"));
radialMirrorIconButtonList.add(buttonDrawPlanes);
y = top + 76;
buttonRadialMirrorAlternate = new GuiCheckBoxFixed(left + 140, y, " Alternate", false);
radialMirrorButtonList.add(buttonRadialMirrorAlternate);
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player);
if (modifierSettings != null) {
RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
buttonRadialMirrorEnabled.setIsChecked(r.enabled);
textRadialMirrorPosX.setNumber(r.position.x);
textRadialMirrorPosY.setNumber(r.position.y);
textRadialMirrorPosZ.setNumber(r.position.z);
textRadialMirrorSlices.setNumber(r.slices);
buttonRadialMirrorAlternate.setIsChecked(r.alternate);
textRadialMirrorRadius.setNumber(r.radius);
drawLines = r.drawLines;
drawPlanes = r.drawPlanes;
buttonDrawLines.setUseAlternateIcon(drawLines);
buttonDrawPlanes.setUseAlternateIcon(drawPlanes);
buttonDrawLines.setTooltip(new StringTextComponent(drawLines ? "Hide lines" : "Show lines"));
buttonDrawPlanes.setTooltip(new StringTextComponent(drawPlanes ? "Hide area" : "Show area"));
if (textRadialMirrorPosX.getNumber() == Math.floor(textRadialMirrorPosX.getNumber())) {
toggleOdd = false;
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set radial mirror position to middle of block"), new StringTextComponent("for odd numbered builds")));
} else {
toggleOdd = true;
buttonToggleOdd.setTooltip(Arrays.asList(new StringTextComponent("Set radial mirror position to corner of block"), new StringTextComponent("for even numbered builds")));
}
buttonToggleOdd.setUseAlternateIcon(toggleOdd);
}
buttonList.addAll(radialMirrorButtonList);
buttonList.addAll(radialMirrorIconButtonList);
setCollapsed(!buttonRadialMirrorEnabled.isChecked());
}
public void updateScreen() {
radialMirrorNumberFieldList.forEach(GuiNumberField::update);
}
@Override y = top + 72;
public void drawEntry(MatrixStack ms, int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, buttonCurrentPosition = new GuiIconButton(id++, left + 5, y, 0, 0, BUILDING_ICONS);
boolean isSelected, float partialTicks) { buttonCurrentPosition.setTooltip("Set radial mirror position to current player position");
radialMirrorIconButtonList.add(buttonCurrentPosition);
int yy = y; buttonToggleOdd = new GuiIconButton(id++, left + 35, y, 0, 20, BUILDING_ICONS);
int offset = 8; buttonToggleOdd.setTooltip(Arrays.asList("Set radial mirror position to middle of block", "for odd numbered builds"));
radialMirrorIconButtonList.add(buttonToggleOdd);
buttonRadialMirrorEnabled.render(ms, mouseX, mouseY, partialTicks); buttonDrawLines = new GuiIconButton(id++, left + 65, y, 0, 40, BUILDING_ICONS);
if (buttonRadialMirrorEnabled.isChecked()) { buttonDrawLines.setTooltip("Show lines");
buttonRadialMirrorEnabled.y = yy; radialMirrorIconButtonList.add(buttonDrawLines);
font.draw(ms, "Radial mirror enabled", left + offset, yy + 2, 0xFFFFFF);
yy = y + 18; buttonDrawPlanes = new GuiIconButton(id++, left + 95, y, 0, 60, BUILDING_ICONS);
font.draw(ms, "Position", left + offset, yy + 5, 0xFFFFFF); buttonDrawPlanes.setTooltip("Show area");
font.draw(ms, "X", left + 40 + offset, yy + 5, 0xFFFFFF); radialMirrorIconButtonList.add(buttonDrawPlanes);
textRadialMirrorPosX.y = yy;
font.draw(ms, "Y", left + 120 + offset, yy + 5, 0xFFFFFF);
textRadialMirrorPosY.y = yy;
font.draw(ms, "Z", left + 200 + offset, yy + 5, 0xFFFFFF);
textRadialMirrorPosZ.y = yy;
yy = y + 50; y = top + 76;
font.draw(ms, "Slices", left + offset, yy + 2, 0xFFFFFF); buttonRadialMirrorAlternate = new GuiCheckBox(id++, left + 140, y, " Alternate", false);
textRadialMirrorSlices.y = yy - 3; radialMirrorButtonList.add(buttonRadialMirrorAlternate);
font.draw(ms, "Radius", left + 176 + offset, yy + 2, 0xFFFFFF);
textRadialMirrorRadius.y = yy - 3;
yy = y + 72; ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(mc.player);
buttonCurrentPosition.y = yy; if (modifierSettings != null) {
buttonToggleOdd.y = yy; RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
buttonDrawLines.y = yy; buttonRadialMirrorEnabled.setIsChecked(r.enabled);
buttonDrawPlanes.y = yy; textRadialMirrorPosX.setNumber(r.position.x);
textRadialMirrorPosY.setNumber(r.position.y);
textRadialMirrorPosZ.setNumber(r.position.z);
textRadialMirrorSlices.setNumber(r.slices);
buttonRadialMirrorAlternate.setIsChecked(r.alternate);
textRadialMirrorRadius.setNumber(r.radius);
drawLines = r.drawLines;
drawPlanes = r.drawPlanes;
buttonDrawLines.setUseAlternateIcon(drawLines);
buttonDrawPlanes.setUseAlternateIcon(drawPlanes);
buttonDrawLines.setTooltip(drawLines ? "Hide lines" : "Show lines");
buttonDrawPlanes.setTooltip(drawPlanes ? "Hide area" : "Show area");
if (textRadialMirrorPosX.getNumber() == Math.floor(textRadialMirrorPosX.getNumber())) {
toggleOdd = false;
buttonToggleOdd.setTooltip(Arrays.asList("Set radial mirror position to middle of block", "for odd numbered builds"));
} else {
toggleOdd = true;
buttonToggleOdd.setTooltip(Arrays.asList("Set radial mirror position to corner of block", "for even numbered builds"));
}
buttonToggleOdd.setUseAlternateIcon(toggleOdd);
}
yy = y + 76; buttonList.addAll(radialMirrorButtonList);
buttonRadialMirrorAlternate.y = yy; buttonList.addAll(radialMirrorIconButtonList);
radialMirrorButtonList.forEach(button -> button.render(ms, mouseX, mouseY, partialTicks)); setCollapsed(!buttonRadialMirrorEnabled.isChecked());
radialMirrorIconButtonList.forEach(button -> button.render(ms, mouseX, mouseY, partialTicks));
radialMirrorNumberFieldList
.forEach(numberField -> numberField.drawNumberField(ms, mouseX, mouseY, partialTicks));
} else {
buttonRadialMirrorEnabled.y = yy;
font.draw(ms, "Radial mirror disabled", left + offset, yy + 2, 0x999999);
}
} return id;
}
public void drawTooltip(MatrixStack ms, Screen guiScreen, int mouseX, int mouseY) { @Override
//Draw tooltips last public void updateScreen() {
if (buttonRadialMirrorEnabled.isChecked()) { super.updateScreen();
radialMirrorIconButtonList.forEach(iconButton -> iconButton.drawTooltip(ms, scrollPane.parent, mouseX, mouseY)); radialMirrorNumberFieldList.forEach(GuiNumberField::update);
radialMirrorNumberFieldList.forEach(numberField -> numberField.drawTooltip(ms, scrollPane.parent, mouseX, mouseY)); }
}
}
@Override @Override
public boolean charTyped(char typedChar, int keyCode) { public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY,
super.charTyped(typedChar, keyCode); boolean isSelected, float partialTicks) {
for (GuiNumberField numberField : radialMirrorNumberFieldList) { super.drawEntry(slotIndex, x, y, listWidth, slotHeight, mouseX, mouseY, isSelected, partialTicks);
numberField.charTyped(typedChar, keyCode);
}
return true;
}
@Override int yy = y;
public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) { int offset = 8;
radialMirrorNumberFieldList.forEach(numberField -> numberField.mouseClicked(mouseX, mouseY, mouseEvent));
boolean insideRadialMirrorEnabledLabel = mouseX >= left && mouseX < right && relativeY >= -2 && relativeY < 12; buttonRadialMirrorEnabled.drawButton(this.mc, mouseX, mouseY, partialTicks);
if (buttonRadialMirrorEnabled.isChecked()) {
buttonRadialMirrorEnabled.y = yy;
fontRenderer.drawString("Radial mirror enabled", left + offset, yy + 2, 0xFFFFFF, true);
if (insideRadialMirrorEnabledLabel) { yy = y + 18;
buttonRadialMirrorEnabled.playDownSound(this.mc.getSoundManager()); fontRenderer.drawString("Position", left + offset, yy + 5, 0xFFFFFF, true);
buttonRadialMirrorEnabled.onClick(mouseX, mouseY); fontRenderer.drawString("X", left + 40 + offset, yy + 5, 0xFFFFFF, true);
} textRadialMirrorPosX.y = yy;
fontRenderer.drawString("Y", left + 120 + offset, yy + 5, 0xFFFFFF, true);
textRadialMirrorPosY.y = yy;
fontRenderer.drawString("Z", left + 200 + offset, yy + 5, 0xFFFFFF, true);
textRadialMirrorPosZ.y = yy;
return true; yy = y + 50;
} fontRenderer.drawString("Slices", left + offset, yy + 2, 0xFFFFFF, true);
textRadialMirrorSlices.y = yy - 3;
fontRenderer.drawString("Radius", left + 176 + offset, yy + 2, 0xFFFFFF, true);
textRadialMirrorRadius.y = yy - 3;
public RadialMirror.RadialMirrorSettings getRadialMirrorSettings() { yy = y + 72;
boolean radialMirrorEnabled = buttonRadialMirrorEnabled.isChecked(); buttonCurrentPosition.y = yy;
buttonToggleOdd.y = yy;
buttonDrawLines.y = yy;
buttonDrawPlanes.y = yy;
Vector3d radialMirrorPos = new Vector3d(0, 64, 0); yy = y + 76;
try { buttonRadialMirrorAlternate.y = yy;
radialMirrorPos = new Vector3d(textRadialMirrorPosX.getNumber(), textRadialMirrorPosY.getNumber(), textRadialMirrorPosZ
.getNumber());
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Radial mirror position not a valid number.");
}
int radialMirrorSlices = 4; radialMirrorButtonList.forEach(button -> button.drawButton(this.mc, mouseX, mouseY, partialTicks));
try { radialMirrorIconButtonList.forEach(button -> button.drawButton(this.mc, mouseX, mouseY, partialTicks));
radialMirrorSlices = (int) textRadialMirrorSlices.getNumber(); radialMirrorNumberFieldList
} catch (NumberFormatException | NullPointerException ex) { .forEach(numberField -> numberField.drawNumberField(this.mc, mouseX, mouseY, partialTicks));
EffortlessBuilding.log(mc.player, "Radial mirror slices not a valid number."); } else {
} buttonRadialMirrorEnabled.y = yy;
fontRenderer.drawString("Radial mirror disabled", left + offset, yy + 2, 0x999999, true);
}
boolean radialMirrorAlternate = buttonRadialMirrorAlternate.isChecked(); }
int radialMirrorRadius = 50; public void drawTooltip(GuiScreen guiScreen, int mouseX, int mouseY) {
try { //Draw tooltips last
radialMirrorRadius = (int) textRadialMirrorRadius.getNumber(); if (buttonRadialMirrorEnabled.isChecked())
} catch (NumberFormatException | NullPointerException ex) { {
EffortlessBuilding.log(mc.player, "Mirror radius not a valid number."); radialMirrorIconButtonList.forEach(iconButton -> iconButton.drawTooltip(scrollPane.parent, mouseX, mouseY));
} radialMirrorNumberFieldList.forEach(numberField -> numberField.drawTooltip(scrollPane.parent, mouseX, mouseY));
}
}
return new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPos, radialMirrorSlices, radialMirrorAlternate, radialMirrorRadius, drawLines, drawPlanes); @Override
} public void updatePosition(int slotIndex, int x, int y, float partialTicks) {
super.updatePosition(slotIndex, x, y, partialTicks);
}
@Override @Override
protected String getName() { public void keyTyped(char typedChar, int keyCode) throws IOException {
return "Radial mirror"; super.keyTyped(typedChar, keyCode);
} for (GuiNumberField numberField : radialMirrorNumberFieldList) {
numberField.keyTyped(typedChar, keyCode);
}
}
@Override @Override
protected int getExpandedHeight() { public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) {
return 100; super.mousePressed(slotIndex, mouseX, mouseY, mouseEvent, relativeX, relativeY);
} radialMirrorNumberFieldList.forEach(numberField -> numberField.mouseClicked(mouseX, mouseY, mouseEvent));
boolean insideRadialMirrorEnabledLabel = mouseX >= left && mouseX < right && relativeY >= -2 && relativeY < 12;
if (insideRadialMirrorEnabledLabel) {
buttonRadialMirrorEnabled.setIsChecked(!buttonRadialMirrorEnabled.isChecked());
buttonRadialMirrorEnabled.playPressSound(this.mc.getSoundHandler());
actionPerformed(buttonRadialMirrorEnabled);
}
return true;
}
@Override
public void actionPerformed(GuiButton button) {
super.actionPerformed(button);
if (button == buttonRadialMirrorEnabled) {
setCollapsed(!buttonRadialMirrorEnabled.isChecked());
}
if (button == buttonCurrentPosition) {
Vec3d pos = new Vec3d(Math.floor(mc.player.posX) + 0.5, Math.floor(mc.player.posY) + 0.5, Math.floor(mc.player.posZ) + 0.5);
textRadialMirrorPosX.setNumber(pos.x);
textRadialMirrorPosY.setNumber(pos.y);
textRadialMirrorPosZ.setNumber(pos.z);
}
if (button == buttonToggleOdd) {
toggleOdd = !toggleOdd;
buttonToggleOdd.setUseAlternateIcon(toggleOdd);
if (toggleOdd) {
buttonToggleOdd.setTooltip(Arrays.asList("Set mirror position to corner of block", "for even numbered builds"));
textRadialMirrorPosX.setNumber(textRadialMirrorPosX.getNumber() + 0.5);
textRadialMirrorPosY.setNumber(textRadialMirrorPosY.getNumber() + 0.5);
textRadialMirrorPosZ.setNumber(textRadialMirrorPosZ.getNumber() + 0.5);
} else {
buttonToggleOdd.setTooltip(Arrays.asList("Set mirror position to middle of block", "for odd numbered builds"));
textRadialMirrorPosX.setNumber(Math.floor(textRadialMirrorPosX.getNumber()));
textRadialMirrorPosY.setNumber(Math.floor(textRadialMirrorPosY.getNumber()));
textRadialMirrorPosZ.setNumber(Math.floor(textRadialMirrorPosZ.getNumber()));
}
}
if (button == buttonDrawLines) {
drawLines = !drawLines;
buttonDrawLines.setUseAlternateIcon(drawLines);
buttonDrawLines.setTooltip(drawLines ? "Hide lines" : "Show lines");
}
if (button == buttonDrawPlanes) {
drawPlanes = !drawPlanes;
buttonDrawPlanes.setUseAlternateIcon(drawPlanes);
buttonDrawPlanes.setTooltip(drawPlanes ? "Hide area" : "Show area");
}
radialMirrorNumberFieldList.forEach(numberField -> numberField.actionPerformed(button));
}
public RadialMirror.RadialMirrorSettings getRadialMirrorSettings() {
boolean radialMirrorEnabled = buttonRadialMirrorEnabled.isChecked();
Vec3d radialMirrorPos = new Vec3d(0, 64, 0);
try {
radialMirrorPos = new Vec3d(textRadialMirrorPosX.getNumber(), textRadialMirrorPosY.getNumber(), textRadialMirrorPosZ
.getNumber());
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Radial mirror position not a valid number.");
}
int radialMirrorSlices = 4;
try {
radialMirrorSlices = (int) textRadialMirrorSlices.getNumber();
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Radial mirror slices not a valid number.");
}
boolean radialMirrorAlternate = buttonRadialMirrorAlternate.isChecked();
int radialMirrorRadius = 50;
try {
radialMirrorRadius = (int) textRadialMirrorRadius.getNumber();
} catch (NumberFormatException | NullPointerException ex) {
EffortlessBuilding.log(mc.player, "Mirror radius not a valid number.");
}
return new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPos, radialMirrorSlices, radialMirrorAlternate, radialMirrorRadius, drawLines, drawPlanes);
}
@Override
protected String getName() {
return "Radial mirror";
}
@Override
protected int getExpandedHeight() {
return 100;
}
} }

View File

@@ -1,62 +0,0 @@
package nl.requios.effortlessbuilding.gui.elements;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.fml.client.gui.GuiUtils;
import javax.annotation.ParametersAreNonnullByDefault;
/**
* This class provides a checkbox style control.
*/
@ParametersAreNonnullByDefault
public class GuiCheckBoxFixed extends Button {
private final int boxWidth;
private boolean isChecked;
public GuiCheckBoxFixed(int xPos, int yPos, String displayString, boolean isChecked) {
super(xPos, yPos, Minecraft.getInstance().font.width(displayString) + 2 + 11, 11, new StringTextComponent(displayString), b -> {
});
this.isChecked = isChecked;
this.boxWidth = 11;
this.height = 11;
this.width = this.boxWidth + 2 + Minecraft.getInstance().font.width(displayString);
}
@Override
public void renderButton(MatrixStack ms, int mouseX, int mouseY, float partial) {
if (this.visible) {
Minecraft mc = Minecraft.getInstance();
this.isHovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.boxWidth && mouseY < this.y + this.height;
GuiUtils.drawContinuousTexturedBox(WIDGETS_LOCATION, this.x, this.y, 0, 46, this.boxWidth, this.height, 200, 20, 2, 3, 2, 2, this.getBlitOffset());
this.renderBg(ms, mc, mouseX, mouseY);
int color = 14737632;
if (packedFGColor != 0) {
color = packedFGColor;
} else if (!this.active) {
color = 10526880;
}
if (this.isChecked)
drawCenteredString(ms, mc.font, "x", this.x + this.boxWidth / 2 + 1, this.y + 1, 14737632);
drawString(ms, mc.font, getMessage(), this.x + this.boxWidth + 2, this.y + 2, color);
}
}
@Override
public void onPress() {
this.isChecked = !this.isChecked;
}
public boolean isChecked() {
return this.isChecked;
}
public void setIsChecked(boolean isChecked) {
this.isChecked = isChecked;
}
}

View File

@@ -1,89 +1,103 @@
package nl.requios.effortlessbuilding.gui.elements; package nl.requios.effortlessbuilding.gui.elements;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.widget.Widget; import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import java.io.IOException;
import java.util.List; import java.util.List;
@OnlyIn(Dist.CLIENT)
public abstract class GuiCollapsibleScrollEntry implements GuiScrollPane.IScrollEntry { public abstract class GuiCollapsibleScrollEntry implements GuiScrollPane.IScrollEntry {
public GuiScrollPane scrollPane; public GuiScrollPane scrollPane;
protected FontRenderer font; protected FontRenderer fontRenderer;
protected Minecraft mc; protected Minecraft mc;
protected boolean isCollapsed = true; protected boolean isCollapsed = true;
protected int left, right, top, bottom; protected int left, right, top, bottom;
public GuiCollapsibleScrollEntry(GuiScrollPane scrollPane) { public GuiCollapsibleScrollEntry(GuiScrollPane scrollPane) {
this.scrollPane = scrollPane; this.scrollPane = scrollPane;
this.font = scrollPane.font; this.fontRenderer = scrollPane.fontRenderer;
this.mc = Minecraft.getInstance(); this.mc = scrollPane.parent.mc;
} }
@Override @Override
public void init(List<Widget> buttonList) { public int initGui(int id, List<GuiButton> buttonList) {
left = scrollPane.getWidth() / 2 - 140;
right = scrollPane.getWidth() / 2 + 140;
top = scrollPane.getHeight() / 2 - 100;
bottom = scrollPane.getHeight() / 2 + 100;
}
@Override left = scrollPane.width / 2 - 140;
public void updateScreen() { right = scrollPane.width / 2 + 140;
} top = scrollPane.height / 2 - 100;
bottom = scrollPane.height / 2 + 100;
@Override return id;
public void drawTooltip(MatrixStack ms, Screen guiScreen, int mouseX, int mouseY) { }
}
@Override @Override
public void updatePosition(int slotIndex, int x, int y, float partialTicks) { public void updateScreen() {
} }
@Override @Override
public boolean charTyped(char eventChar, int eventKey) { public void drawEntry(int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY,
return false; boolean isSelected, float partialTicks) {
}
@Override }
public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) {
return false;
}
@Override @Override
public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) { public void drawTooltip(GuiScreen guiScreen, int mouseX, int mouseY) {
} }
@Override @Override
public void onGuiClosed() { public void updatePosition(int slotIndex, int x, int y, float partialTicks) {
}
@Override }
public int getHeight() {
return isCollapsed ? getCollapsedHeight() : getExpandedHeight();
}
public void setCollapsed(boolean collapsed) { @Override
this.isCollapsed = collapsed; public void keyTyped(char eventChar, int eventKey) throws IOException {
}
protected String getName() { }
return "Collapsible scroll entry";
}
protected int getCollapsedHeight() { @Override
return 24; public boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY) {
} return false;
}
protected int getExpandedHeight() { @Override
return 100; public void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY) {
}
}
@Override
public void actionPerformed(GuiButton button) {
}
@Override
public void onGuiClosed() {
}
@Override
public int getHeight() {
return isCollapsed ? getCollapsedHeight() : getExpandedHeight();
}
public void setCollapsed(boolean collapsed) {
this.isCollapsed = collapsed;
}
protected String getName() {
return "Collapsible scroll entry";
}
protected int getCollapsedHeight() {
return 24;
}
protected int getExpandedHeight() {
return 100;
}
} }

View File

@@ -1,80 +1,75 @@
package nl.requios.effortlessbuilding.gui.elements; package nl.requios.effortlessbuilding.gui.elements;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.widget.button.Button; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Arrays;
import java.util.List; import java.util.List;
@OnlyIn(Dist.CLIENT) public class GuiIconButton extends GuiButton {
@ParametersAreNonnullByDefault
public class GuiIconButton extends Button {
private final ResourceLocation resourceLocation; private final ResourceLocation resourceLocation;
private final int iconX, iconY, iconWidth, iconHeight, iconAltX, iconAltY; private final int iconX, iconY, iconWidth, iconHeight, iconAltX, iconAltY;
List<ITextComponent> tooltip = new ArrayList<>(); List<String> tooltip = new ArrayList<>();
private boolean useAltIcon = false; private boolean useAltIcon = false;
public GuiIconButton(int x, int y, int iconX, int iconY, ResourceLocation resourceLocation, Button.IPressable onPress) { public GuiIconButton(int buttonId, int x, int y, int iconX, int iconY, ResourceLocation resourceLocation) {
this(x, y, 20, 20, iconX, iconY, 20, 20, 20, 0, resourceLocation, onPress); this(buttonId, x, y, 20, 20, iconX, iconY, 20, 20, 20, 0, resourceLocation);
} }
public GuiIconButton(int x, int y, int width, int height, int iconX, int iconY, int iconWidth, int iconHeight, int iconAltX, int iconAltY, ResourceLocation resourceLocation, Button.IPressable onPress) { public GuiIconButton(int buttonId, int x, int y, int width, int height, int iconX, int iconY, int iconWidth, int iconHeight, int iconAltX, int iconAltY, ResourceLocation resourceLocation) {
super(x, y, width, height, StringTextComponent.EMPTY, onPress); super(buttonId, x, y, width, height, "");
this.iconX = iconX; this.iconX = iconX;
this.iconY = iconY; this.iconY = iconY;
this.iconWidth = iconWidth; this.iconWidth = iconWidth;
this.iconHeight = iconHeight; this.iconHeight = iconHeight;
this.iconAltX = iconAltX; this.iconAltX = iconAltX;
this.iconAltY = iconAltY; this.iconAltY = iconAltY;
this.resourceLocation = resourceLocation; this.resourceLocation = resourceLocation;
} }
public void setTooltip(ITextComponent tooltip) { public void setTooltip(String tooltip) {
setTooltip(Collections.singletonList(tooltip)); setTooltip(Arrays.asList(tooltip));
} }
public void setTooltip(List<ITextComponent> tooltip) { public void setTooltip(List<String> tooltip) {
this.tooltip = tooltip; this.tooltip = tooltip;
} }
public void setUseAlternateIcon(boolean useAlternateIcon) { public void setUseAlternateIcon(boolean useAlternateIcon) {
this.useAltIcon = useAlternateIcon; this.useAltIcon = useAlternateIcon;
} }
@Override @Override
public void render(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) {
super.render(ms, mouseX, mouseY, partialTicks); super.drawButton(mc, mouseX, mouseY, partialTicks);
if (this.visible) { if (this.visible)
this.isHovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; {
Minecraft.getInstance().getTextureManager().bind(this.resourceLocation); this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
int currentIconX = this.iconX; mc.getTextureManager().bindTexture(this.resourceLocation);
int currentIconY = this.iconY; int currentIconX = this.iconX;
int currentIconY = this.iconY;
if (useAltIcon) { if (useAltIcon)
currentIconX += iconAltX; {
currentIconY += iconAltY; currentIconX += iconAltX;
} currentIconY += iconAltY;
}
//Draws a textured rectangle at the current z-value. Used to be drawTexturedModalRect in Gui. this.drawTexturedModalRect(this.x, this.y, currentIconX, currentIconY, this.iconWidth, this.iconHeight);
this.blit(ms, this.x, this.y, currentIconX, currentIconY, this.iconWidth, this.iconHeight); }
} }
}
public void drawTooltip(MatrixStack ms, Screen screen, int mouseX, int mouseY) { public void drawTooltip(GuiScreen guiScreen, int mouseX, int mouseY) {
boolean flag = mouseX >= x && mouseX < x + width && mouseY >= y && mouseY < y + height; boolean flag = mouseX >= x && mouseX < x + width && mouseY >= y && mouseY < y + height;
if (flag) { if (flag) {
screen.renderComponentTooltip(ms, tooltip, mouseX - 10, mouseY + 25); List<String> textLines = new ArrayList<>();
} textLines.addAll(tooltip);
} guiScreen.drawHoveringText(textLines, mouseX - 10, mouseY + 25);
}
}
} }

View File

@@ -1,160 +1,138 @@
package nl.requios.effortlessbuilding.gui.elements; package nl.requios.effortlessbuilding.gui.elements;
import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.Minecraft;
import mcp.MethodsReturnNonnullByDefault; import net.minecraft.client.gui.*;
import net.minecraft.client.gui.AbstractGui;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.client.gui.widget.Widget;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.ParametersAreNonnullByDefault; import java.io.IOException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Arrays;
import java.util.List; import java.util.List;
@OnlyIn(Dist.CLIENT) public class GuiNumberField extends Gui {
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class GuiNumberField extends AbstractGui {
public int x, y, width, height; public int x, y, width, height;
public int buttonWidth = 10; public int buttonWidth = 10;
protected TextFieldWidget textField; protected GuiTextField textField;
protected Button minusButton, plusButton; protected GuiButton minusButton, plusButton;
List<ITextComponent> tooltip = new ArrayList<>(); List<String> tooltip = new ArrayList<>();
public GuiNumberField(FontRenderer font, List<Widget> buttonList, int x, int y, int width, int height) { public GuiNumberField(int id1, int id2, int id3, FontRenderer fontRenderer,
this.x = x; List<GuiButton> buttonList, int x, int y, int width, int height) {
this.y = y; this.x = x;
this.width = width; this.y = y;
this.height = height; this.width = width;
this.height = height;
textField = new TextFieldWidget(font, x + buttonWidth + 1, y + 1, width - 2 * buttonWidth - 2, height - 2, StringTextComponent.EMPTY); textField = new GuiTextField(id1, fontRenderer, x + buttonWidth + 1, y + 1, width - 2 * buttonWidth - 2, height - 2);
minusButton = new Button(x, y - 1, buttonWidth, height + 2, new StringTextComponent("-"), button -> { minusButton = new GuiButton(id2, x, y - 1, buttonWidth, height + 2, "-");
float valueChanged = 1f; plusButton = new GuiButton(id3, x + width - buttonWidth, y - 1, buttonWidth, height + 2, "+");
if (Screen.hasControlDown()) valueChanged = 5f;
if (Screen.hasShiftDown()) valueChanged = 10f;
setNumber(getNumber() - valueChanged); buttonList.add(minusButton);
}); buttonList.add(plusButton);
plusButton = new Button(x + width - buttonWidth, y - 1, buttonWidth, height + 2, new StringTextComponent("+"), button -> { }
float valueChanged = 1f;
if (Screen.hasControlDown()) valueChanged = 5f;
if (Screen.hasShiftDown()) valueChanged = 10f;
setNumber(getNumber() + valueChanged); public void setNumber(double number) {
}); DecimalFormat format = new DecimalFormat("0.#");
textField.setText(format.format(number));
}
buttonList.add(minusButton); public double getNumber() {
buttonList.add(plusButton); if (textField.getText().isEmpty()) return 0;
} return Double.parseDouble(textField.getText());
}
public double getNumber() { public void setTooltip(String tooltip) {
if (textField.getValue().isEmpty()) return 0; setTooltip(Arrays.asList(tooltip));
try { }
return DecimalFormat.getInstance().parse(textField.getValue()).doubleValue();
} catch (ParseException e) {
return 0;
}
}
public void setNumber(double number) { public void setTooltip(List<String> tooltip) {
textField.setValue(DecimalFormat.getInstance().format(number)); this.tooltip = tooltip;
} }
public void setTooltip(ITextComponent tooltip) { public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) {
setTooltip(Collections.singletonList(tooltip)); boolean result = textField.mouseClicked(mouseX, mouseY, mouseButton);
}
public void setTooltip(List<ITextComponent> tooltip) { //Check if clicked inside textfield
this.tooltip = tooltip; boolean flag = mouseX >= x + buttonWidth && mouseX < x + width - buttonWidth && mouseY >= y && mouseY < y + height;
}
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) { //Rightclicked inside textfield
boolean result = textField.mouseClicked(mouseX, mouseY, mouseButton); if (flag && mouseButton == 1) {
textField.setText("");
textField.setFocused(true);
result = true;
}
//Check if clicked inside textfield return result;
boolean flag = mouseX >= x + buttonWidth && mouseX < x + width - buttonWidth && mouseY >= y && mouseY < y + height; }
//Rightclicked inside textfield public void drawNumberField(Minecraft mc, int mouseX, int mouseY, float partialTicks) {
if (flag && mouseButton == 1) { textField.y = y + 1;
textField.setValue(""); minusButton.y = y - 1;
textField.setFocus(true); plusButton.y = y - 1;
result = true;
}
return result; textField.drawTextBox();
} minusButton.drawButton(mc, mouseX, mouseY, partialTicks);
plusButton.drawButton(mc, mouseX, mouseY, partialTicks);
}
public void drawNumberField(MatrixStack ms, int mouseX, int mouseY, float partialTicks) { public void drawTooltip(GuiScreen guiScreen, int mouseX, int mouseY) {
textField.y = y + 1; boolean insideTextField = mouseX >= x + buttonWidth && mouseX < x + width - buttonWidth && mouseY >= y && mouseY < y + height;
minusButton.y = y - 1; boolean insideMinusButton = mouseX >= x && mouseX < x + buttonWidth && mouseY >= y && mouseY < y + height;
plusButton.y = y - 1; boolean insidePlusButton = mouseX >= x + width - buttonWidth && mouseX < x + width && mouseY >= y && mouseY < y + height;
textField.render(ms, mouseX, mouseY, partialTicks); List<String> textLines = new ArrayList<>();
minusButton.render(ms, mouseX, mouseY, partialTicks);
plusButton.render(ms, mouseX, mouseY, partialTicks);
}
public void drawTooltip(MatrixStack ms, Screen screen, int mouseX, int mouseY) { if (insideTextField) {
boolean insideTextField = mouseX >= x + buttonWidth && mouseX < x + width - buttonWidth && mouseY >= y && mouseY < y + height; if (!tooltip.isEmpty())
boolean insideMinusButton = mouseX >= x && mouseX < x + buttonWidth && mouseY >= y && mouseY < y + height; textLines.addAll(tooltip);
boolean insidePlusButton = mouseX >= x + width - buttonWidth && mouseX < x + width && mouseY >= y && mouseY < y + height;
// List<String> textLines = new ArrayList<>();
List<ITextComponent> textLines = new ArrayList<>();
if (insideTextField) {
textLines.addAll(tooltip);
// textLines.add(TextFormatting.GRAY + "Tip: try scrolling."); // textLines.add(TextFormatting.GRAY + "Tip: try scrolling.");
} }
if (insideMinusButton) { if (insideMinusButton) {
textLines.add(new StringTextComponent("Hold ").append(new StringTextComponent("shift ").withStyle(TextFormatting.AQUA)).append("for ") textLines.add("Hold " + TextFormatting.AQUA + "shift " + TextFormatting.RESET + "for " + TextFormatting.RED + "10");
.append(new StringTextComponent("10").withStyle(TextFormatting.RED))); textLines.add("Hold " + TextFormatting.AQUA + "ctrl " + TextFormatting.RESET + "for " + TextFormatting.RED + "5");
textLines.add(new StringTextComponent("Hold ").append(new StringTextComponent("ctrl ").withStyle(TextFormatting.AQUA)).append("for ") }
.append(new StringTextComponent("5").withStyle(TextFormatting.RED)));
}
if (insidePlusButton) { if (insidePlusButton) {
textLines.add(new StringTextComponent("Hold ").append(new StringTextComponent("shift ").withStyle(TextFormatting.DARK_GREEN)).append("for ") textLines.add("Hold " + TextFormatting.AQUA + "shift " + TextFormatting.RESET + "for " + TextFormatting.DARK_GREEN + "10");
.append(new StringTextComponent("10").withStyle(TextFormatting.RED))); textLines.add("Hold " + TextFormatting.AQUA + "ctrl " + TextFormatting.RESET + "for " + TextFormatting.DARK_GREEN + "5");
textLines.add(new StringTextComponent("Hold ").append(new StringTextComponent("ctrl ").withStyle(TextFormatting.DARK_GREEN)).append("for ") }
.append(new StringTextComponent("5").withStyle(TextFormatting.RED)));
}
screen.renderComponentTooltip(ms, textLines, mouseX - 10, mouseY + 25); guiScreen.drawHoveringText(textLines, mouseX - 10, mouseY + 25);
} }
public void update() { public void actionPerformed(GuiButton button) {
textField.tick(); float valueChanged = 1f;
} if (GuiScreen.isCtrlKeyDown()) valueChanged = 5f;
if (GuiScreen.isShiftKeyDown()) valueChanged = 10f;
public boolean charTyped(char typedChar, int keyCode) { if (button == minusButton) {
if (!textField.isFocused()) return false; setNumber(getNumber() - valueChanged);
}
if (button == plusButton) {
setNumber(getNumber() + valueChanged);
}
}
public void update() {
textField.updateCursorCounter();
}
public void keyTyped(char typedChar, int keyCode) throws IOException {
if (!textField.isFocused()) return;
// if (Character.isDigit(typedChar) || typedChar == '.' || typedChar == '-' || keyCode == Keyboard.KEY_BACK // if (Character.isDigit(typedChar) || typedChar == '.' || typedChar == '-' || keyCode == Keyboard.KEY_BACK
// || keyCode == Keyboard.KEY_DELETE || keyCode == Keyboard.KEY_LEFT || keyCode == Keyboard.KEY_RIGHT // || keyCode == Keyboard.KEY_DELETE || keyCode == Keyboard.KEY_LEFT || keyCode == Keyboard.KEY_RIGHT
// || keyCode == Keyboard.KEY_UP || keyCode == Keyboard.KEY_DOWN) { // || keyCode == Keyboard.KEY_UP || keyCode == Keyboard.KEY_DOWN) {
return textField.charTyped(typedChar, keyCode); textField.textboxKeyTyped(typedChar, keyCode);
// } // }
} }
//Scroll inside textfield to change number //Scroll inside textfield to change number
//Disabled because entire screen can be scrolled
// public void handleMouseInput(int mouseX, int mouseY) { // public void handleMouseInput(int mouseX, int mouseY) {
// boolean insideTextField = mouseX >= x + buttonWidth && mouseX < x + width - buttonWidth && mouseY >= y && mouseY < y + height; // boolean insideTextField = mouseX >= x + buttonWidth && mouseX < x + width - buttonWidth && mouseY >= y && mouseY < y + height;
// //

View File

@@ -1,229 +1,221 @@
package nl.requios.effortlessbuilding.gui.elements; package nl.requios.effortlessbuilding.gui.elements;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.IGuiEventListener; import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.GuiListExtended;
import net.minecraft.client.gui.widget.Widget; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.input.Mouse;
import javax.annotation.ParametersAreNonnullByDefault; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@OnlyIn(Dist.CLIENT) @SideOnly(Side.CLIENT)
@MethodsReturnNonnullByDefault public class GuiScrollPane extends GuiListExtended {
@ParametersAreNonnullByDefault
public class GuiScrollPane extends SlotGui {
public Screen parent; public GuiScreen parent;
public FontRenderer font; public FontRenderer fontRenderer;
private final List<IScrollEntry> listEntries; public List<IScrollEntry> listEntries;
private float scrollMultiplier = 1f;
private int mouseX; public GuiScrollPane(GuiScreen parent, FontRenderer fontRenderer, int top, int bottom) {
private int mouseY; super(parent.mc, parent.width, parent.height, top, bottom, 100);
this.parent = parent;
this.fontRenderer = fontRenderer;
this.setShowSelectionBox(false);
listEntries = new ArrayList<>();
}
public GuiScrollPane(Screen parent, FontRenderer font, int top, int bottom) { @Override
super(Minecraft.getInstance(), parent.width, parent.height, top, bottom, 100); public IGuiListEntry getListEntry(int index) {
this.parent = parent; return listEntries.get(index);
this.font = font; }
this.renderSelection = false;
listEntries = new ArrayList<>();
MinecraftForge.EVENT_BUS.register(this);
}
public IScrollEntry getListEntry(int index) { @Override
return listEntries.get(index); protected int getSize() {
} return listEntries.size();
}
public void AddListEntry(IScrollEntry listEntry) { @Override
listEntries.add(listEntry); protected int getScrollBarX() {
} //return width / 2 + 140 + 10;
return width - 15;
}
@Override @Override
protected int getItemCount() { public int getListWidth() {
return listEntries.size(); return 280;
} }
@Override //Removed background
protected boolean isSelectedItem(int slotIndex) { @Override
return false; public void drawScreen(int mouseXIn, int mouseYIn, float partialTicks)
} {
if (this.visible)
{
this.mouseX = mouseXIn;
this.mouseY = mouseYIn;
int scrollBarLeft = this.getScrollBarX();
int scrollBarRight = scrollBarLeft + 6;
this.bindAmountScrolled();
GlStateManager.disableLighting();
GlStateManager.disableFog();
@Override Tessellator tessellator = Tessellator.getInstance();
protected int getScrollbarPosition() { BufferBuilder bufferbuilder = tessellator.getBuffer();
//return width / 2 + 140 + 10; int insideLeft = this.left + this.width / 2 - this.getListWidth() / 2 + 2;
return width - 15; int insideTop = this.top + 4 - (int)this.amountScrolled;
}
@Override if (this.hasListHeader) {
public int getRowWidth() { this.drawListHeader(insideLeft, insideTop, tessellator);
return 280; }
}
//Removed background //All entries
@Override this.drawSelectionBox(insideLeft, insideTop, mouseXIn, mouseYIn, partialTicks);
public void render(MatrixStack ms, int mouseXIn, int mouseYIn, float partialTicks) { GlStateManager.disableDepth();
if (this.visible) {
this.mouseX = mouseXIn;
this.mouseY = mouseYIn;
this.renderBackground();
int scrollbarLeft = this.getScrollbarPosition();
int scrollbarRight = scrollbarLeft + 6;
this.capYPosition();
Tessellator tessellator = Tessellator.getInstance(); //Dirt overlays on top and bottom
BufferBuilder bufferbuilder = tessellator.getBuilder(); // this.overlayBackground(0, this.top, 255, 255);
// this.overlayBackground(this.bottom, this.height, 255, 255);
int insideLeft = this.x0 + this.width / 2 - this.getRowWidth() / 2 + 2; GlStateManager.enableBlend();
int insideTop = this.y0 + 4 - (int) this.yo; GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE);
if (this.renderHeader) { GlStateManager.disableAlpha();
this.renderHeader(insideLeft, insideTop, tessellator); GlStateManager.shadeModel(7425);
} GlStateManager.disableTexture2D();
//All entries // //top fade
this.renderList(ms, insideLeft, insideTop, mouseXIn, mouseYIn, partialTicks);
RenderSystem.disableDepthTest();
//Dirt overlays on top and bottom
// this.renderHoleBackground(0, this.y0, 255, 255);
// this.renderHoleBackground(this.y1, this.height, 255, 255);
RenderSystem.enableBlend();
RenderSystem.blendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ZERO, GlStateManager.DestFactor.ONE);
RenderSystem.disableAlphaTest();
RenderSystem.shadeModel(7425);
RenderSystem.disableTexture();
//top
// bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); // bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
// bufferbuilder.pos((double)this.x0, (double)(this.y0 + 4), 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 0).endVertex(); // bufferbuilder.pos((double)this.left, (double)(this.top + 5), 0.0D).tex(0.0D, 1.0D).color(100, 100, 100, 0).endVertex();
// bufferbuilder.pos((double)this.x1, (double)(this.y0 + 4), 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 0).endVertex(); // bufferbuilder.pos((double)this.right, (double)(this.top + 5), 0.0D).tex(1.0D, 1.0D).color(100, 100, 100, 0).endVertex();
// bufferbuilder.pos((double)this.x1, (double)this.y0, 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex(); // bufferbuilder.pos((double)this.right, (double)this.top, 0.0D).tex(1.0D, 0.0D).color(100, 100, 100, 100).endVertex();
// bufferbuilder.pos((double)this.x0, (double)this.y0, 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex(); // bufferbuilder.pos((double)this.left, (double)this.top, 0.0D).tex(0.0D, 0.0D).color(100, 100, 100, 100).endVertex();
// tessellator.draw(); // tessellator.draw();
//bottom // //top line
// bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); // bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
// bufferbuilder.pos((double)this.x0, (double)this.y1, 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex(); // bufferbuilder.pos((double)this.left, (double)this.top, 0.0D).tex(0.0D, 1.0D).color(20, 20, 20, 255).endVertex();
// bufferbuilder.pos((double)this.x1, (double)this.y1, 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex(); // bufferbuilder.pos((double)this.right, (double)this.top, 0.0D).tex(1.0D, 1.0D).color(20, 20, 20, 255).endVertex();
// bufferbuilder.pos((double)this.x1, (double)(this.y1 - 4), 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 0).endVertex(); // bufferbuilder.pos((double)this.right, (double)(this.top - 1), 0.0D).tex(1.0D, 0.0D).color(20, 20, 20, 255).endVertex();
// bufferbuilder.pos((double)this.x0, (double)(this.y1 - 4), 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 0).endVertex(); // bufferbuilder.pos((double)this.left, (double)(this.top - 1), 0.0D).tex(0.0D, 0.0D).color(20, 20, 20, 255).endVertex();
// tessellator.draw(); // tessellator.draw();
//Draw scrollbar // //bottom fade
int maxScroll = this.getMaxScroll(); // bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
if (maxScroll > 0) { // bufferbuilder.pos((double)this.left, (double)this.bottom, 0.0D).tex(0.0D, 1.0D).color(10, 10, 10, 100).endVertex();
int k1 = (int) ((float) ((this.y1 - this.y0) * (this.y1 - this.y0)) / (float) this.getMaxPosition()); // bufferbuilder.pos((double)this.right, (double)this.bottom, 0.0D).tex(1.0D, 1.0D).color(10, 10, 10, 100).endVertex();
k1 = MathHelper.clamp(k1, 32, this.y1 - this.y0 - 8); // bufferbuilder.pos((double)this.right, (double)(this.bottom - 5), 0.0D).tex(1.0D, 0.0D).color(10, 10, 10, 0).endVertex();
int l1 = (int) this.yo * (this.y1 - this.y0 - k1) / maxScroll + this.y0; // bufferbuilder.pos((double)this.left, (double)(this.bottom - 5), 0.0D).tex(0.0D, 0.0D).color(10, 10, 10, 0).endVertex();
if (l1 < this.y0) { // tessellator.draw();
l1 = this.y0;
}
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); // //bottom line
bufferbuilder.vertex(scrollbarLeft, this.y1, 0.0F).uv(0.0F, 1.0F).color(0, 0, 0, 255).endVertex(); // bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
bufferbuilder.vertex(scrollbarRight, this.y1, 0.0F).uv(1.0F, 1.0F).color(0, 0, 0, 255).endVertex(); // bufferbuilder.pos((double)this.left, (double)(this.bottom + 1), 0.0D).tex(0.0D, 1.0D).color(20, 20, 20, 255).endVertex();
bufferbuilder.vertex(scrollbarRight, this.y0, 0.0F).uv(1.0F, 0.0F).color(0, 0, 0, 255).endVertex(); // bufferbuilder.pos((double)this.right, (double)(this.bottom + 1), 0.0D).tex(1.0D, 1.0D).color(20, 20, 20, 255).endVertex();
bufferbuilder.vertex(scrollbarLeft, this.y0, 0.0F).uv(0.0F, 0.0F).color(0, 0, 0, 255).endVertex(); // bufferbuilder.pos((double)this.right, (double)this.bottom, 0.0D).tex(1.0D, 0.0D).color(20, 20, 20, 255).endVertex();
tessellator.end(); // bufferbuilder.pos((double)this.left, (double)this.bottom, 0.0D).tex(0.0D, 0.0D).color(20, 20, 20, 255).endVertex();
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR); // tessellator.draw();
bufferbuilder.vertex(scrollbarLeft, l1 + k1, 0.0F).uv(0.0F, 1.0F).color(128, 128, 128, 255).endVertex();
bufferbuilder.vertex(scrollbarRight, l1 + k1, 0.0F).uv(1.0F, 1.0F).color(128, 128, 128, 255).endVertex();
bufferbuilder.vertex(scrollbarRight, l1, 0.0F).uv(1.0F, 0.0F).color(128, 128, 128, 255).endVertex();
bufferbuilder.vertex(scrollbarLeft, l1, 0.0F).uv(0.0F, 0.0F).color(128, 128, 128, 255).endVertex();
tessellator.end();
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
bufferbuilder.vertex(scrollbarLeft, l1 + k1 - 1, 0.0F).uv(0.0F, 1.0F).color(192, 192, 192, 255).endVertex();
bufferbuilder.vertex(scrollbarRight - 1, l1 + k1 - 1, 0.0F).uv(1.0F, 1.0F).color(192, 192, 192, 255).endVertex();
bufferbuilder.vertex(scrollbarRight - 1, l1, 0.0F).uv(1.0F, 0.0F).color(192, 192, 192, 255).endVertex();
bufferbuilder.vertex(scrollbarLeft, l1, 0.0F).uv(0.0F, 0.0F).color(192, 192, 192, 255).endVertex();
tessellator.end();
}
//this.renderDecorations(mouseXIn, mouseYIn); //Draw scrollbar
RenderSystem.enableTexture(); int maxScroll = this.getMaxScroll();
RenderSystem.shadeModel(7424); if (maxScroll > 0)
RenderSystem.enableAlphaTest(); {
RenderSystem.disableBlend(); int k1 = (this.bottom - this.top) * (this.bottom - this.top) / this.getContentHeight();
} k1 = MathHelper.clamp(k1, 32, this.bottom - this.top - 8);
} int l1 = (int)this.amountScrolled * (this.bottom - this.top - k1) / maxScroll + this.top;
//SLOTHEIGHT MODIFICATIONS if (l1 < this.top)
//SlotHeight is still relied on for determining how much to scroll {
@Override l1 = this.top;
protected int getMaxPosition() { }
//Add every entry height
int height = this.headerHeight;
for (IScrollEntry entry : listEntries) {
height += entry.getHeight();
}
return height;
}
@Override bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
protected void renderBackground() { bufferbuilder.pos((double)scrollBarLeft, (double)this.bottom, 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex();
bufferbuilder.pos((double)scrollBarRight, (double)this.bottom, 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex();
bufferbuilder.pos((double)scrollBarRight, (double)this.top, 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex();
bufferbuilder.pos((double)scrollBarLeft, (double)this.top, 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex();
tessellator.draw();
} bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
bufferbuilder.pos((double)scrollBarLeft, (double)(l1 + k1), 0.0D).tex(0.0D, 1.0D).color(128, 128, 128, 255).endVertex();
bufferbuilder.pos((double)scrollBarRight, (double)(l1 + k1), 0.0D).tex(1.0D, 1.0D).color(128, 128, 128, 255).endVertex();
bufferbuilder.pos((double)scrollBarRight, (double)l1, 0.0D).tex(1.0D, 0.0D).color(128, 128, 128, 255).endVertex();
bufferbuilder.pos((double)scrollBarLeft, (double)l1, 0.0D).tex(0.0D, 0.0D).color(128, 128, 128, 255).endVertex();
tessellator.draw();
@Override bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
protected void renderItem(MatrixStack ms, int slotIndex, int xPos, int yPos, int heightIn, int mouseXIn, int mouseYIn, float partialTicks) { bufferbuilder.pos((double)scrollBarLeft, (double)(l1 + k1 - 1), 0.0D).tex(0.0D, 1.0D).color(192, 192, 192, 255).endVertex();
this.getListEntry(slotIndex).drawEntry(ms, slotIndex, xPos, yPos, this.getRowWidth(), heightIn, mouseXIn, mouseYIn, bufferbuilder.pos((double)(scrollBarRight - 1), (double)(l1 + k1 - 1), 0.0D).tex(1.0D, 1.0D).color(192, 192, 192, 255).endVertex();
this.getSlotIndexFromScreenCoords(mouseXIn, mouseYIn) == slotIndex, partialTicks); bufferbuilder.pos((double)(scrollBarRight - 1), (double)l1, 0.0D).tex(1.0D, 0.0D).color(192, 192, 192, 255).endVertex();
} bufferbuilder.pos((double)scrollBarLeft, (double)l1, 0.0D).tex(0.0D, 0.0D).color(192, 192, 192, 255).endVertex();
tessellator.draw();
}
public int getMaxPosition(int count) { GlStateManager.enableTexture2D();
//Add all count entry heights GlStateManager.shadeModel(7424);
int height = this.headerHeight; GlStateManager.enableAlpha();
for (int i = 0; i < count; i++) { GlStateManager.disableBlend();
IScrollEntry entry = listEntries.get(i); }
height += entry.getHeight(); }
}
return height;
}
public int getSlotIndexFromScreenCoords(double posX, double posY) { //SLOTHEIGHT MODIFICATIONS
int left = this.x0 + (this.width - this.getRowWidth()) / 2; //SlotHeight is still relied on for determining how much to scroll
int right = this.x0 + (this.width + this.getRowWidth()) / 2; @Override
double relativeMouseY = getRelativeMouseY(mouseY, 0); protected int getContentHeight() {
//Add every entry height
int height = this.headerPadding;
for (IScrollEntry entry : listEntries) {
height += entry.getHeight();
}
return height;
}
//Iterate over every entry until relativeMouseY falls within its height public int getContentHeight(int count) {
for (int i = 0; i < listEntries.size(); i++) { //Add all count entry heights
IScrollEntry entry = listEntries.get(i); int height = this.headerPadding;
if (relativeMouseY <= entry.getHeight()) for (int i = 0; i < count; i++) {
return posX < this.getScrollbarPosition() && posX >= left && posX <= right && i >= 0 && IScrollEntry entry = listEntries.get(i);
relativeMouseY >= 0 && i < this.getItemCount() ? i : -1; height += entry.getHeight();
relativeMouseY -= entry.getHeight(); }
} return height;
return -1; }
}
@Override @Override
public List<? extends IGuiEventListener> children() { public int getSlotIndexFromScreenCoords(int posX, int posY) {
return null; int left = this.left + (this.width - this.getListWidth()) / 2;
} int right = this.left + (this.width + this.getListWidth()) / 2;
int relativeMouseY = getRelativeMouseY(mouseY, 0);
@Override //Iterate over every entry until relativeMouseY falls within its height
public boolean mouseClicked(double mouseX, double mouseY, int button) { for (int i = 0; i < listEntries.size(); i++) {
int selectedSlot = this.getSlotIndexFromScreenCoords(mouseX, mouseY); IScrollEntry entry = listEntries.get(i);
double relativeX = getRelativeMouseX(mouseX); if (relativeMouseY <= entry.getHeight())
return posX < this.getScrollBarX() && posX >= left && posX <= right && i >= 0 &&
relativeMouseY >= 0 && i < this.getSize() ? i : -1;
relativeMouseY -= entry.getHeight();
}
return -1;
}
//Always pass through mouseclicked, to be able to unfocus textfields @Override
for (int i = 0; i < this.listEntries.size(); i++) { public boolean mouseClicked(int mouseX, int mouseY, int mouseEvent)
double relativeY = getRelativeMouseY(mouseY, i); {
this.getListEntry(i).mousePressed(selectedSlot, (int) mouseX, (int) mouseY, button, (int) relativeX, (int) relativeY); int selectedSlot = this.getSlotIndexFromScreenCoords(mouseX, mouseY);
} int relativeX = getRelativeMouseX(mouseX);
//Always pass through mouseclicked, to be able to unfocus textfields
for (int i = 0; i < this.listEntries.size(); i++) {
int relativeY = getRelativeMouseY(mouseY, i);
this.getListEntry(i).mousePressed(selectedSlot, mouseX, mouseY, mouseEvent, relativeX, relativeY);
}
// if (this.isMouseYWithinSlotBounds(mouseY)) // if (this.isMouseYWithinSlotBounds(mouseY))
@@ -243,230 +235,232 @@ public class GuiScrollPane extends SlotGui {
// } // }
// } // }
return false; return false;
} }
@Override @Override
public boolean mouseReleased(double mouseX, double mouseY, int button) { public boolean mouseReleased(int x, int y, int mouseEvent)
for (int i = 0; i < this.getItemCount(); ++i) { {
double relativeX = getRelativeMouseX(mouseX); for (int i = 0; i < this.getSize(); ++i)
double relativeY = getRelativeMouseY(mouseY, i); {
this.getListEntry(i).mouseReleased(i, (int) mouseX, (int) mouseY, button, (int) relativeX, (int) relativeY); int relativeX = getRelativeMouseX(mouseX);
} int relativeY = getRelativeMouseY(mouseY, i);
this.getListEntry(i).mouseReleased(i, x, y, mouseEvent, relativeX, relativeY);
}
this.visible = true; this.setEnabled(true);
return false; return false;
} }
public void handleMouseInput() { @Override
if (this.isMouseInList(this.mouseX, this.mouseY)) { public void handleMouseInput() {
if (minecraft.mouseHandler.isLeftPressed() && this.mouseY >= this.y0 && if (this.isMouseYWithinSlotBounds(this.mouseY)) {
this.mouseY <= this.y1) { if (Mouse.getEventButton() == 0 && Mouse.getEventButtonState() && this.mouseY >= this.top &&
int i = this.x0 + (this.width - this.getRowWidth()) / 2; this.mouseY <= this.bottom) {
int j = this.x0 + (this.width + this.getRowWidth()) / 2; int i = this.left + (this.width - this.getListWidth()) / 2;
int slotIndex = getSlotIndexFromScreenCoords(this.mouseX, this.mouseY); int j = this.left + (this.width + this.getListWidth()) / 2;
double relativeMouseY = getRelativeMouseY(mouseY, slotIndex); int slotIndex = getSlotIndexFromScreenCoords(this.mouseX, this.mouseY);
int relativeMouseY = getRelativeMouseY(mouseY, slotIndex);
if (slotIndex > -1) { if (slotIndex > -1) {
this.mouseClicked(this.mouseX, this.mouseY, 0); this.elementClicked(slotIndex, false, this.mouseX, this.mouseY);
} else if (this.mouseX >= i && this.mouseX <= j && relativeMouseY < 0) { this.selectedElement = slotIndex;
this.clickedHeader(this.mouseX - i, this.mouseY - this.y0 + (int) this.yo - 4); } else if (this.mouseX >= i && this.mouseX <= j && relativeMouseY < 0) {
} this.clickedHeader(this.mouseX - i, this.mouseY - this.top + (int) this.amountScrolled - 4);
} }
}
if (minecraft.mouseHandler.isLeftPressed() && this.isVisible()) { if (Mouse.isButtonDown(0) && this.getEnabled()) {
if (this.yDrag == -1) { if (this.initialClickY == -1) {
boolean flag1 = true; boolean flag1 = true;
if (this.mouseY >= this.y0 && this.mouseY <= this.y1) { if (this.mouseY >= this.top && this.mouseY <= this.bottom) {
int i2 = this.x0 + (this.width - this.getRowWidth()) / 2; int i2 = this.left + (this.width - this.getListWidth()) / 2;
int j2 = this.x0 + (this.width + this.getRowWidth()) / 2; int j2 = this.left + (this.width + this.getListWidth()) / 2;
int slotIndex = getSlotIndexFromScreenCoords(this.mouseX, this.mouseY); int slotIndex = getSlotIndexFromScreenCoords(this.mouseX, this.mouseY);
double relativeMouseY = getRelativeMouseY(mouseY, slotIndex); int relativeMouseY = getRelativeMouseY(mouseY, slotIndex);
if (slotIndex > -1) { if (slotIndex > -1) {
this.mouseClicked(slotIndex, this.mouseX, this.mouseY); boolean flag = slotIndex == this.selectedElement &&
} else if (this.mouseX >= i2 && this.mouseX <= j2 && relativeMouseY < 0) { Minecraft.getSystemTime() - this.lastClicked < 250L;
this.clickedHeader(this.mouseX - i2, this.elementClicked(slotIndex, flag, this.mouseX, this.mouseY);
this.mouseY - this.y0 + (int) this.yo - 4); this.selectedElement = slotIndex;
flag1 = false; this.lastClicked = Minecraft.getSystemTime();
} } else if (this.mouseX >= i2 && this.mouseX <= j2 && relativeMouseY < 0) {
this.clickedHeader(this.mouseX - i2,
this.mouseY - this.top + (int) this.amountScrolled - 4);
flag1 = false;
}
int i3 = this.getScrollbarPosition(); int i3 = this.getScrollBarX();
int j1 = i3 + 6; int j1 = i3 + 6;
if (this.mouseX >= i3 && this.mouseX <= j1) { if (this.mouseX >= i3 && this.mouseX <= j1) {
this.scrollMultiplier = -1.0F; this.scrollMultiplier = -1.0F;
int maxScroll = this.getMaxScroll(); int maxScroll = this.getMaxScroll();
if (maxScroll < 1) { if (maxScroll < 1) {
maxScroll = 1; maxScroll = 1;
} }
int l1 = (int) ((float) ((this.y1 - this.y0) * (this.y1 - this.y0)) / int l1 = (int) ((float) ((this.bottom - this.top) * (this.bottom - this.top)) /
(float) this.getMaxPosition()); (float) this.getContentHeight());
l1 = MathHelper.clamp(l1, 32, this.y1 - this.y0 - 8); l1 = MathHelper.clamp(l1, 32, this.bottom - this.top - 8);
this.scrollMultiplier /= (float) (this.y1 - this.y0 - l1) / (float) maxScroll; this.scrollMultiplier /= (float) (this.bottom - this.top - l1) / (float) maxScroll;
} else { } else {
this.scrollMultiplier = 1.0F; this.scrollMultiplier = 1.0F;
} }
if (flag1) { if (flag1) {
this.yDrag = this.mouseY; this.initialClickY = this.mouseY;
} else { } else {
this.yDrag = -2; this.initialClickY = -2;
} }
} else { } else {
this.yDrag = -2; this.initialClickY = -2;
} }
} else if (this.yDrag >= 0) { } else if (this.initialClickY >= 0) {
this.yo -= (float) (this.mouseY - this.yDrag) * this.scrollMultiplier; this.amountScrolled -= (float) (this.mouseY - this.initialClickY) * this.scrollMultiplier;
this.yDrag = this.mouseY; this.initialClickY = this.mouseY;
} }
} else { } else {
this.yDrag = -1; this.initialClickY = -1;
} }
} int i2 = Mouse.getEventDWheel();
}
//Draw in center if it fits if (i2 != 0) {
@Override if (i2 > 0) {
protected void renderList(MatrixStack ms, int insideLeft, int insideTop, int mouseXIn, int mouseYIn, float partialTicks) { i2 = -1;
int itemCount = this.getItemCount(); } else if (i2 < 0) {
Tessellator tessellator = Tessellator.getInstance(); i2 = 1;
BufferBuilder bufferbuilder = tessellator.getBuilder(); }
//Find y to start with this.amountScrolled += (float) (i2 * this.slotHeight / 2);
int y = this.headerHeight + insideTop; }
int contentHeight = getMaxPosition(); }
int insideHeight = this.y1 - this.y0 - 4; }
if (contentHeight < insideHeight) { //Draw in center if it fits
//it fits, so we can center it vertically @Override
y += (insideHeight - contentHeight) / 2; protected void drawSelectionBox(int insideLeft, int insideTop, int mouseXIn, int mouseYIn, float partialTicks)
} {
int size = this.getSize();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferbuilder = tessellator.getBuffer();
//Draw all entries //Find y to start with
for (int i = 0; i < itemCount; ++i) { int y = this.headerPadding + insideTop;
int entryHeight = listEntries.get(i).getHeight(); int contentHeight = getContentHeight();
int entryHeight2 = entryHeight - 4; int insideHeight = this.bottom - this.top - 4;
if (y > this.y1 || y + entryHeight2 < this.y0) { if (contentHeight < insideHeight) {
this.updateItemPosition(i, insideLeft, y, partialTicks); //it fits, so we can center it vertically
} y += (insideHeight - contentHeight) / 2;
}
if (this.renderSelection && this.isSelectedItem(i)) { //Draw all entries
int i1 = this.x0 + this.width / 2 - this.getRowWidth() / 2; for (int i = 0; i < size; ++i)
int j1 = this.x0 + this.width / 2 + this.getRowWidth() / 2; {
RenderSystem.disableTexture(); int entryHeight = listEntries.get(i).getHeight();
float f = this.isFocused() ? 1.0F : 0.5F; int entryHeight2 = entryHeight - 4;
RenderSystem.color4f(f, f, f, 1.0F);
bufferbuilder.begin(7, DefaultVertexFormats.POSITION);
bufferbuilder.vertex(i1, y + entryHeight2 + 2, 0.0D).endVertex();
bufferbuilder.vertex(j1, y + entryHeight2 + 2, 0.0D).endVertex();
bufferbuilder.vertex(j1, y - 2, 0.0D).endVertex();
bufferbuilder.vertex(i1, y - 2, 0.0D).endVertex();
tessellator.end();
RenderSystem.color4f(0.0F, 0.0F, 0.0F, 1.0F);
bufferbuilder.begin(7, DefaultVertexFormats.POSITION);
bufferbuilder.vertex(i1 + 1, y + entryHeight2 + 1, 0.0D).endVertex();
bufferbuilder.vertex(j1 - 1, y + entryHeight2 + 1, 0.0D).endVertex();
bufferbuilder.vertex(j1 - 1, y - 1, 0.0D).endVertex();
bufferbuilder.vertex(i1 + 1, y - 1, 0.0D).endVertex();
tessellator.end();
RenderSystem.enableTexture();
}
this.renderItem(ms, i, insideLeft, y, entryHeight2, mouseXIn, mouseYIn, partialTicks); if (y > this.bottom || y + entryHeight2 < this.top)
y += entryHeight; {
} this.updateItemPos(i, insideLeft, y, partialTicks);
} }
private double getRelativeMouseX(double mouseX) { if (this.showSelectionBox && this.isSelected(i))
int j = this.x0 + this.width / 2 - this.getRowWidth() / 2 + 2; {
return mouseX - j; int i1 = this.left + this.width / 2 - this.getListWidth() / 2;
} int j1 = this.left + this.width / 2 + this.getListWidth() / 2;
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
GlStateManager.disableTexture2D();
bufferbuilder.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
bufferbuilder.pos((double)i1, (double)(y + entryHeight2 + 2), 0.0D).tex(0.0D, 1.0D).color(128, 128, 128, 255).endVertex();
bufferbuilder.pos((double)j1, (double)(y + entryHeight2 + 2), 0.0D).tex(1.0D, 1.0D).color(128, 128, 128, 255).endVertex();
bufferbuilder.pos((double)j1, (double)(y - 2), 0.0D).tex(1.0D, 0.0D).color(128, 128, 128, 255).endVertex();
bufferbuilder.pos((double)i1, (double)(y - 2), 0.0D).tex(0.0D, 0.0D).color(128, 128, 128, 255).endVertex();
bufferbuilder.pos((double)(i1 + 1), (double)(y + entryHeight2 + 1), 0.0D).tex(0.0D, 1.0D).color(0, 0, 0, 255).endVertex();
bufferbuilder.pos((double)(j1 - 1), (double)(y + entryHeight2 + 1), 0.0D).tex(1.0D, 1.0D).color(0, 0, 0, 255).endVertex();
bufferbuilder.pos((double)(j1 - 1), (double)(y - 1), 0.0D).tex(1.0D, 0.0D).color(0, 0, 0, 255).endVertex();
bufferbuilder.pos((double)(i1 + 1), (double)(y - 1), 0.0D).tex(0.0D, 0.0D).color(0, 0, 0, 255).endVertex();
tessellator.draw();
GlStateManager.enableTexture2D();
}
private double getRelativeMouseY(double mouseY, int contentIndex) { this.drawSlot(i, insideLeft, y, entryHeight2, mouseXIn, mouseYIn, partialTicks);
int k = this.y0 + 4 - this.getScroll() + getMaxPosition(contentIndex) + this.headerHeight; y += entryHeight;
double relativeMouseY = mouseY - k; }
}
//Content might be centered, adjust relative mouse y accordingly private int getRelativeMouseX(int mouseX) {
int contentHeight = getMaxPosition(); int j = this.left + this.width / 2 - this.getListWidth() / 2 + 2;
int insideHeight = this.y1 - this.y0 - 4; return mouseX - j;
}
if (contentHeight < insideHeight) { private int getRelativeMouseY(int mouseY, int contentIndex) {
//it fits, so we can center it vertically int k = this.top + 4 - this.getAmountScrolled() + getContentHeight(contentIndex) + this.headerPadding;
relativeMouseY -= (insideHeight - contentHeight) / 2f; int relativeMouseY = mouseY - k;
}
return relativeMouseY;
}
//PASSTHROUGHS //Content might be centered, adjust relative mouse y accordingly
public void init(List<Widget> buttonList) { int contentHeight = getContentHeight();
for (IScrollEntry entry : this.listEntries) { int insideHeight = this.bottom - this.top - 4;
entry.init(buttonList);
}
}
public void updateScreen() { if (contentHeight < insideHeight) {
for (IScrollEntry entry : this.listEntries) //it fits, so we can center it vertically
entry.updateScreen(); relativeMouseY -= (insideHeight - contentHeight) / 2;
} }
return relativeMouseY;
}
public void drawTooltip(MatrixStack ms, Screen guiScreen, int mouseX, int mouseY) { //PASSTHROUGHS
for (IScrollEntry entry : this.listEntries) public int initGui(int id, List<GuiButton> buttonList) {
entry.drawTooltip(ms, guiScreen, mouseX, mouseY); for (IScrollEntry entry : this.listEntries) {
} id = entry.initGui(id, buttonList);
}
registerScrollButtons(id++, id++);
return id;
}
@Override public void updateScreen() {
public boolean charTyped(char eventChar, int eventKey) { for (IScrollEntry entry : this.listEntries)
for (IScrollEntry entry : this.listEntries) entry.updateScreen();
entry.charTyped(eventChar, eventKey); }
return false;
}
public void onGuiClosed() { public void drawTooltip(GuiScreen guiScreen, int mouseX, int mouseY) {
for (IScrollEntry entry : this.listEntries) for (IScrollEntry entry : this.listEntries)
entry.onGuiClosed(); entry.drawTooltip(guiScreen, mouseX, mouseY);
} }
//Make protected values available public void keyTyped(char eventChar, int eventKey) throws IOException {
public int getWidth() { for (IScrollEntry entry : this.listEntries)
return width; entry.keyTyped(eventChar, eventKey);
} }
public int getHeight() { public void actionPerformed(GuiButton button) {
return height; for (IScrollEntry entry : this.listEntries)
} entry.actionPerformed(button);
}
public interface IScrollEntry { public void onGuiClosed() {
void init(List<Widget> buttonList); for (IScrollEntry entry : this.listEntries)
entry.onGuiClosed();
}
void updateScreen(); public interface IScrollEntry extends GuiListExtended.IGuiListEntry {
int initGui(int id, List<GuiButton> buttonList);
void drawTooltip(MatrixStack ms, Screen guiScreen, int mouseX, int mouseY); void updateScreen();
boolean charTyped(char eventChar, int eventKey); void drawTooltip(GuiScreen guiScreen, int mouseX, int mouseY);
void onGuiClosed(); void keyTyped(char eventChar, int eventKey) throws IOException;
int getHeight(); void actionPerformed(GuiButton button);
void updatePosition(int slotIndex, int x, int y, float partialTicks); void onGuiClosed();
void drawEntry(MatrixStack ms, int slotIndex, int x, int y, int listWidth, int slotHeight, int mouseX, int mouseY, boolean isSelected, float partialTicks); int getHeight();
}
/**
* Called when the mouse is clicked within this entry. Returning true means that something within this entry was
* clicked and the list should not be dragged.
*/
boolean mousePressed(int slotIndex, int mouseX, int mouseY, int mouseEvent, int relativeX, int relativeY);
/**
* Fired when the mouse button is released. Arguments: index, x, y, mouseEvent, relativeX, relativeY
*/
void mouseReleased(int slotIndex, int x, int y, int mouseEvent, int relativeX, int relativeY);
}
} }

View File

@@ -1,263 +0,0 @@
package nl.requios.effortlessbuilding.gui.elements;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FocusableGui;
import net.minecraft.client.gui.IGuiEventListener;
import net.minecraft.client.gui.IRenderable;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Collections;
import java.util.List;
@OnlyIn(Dist.CLIENT)
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@SuppressWarnings("deprecation")
public abstract class SlotGui extends FocusableGui implements IRenderable {
protected final Minecraft minecraft;
protected final int itemHeight;
protected int width;
protected int height;
protected int y0;
protected int y1;
protected int x1;
protected int x0;
protected int yDrag = -2;
protected double yo;
protected boolean visible = true;
protected boolean renderSelection = true;
protected boolean renderHeader;
protected int headerHeight;
private boolean scrolling;
public SlotGui(Minecraft mcIn, int width, int height, int topIn, int bottomIn, int slotHeightIn) {
this.minecraft = mcIn;
this.width = width;
this.height = height;
this.y0 = topIn;
this.y1 = bottomIn;
this.itemHeight = slotHeightIn;
this.x0 = 0;
this.x1 = width;
}
public boolean isVisible() {
return this.visible;
}
protected abstract int getItemCount();
public List<? extends IGuiEventListener> children() {
return Collections.emptyList();
}
protected boolean selectItem(int p_selectItem_1_, int p_selectItem_2_, double p_selectItem_3_, double p_selectItem_5_) {
return true;
}
protected abstract boolean isSelectedItem(int p_isSelectedItem_1_);
protected int getMaxPosition() {
return this.getItemCount() * this.itemHeight + this.headerHeight;
}
protected abstract void renderBackground();
protected void updateItemPosition(int p_updateItemPosition_1_, int p_updateItemPosition_2_, int p_updateItemPosition_3_, float p_updateItemPosition_4_) {
}
protected abstract void renderItem(MatrixStack ms, int p_renderItem_1_, int p_renderItem_2_, int p_renderItem_3_, int p_renderItem_4_, int p_renderItem_5_, int p_renderItem_6_, float p_renderItem_7_);
protected void renderHeader(int p_renderHeader_1_, int p_renderHeader_2_, Tessellator p_renderHeader_3_) {
}
protected void clickedHeader(int p_clickedHeader_1_, int p_clickedHeader_2_) {
}
public int getItemAtPosition(double p_getItemAtPosition_1_, double p_getItemAtPosition_3_) {
int i = this.x0 + this.width / 2 - this.getRowWidth() / 2;
int j = this.x0 + this.width / 2 + this.getRowWidth() / 2;
int k = MathHelper.floor(p_getItemAtPosition_3_ - (double) this.y0) - this.headerHeight + (int) this.yo - 4;
int l = k / this.itemHeight;
return p_getItemAtPosition_1_ < (double) this.getScrollbarPosition() && p_getItemAtPosition_1_ >= (double) i && p_getItemAtPosition_1_ <= (double) j && l >= 0 && k >= 0 && l < this.getItemCount() ? l : -1;
}
protected void capYPosition() {
this.yo = MathHelper.clamp(this.yo, 0.0D, this.getMaxScroll());
}
public int getMaxScroll() {
return Math.max(0, this.getMaxPosition() - (this.y1 - this.y0 - 4));
}
public int getScroll() {
return (int) this.yo;
}
public boolean isMouseInList(double p_isMouseInList_1_, double p_isMouseInList_3_) {
return p_isMouseInList_3_ >= (double) this.y0 && p_isMouseInList_3_ <= (double) this.y1 && p_isMouseInList_1_ >= (double) this.x0 && p_isMouseInList_1_ <= (double) this.x1;
}
public abstract void render(MatrixStack ms, int p_render_1_, int p_render_2_, float p_render_3_);
protected void updateScrollingState(double p_updateScrollingState_1_, double p_updateScrollingState_3_, int p_updateScrollingState_5_) {
this.scrolling = p_updateScrollingState_5_ == 0 && p_updateScrollingState_1_ >= (double) this.getScrollbarPosition() && p_updateScrollingState_1_ < (double) (this.getScrollbarPosition() + 6);
}
public boolean mouseClicked(double p_mouseClicked_1_, double p_mouseClicked_3_, int p_mouseClicked_5_) {
this.updateScrollingState(p_mouseClicked_1_, p_mouseClicked_3_, p_mouseClicked_5_);
if (this.isVisible() && this.isMouseInList(p_mouseClicked_1_, p_mouseClicked_3_)) {
int i = this.getItemAtPosition(p_mouseClicked_1_, p_mouseClicked_3_);
if (i == -1 && p_mouseClicked_5_ == 0) {
this.clickedHeader((int) (p_mouseClicked_1_ - (double) (this.x0 + this.width / 2 - this.getRowWidth() / 2)), (int) (p_mouseClicked_3_ - (double) this.y0) + (int) this.yo - 4);
return true;
} else if (i != -1 && this.selectItem(i, p_mouseClicked_5_, p_mouseClicked_1_, p_mouseClicked_3_)) {
if (this.children().size() > i) {
this.setFocused(this.children().get(i));
}
this.setDragging(true);
return true;
} else {
return this.scrolling;
}
} else {
return false;
}
}
public boolean mouseReleased(double p_mouseReleased_1_, double p_mouseReleased_3_, int p_mouseReleased_5_) {
if (this.getFocused() != null) {
this.getFocused().mouseReleased(p_mouseReleased_1_, p_mouseReleased_3_, p_mouseReleased_5_);
}
return false;
}
public boolean mouseDragged(double p_mouseDragged_1_, double p_mouseDragged_3_, int p_mouseDragged_5_, double p_mouseDragged_6_, double p_mouseDragged_8_) {
if (super.mouseDragged(p_mouseDragged_1_, p_mouseDragged_3_, p_mouseDragged_5_, p_mouseDragged_6_, p_mouseDragged_8_)) {
return true;
} else if (this.isVisible() && p_mouseDragged_5_ == 0 && this.scrolling) {
if (p_mouseDragged_3_ < (double) this.y0) {
this.yo = 0.0D;
} else if (p_mouseDragged_3_ > (double) this.y1) {
this.yo = this.getMaxScroll();
} else {
double d0 = this.getMaxScroll();
if (d0 < 1.0D) {
d0 = 1.0D;
}
int i = (int) ((float) ((this.y1 - this.y0) * (this.y1 - this.y0)) / (float) this.getMaxPosition());
i = MathHelper.clamp(i, 32, this.y1 - this.y0 - 8);
double d1 = d0 / (double) (this.y1 - this.y0 - i);
if (d1 < 1.0D) {
d1 = 1.0D;
}
this.yo += p_mouseDragged_8_ * d1;
this.capYPosition();
}
return true;
} else {
return false;
}
}
public boolean mouseScrolled(double p_mouseScrolled_1_, double p_mouseScrolled_3_, double p_mouseScrolled_5_) {
if (!this.isVisible()) {
return false;
} else {
this.yo -= p_mouseScrolled_5_ * (double) this.itemHeight / 2.0D;
return true;
}
}
public boolean keyPressed(int p_keyPressed_1_, int p_keyPressed_2_, int p_keyPressed_3_) {
if (!this.isVisible()) {
return false;
} else if (super.keyPressed(p_keyPressed_1_, p_keyPressed_2_, p_keyPressed_3_)) {
return true;
} else if (p_keyPressed_1_ == 264) {
this.moveSelection(1);
return true;
} else if (p_keyPressed_1_ == 265) {
this.moveSelection(-1);
return true;
} else {
return false;
}
}
protected void moveSelection(int p_moveSelection_1_) {
}
public boolean charTyped(char p_charTyped_1_, int p_charTyped_2_) {
return this.isVisible() && super.charTyped(p_charTyped_1_, p_charTyped_2_);
}
public boolean isMouseOver(double p_isMouseOver_1_, double p_isMouseOver_3_) {
return this.isMouseInList(p_isMouseOver_1_, p_isMouseOver_3_);
}
public int getRowWidth() {
return 220;
}
protected void renderList(MatrixStack ms, int p_renderList_1_, int p_renderList_2_, int p_renderList_3_, int p_renderList_4_, float p_renderList_5_) {
int i = this.getItemCount();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder bufferbuilder = tessellator.getBuilder();
for (int j = 0; j < i; ++j) {
int k = p_renderList_2_ + j * this.itemHeight + this.headerHeight;
int l = this.itemHeight - 4;
if (k > this.y1 || k + l < this.y0) {
this.updateItemPosition(j, p_renderList_1_, k, p_renderList_5_);
}
if (this.renderSelection && this.isSelectedItem(j)) {
int i1 = this.x0 + this.width / 2 - this.getRowWidth() / 2;
int j1 = this.x0 + this.width / 2 + this.getRowWidth() / 2;
RenderSystem.disableTexture();
float f = this.isFocused() ? 1.0F : 0.5F;
RenderSystem.color4f(f, f, f, 1.0F);
bufferbuilder.begin(7, DefaultVertexFormats.POSITION);
bufferbuilder.vertex(i1, k + l + 2, 0.0D).endVertex();
bufferbuilder.vertex(j1, k + l + 2, 0.0D).endVertex();
bufferbuilder.vertex(j1, k - 2, 0.0D).endVertex();
bufferbuilder.vertex(i1, k - 2, 0.0D).endVertex();
tessellator.end();
RenderSystem.color4f(0.0F, 0.0F, 0.0F, 1.0F);
bufferbuilder.begin(7, DefaultVertexFormats.POSITION);
bufferbuilder.vertex(i1 + 1, k + l + 1, 0.0D).endVertex();
bufferbuilder.vertex(j1 - 1, k + l + 1, 0.0D).endVertex();
bufferbuilder.vertex(j1 - 1, k - 1, 0.0D).endVertex();
bufferbuilder.vertex(i1 + 1, k - 1, 0.0D).endVertex();
tessellator.end();
RenderSystem.enableTexture();
}
this.renderItem(ms, j, p_renderList_1_, k, l, p_renderList_3_, p_renderList_4_, p_renderList_5_);
}
}
protected boolean isFocused() {
return false;
}
protected int getScrollbarPosition() {
return this.width / 2 + 124;
}
}

View File

@@ -1,52 +1,54 @@
package nl.requios.effortlessbuilding.helper; package nl.requios.effortlessbuilding.helper;
import nl.requios.effortlessbuilding.EffortlessBuilding;
//Stack with fixed size. Removes (overwrites) oldest element on push. //Stack with fixed size. Removes (overwrites) oldest element on push.
public class FixedStack<T> { public class FixedStack<T> {
private final T[] stack; private T[] stack;
private final int size; private int size;
private int top; private int top;
private int filled = 0; //how many valid items are in the stack private int filled = 0; //how many valid items are in the stack
public FixedStack(T[] stack) { public FixedStack(T[] stack) {
this.stack = stack; this.stack = stack;
this.top = 0; this.top = 0;
this.size = stack.length; this.size = stack.length;
} }
public void push(T object) { public void push(T object) {
if (top == stack.length) if (top == stack.length)
top = 0; top = 0;
stack[top] = object; stack[top] = object;
top++; top++;
if (filled < size) if (filled < size)
filled++; filled++;
} }
public T pop() { public T pop() {
if (filled <= 0) return null; if (filled <= 0) return null;
if (top - 1 < 0) if (top - 1 < 0)
top = size; top = size;
top--; top--;
T object = stack[top]; T object = stack[top];
filled--; filled--;
return object; return object;
} }
public void clear() { public void clear() {
top = 0; top = 0;
filled = 0; filled = 0;
} }
public int size() { public int size() {
return size; return size;
} }
public boolean isEmpty() { public boolean isEmpty() {
return filled <= 0; return filled <= 0;
} }
} }

View File

@@ -1,30 +1,31 @@
package nl.requios.effortlessbuilding.helper; package nl.requios.effortlessbuilding.helper;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.block.state.IBlockState;
import net.minecraft.item.BlockItem; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
public class InventoryHelper { public class InventoryHelper {
public static ItemStack findItemStackInInventory(PlayerEntity player, Block block) { public static ItemStack findItemStackInInventory(EntityPlayer player, Block block) {
for (ItemStack invStack : player.inventory.items) { for (ItemStack invStack : player.inventory.mainInventory) {
if (!invStack.isEmpty() && invStack.getItem() instanceof BlockItem && if (!invStack.isEmpty() && invStack.getItem() instanceof ItemBlock &&
((BlockItem) invStack.getItem()).getBlock().equals(block)) { ((ItemBlock) invStack.getItem()).getBlock().equals(block)) {
return invStack; return invStack;
} }
} }
return ItemStack.EMPTY; return ItemStack.EMPTY;
} }
public static int findTotalBlocksInInventory(PlayerEntity player, Block block) { public static int findTotalBlocksInInventory(EntityPlayer player, Block block) {
int total = 0; int total = 0;
for (ItemStack invStack : player.inventory.items) { for (ItemStack invStack : player.inventory.mainInventory) {
if (!invStack.isEmpty() && invStack.getItem() instanceof BlockItem && if (!invStack.isEmpty() && invStack.getItem() instanceof ItemBlock &&
((BlockItem) invStack.getItem()).getBlock().equals(block)) { ((ItemBlock) invStack.getItem()).getBlock().equals(block)) {
total += invStack.getCount(); total += invStack.getCount();
} }
} }
return total; return total;
} }
} }

View File

@@ -0,0 +1,15 @@
package nl.requios.effortlessbuilding.helper;
import com.google.gson.JsonObject;
import net.minecraftforge.common.crafting.IConditionFactory;
import net.minecraftforge.common.crafting.JsonContext;
import nl.requios.effortlessbuilding.BuildConfig;
import java.util.function.BooleanSupplier;
public class ReachConditionFactory implements IConditionFactory {
@Override
public BooleanSupplier parse(JsonContext context, JsonObject json) {
return () -> BuildConfig.reach.enableReachUpgrades;
}
}

View File

@@ -1,54 +1,50 @@
package nl.requios.effortlessbuilding.helper; package nl.requios.effortlessbuilding.helper;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
public class ReachHelper { public class ReachHelper {
public static int getMaxReach(PlayerEntity player) { public static int getMaxReach(EntityPlayer player) {
if (player.isCreative()) return BuildConfig.reach.maxReachCreative.get(); if (player.isCreative()) return BuildConfig.reach.maxReachCreative;
if (!BuildConfig.reach.enableReachUpgrades.get()) return BuildConfig.reach.maxReachLevel3.get(); if (!BuildConfig.reach.enableReachUpgrades) return BuildConfig.reach.maxReachLevel3;
//Check buildsettings for reachUpgrade //Check buildsettings for reachUpgrade
int reachUpgrade = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade(); int reachUpgrade = ModifierSettingsManager.getModifierSettings(player).getReachUpgrade();
switch (reachUpgrade) { switch (reachUpgrade) {
case 0: case 0: return BuildConfig.reach.maxReachLevel0;
return BuildConfig.reach.maxReachLevel0.get(); case 1: return BuildConfig.reach.maxReachLevel1;
case 1: case 2: return BuildConfig.reach.maxReachLevel2;
return BuildConfig.reach.maxReachLevel1.get(); case 3: return BuildConfig.reach.maxReachLevel3;
case 2: }
return BuildConfig.reach.maxReachLevel2.get(); return BuildConfig.reach.maxReachLevel0;
case 3: }
return BuildConfig.reach.maxReachLevel3.get();
}
return BuildConfig.reach.maxReachLevel0.get();
}
public static int getPlacementReach(PlayerEntity player) { public static int getPlacementReach(EntityPlayer player) {
return getMaxReach(player) / 4; return getMaxReach(player) / 4;
} }
public static int getMaxBlocksPlacedAtOnce(PlayerEntity player) { public static int getMaxBlocksPlacedAtOnce(EntityPlayer player) {
if (player.isCreative()) return 1000000; if (player.isCreative()) return 1000000;
return MathHelper.ceil(Math.pow(getMaxReach(player), 1.6)); return MathHelper.ceil(Math.pow(getMaxReach(player), 1.6));
//Level 0: 121 //Level 0: 121
//Level 1: 523 //Level 1: 523
//Level 2: 1585 //Level 2: 1585
//Level 3: 4805 //Level 3: 4805
} }
public static int getMaxBlocksPerAxis(PlayerEntity player) { public static int getMaxBlocksPerAxis(EntityPlayer player) {
if (player.isCreative()) return 2000; if (player.isCreative()) return 2000;
return MathHelper.ceil(getMaxReach(player) * 0.3); return MathHelper.ceil(getMaxReach(player) * 0.3);
//Level 0: 6 //Level 0: 6
//Level 1: 15 //Level 1: 15
//Level 2: 30 //Level 2: 30
//Level 3: 60 //Level 3: 60
} }
public static boolean canBreakFar(PlayerEntity player) { public static boolean canBreakFar(EntityPlayer player) {
return player.isCreative() || BuildConfig.survivalBalancers.breakFar.get(); return player.isCreative() || BuildConfig.survivalBalancers.breakFar;
} }
} }

View File

@@ -1,22 +1,26 @@
package nl.requios.effortlessbuilding.helper; package nl.requios.effortlessbuilding.helper;
import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.block.Block;
import net.minecraft.block.*; import net.minecraft.block.BlockLiquid;
import net.minecraft.block.BlockSlab;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.init.Blocks;
import net.minecraft.item.BlockItem; import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemSlab;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.CachedBlockInfo; import net.minecraft.util.EnumFacing;
import net.minecraft.util.Direction; import net.minecraft.util.EnumHand;
import net.minecraft.util.Hand;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.ToolType;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
@@ -26,62 +30,55 @@ import javax.annotation.Nullable;
public class SurvivalHelper { public class SurvivalHelper {
//Used for all placing of blocks in this mod. //Used for all placing of blocks in this mod.
//Checks if area is loaded, if player has the right permissions, if existing block can be replaced (drops it if so) and consumes an item from the stack. //Checks if area is loaded, if player has the right permissions, if existing block can be replaced (drops it if so) and consumes an item from the stack.
//Based on ItemBlock#onItemUse //Based on ItemBlock#onItemUse
public static boolean placeBlock(World world, PlayerEntity player, BlockPos pos, BlockState blockState, public static boolean placeBlock(World world, EntityPlayer player, BlockPos pos, IBlockState blockState,
ItemStack origstack, Direction facing, Vector3d hitVec, boolean skipPlaceCheck, ItemStack origstack, EnumFacing facing, Vec3d hitVec, boolean skipPlaceCheck,
boolean skipCollisionCheck, boolean playSound) { boolean skipCollisionCheck, boolean playSound) {
if (!world.isLoaded(pos)) return false; if (!world.isBlockLoaded(pos, true)) return false;
ItemStack itemstack = origstack; ItemStack itemstack = origstack;
if (blockState.getBlock().isAir(blockState, world, pos) || itemstack.isEmpty()) { if (blockState.getBlock().isAir(blockState, world, pos) || itemstack.isEmpty()) {
dropBlock(world, player, pos); dropBlock(world, player, pos);
world.removeBlock(pos, false); world.setBlockToAir(pos);
return true; return true;
} }
//Randomizer bag, other proxy item synergy //Randomizer bag, other proxy item synergy
//Preliminary compatibility code for other items that hold blocks //Preliminary compatibility code for other items that hold blocks
if (CompatHelper.isItemBlockProxy(itemstack)) if (CompatHelper.isItemBlockProxy(itemstack))
itemstack = CompatHelper.getItemBlockByState(itemstack, blockState); itemstack = CompatHelper.getItemBlockByState(itemstack, blockState);
if (!(itemstack.getItem() instanceof BlockItem)) if (!(itemstack.getItem() instanceof ItemBlock))
return false; return false;
Block block = ((BlockItem) itemstack.getItem()).getBlock(); Block block = ((ItemBlock) itemstack.getItem()).getBlock();
//More manual with ItemBlock#placeBlockAt //More manual with ItemBlock#placeBlockAt
if (skipPlaceCheck || canPlace(world, player, pos, blockState, itemstack, skipCollisionCheck, facing.getOpposite())) { if (skipPlaceCheck || canPlace(world, player, pos, blockState, itemstack, skipCollisionCheck, facing.getOpposite())) {
//Drop existing block //Drop existing block
dropBlock(world, player, pos); dropBlock(world, player, pos);
//TryPlace sets block with offset and reduces itemstack count in creative, so we copy only parts of it boolean placed = ((ItemBlock) itemstack.getItem()).placeBlockAt(itemstack, player, world, pos, facing, (float) hitVec.x, (float) hitVec.y, (float) hitVec.z, blockState);
// BlockItemUseContext blockItemUseContext = new BlockItemUseContext(world, player, itemstack, pos, facing, (float) hitVec.x, (float) hitVec.y, (float) hitVec.z); if (!placed) return false;
// EnumActionResult result = ((ItemBlock) itemstack.getItem()).tryPlace(blockItemUseContext);
if (!world.setBlock(pos, blockState, 3)) return false;
BlockItem.updateCustomBlockEntityTag(world, player, pos, itemstack); //Actually BlockItem::onBlockPlaced but that is protected
block.setPlacedBy(world, pos, blockState, player, itemstack);
if (player instanceof ServerPlayerEntity) {
CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayerEntity) player, pos, itemstack);
}
BlockState afterState = world.getBlockState(pos); IBlockState afterState = world.getBlockState(pos);
if (playSound) { if (playSound) {
SoundType soundtype = afterState.getBlock().getSoundType(afterState, world, pos, player); SoundType soundtype = afterState.getBlock().getSoundType(afterState, world, pos, player);
world.playSound(null, pos, soundtype.getPlaceSound(), SoundCategory.BLOCKS, (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F); world.playSound(null, pos, soundtype.getPlaceSound(), SoundCategory.BLOCKS, (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F);
} }
if (!player.isCreative() && Block.byItem(itemstack.getItem()) == block) { if (!player.isCreative() && Block.getBlockFromItem(itemstack.getItem()) == block) {
itemstack.shrink(1); CompatHelper.shrinkStack(origstack, itemstack, player);
} }
return true; return true;
} }
return false; return false;
//Using ItemBlock#onItemUse //Using ItemBlock#onItemUse
// EnumActionResult result; // EnumActionResult result;
// PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock(player, EnumHand.MAIN_HAND, pos, facing, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(player, ReachHelper.getPlacementReach(player))); // PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock(player, EnumHand.MAIN_HAND, pos, facing, net.minecraftforge.common.ForgeHooks.rayTraceEyeHitVec(player, ReachHelper.getPlacementReach(player)));
// if (player.isCreative()) // if (player.isCreative())
@@ -104,40 +101,40 @@ public class SurvivalHelper {
// return false; // return false;
// } // }
} }
//Used for all breaking of blocks in this mod. //Used for all breaking of blocks in this mod.
//Checks if area is loaded, if appropriate tool is used in survival mode, and drops the block directly into the players inventory //Checks if area is loaded, if appropriate tool is used in survival mode, and drops the block directly into the players inventory
public static boolean breakBlock(World world, PlayerEntity player, BlockPos pos, boolean skipChecks) { public static boolean breakBlock(World world, EntityPlayer player, BlockPos pos, boolean skipChecks) {
if (!world.isLoaded(pos) && !world.isEmptyBlock(pos)) return false; if (!world.isBlockLoaded(pos, false)) return false;
//Check if can break //Check if can break
if (skipChecks || canBreak(world, player, pos)) { if (skipChecks || canBreak(world, player, pos)) {
// player.addStat(StatList.getBlockStats(world.getNewBlockState(pos).getBlock())); // player.addStat(StatList.getBlockStats(world.getNewBlockState(pos).getBlock()));
// player.addExhaustion(0.005F); // player.addExhaustion(0.005F);
//Drop existing block //Drop existing block
dropBlock(world, player, pos); dropBlock(world, player, pos);
//Damage tool //Damage tool
player.getMainHandItem().mineBlock(world, world.getBlockState(pos), pos, player); player.getHeldItemMainhand().onBlockDestroyed(world, world.getBlockState(pos), pos, player);
world.removeBlock(pos, false); world.setBlockToAir(pos);
return true; return true;
} }
return false; return false;
} }
//Gives items directly to player //Gives items directly to player
public static void dropBlock(World world, PlayerEntity player, BlockPos pos) { public static void dropBlock(World world, EntityPlayer player, BlockPos pos){
if (player.isCreative()) return; if (player.isCreative()) return;
BlockState blockState = world.getBlockState(pos); IBlockState blockState = world.getBlockState(pos);
Block block = blockState.getBlock(); Block block = blockState.getBlock();
block.playerDestroy(world, player, pos, blockState, world.getBlockEntity(pos), player.getMainHandItem()); block.harvestBlock(world, player, pos, blockState, world.getTileEntity(pos), player.getHeldItemMainhand());
//TODO drop items in inventory instead of world //TODO drop items in inventory instead of world
// List<ItemStack> drops = new ArrayList<>(); // List<ItemStack> drops = new ArrayList<>();
// //
@@ -165,173 +162,174 @@ public class SurvivalHelper {
// { // {
// ItemHandlerHelper.giveItemToPlayer(player, drop); // ItemHandlerHelper.giveItemToPlayer(player, drop);
// } // }
} }
/** /**
* Check if player can place a block. * Check if player can place a block.
* Turn randomizer bag into itemstack inside before. * Turn randomizer bag into itemstack inside before.
* * @param world
* @param world * @param player
* @param player * @param pos
* @param pos * @param newBlockState the blockstate that is going to be placed
* @param newBlockState the blockstate that is going to be placed * @param itemStack the itemstack used for placing
* @param itemStack the itemstack used for placing * @param skipCollisionCheck skips collision check with entities
* @param skipCollisionCheck skips collision check with entities * @param sidePlacedOn
* @param sidePlacedOn * @return Whether the player may place the block at pos with itemstack
* @return Whether the player may place the block at pos with itemstack */
*/ public static boolean canPlace(World world, EntityPlayer player, BlockPos pos, IBlockState newBlockState, ItemStack itemStack, boolean skipCollisionCheck, EnumFacing sidePlacedOn) {
public static boolean canPlace(World world, PlayerEntity player, BlockPos pos, BlockState newBlockState, ItemStack itemStack, boolean skipCollisionCheck, Direction sidePlacedOn) {
//Check if itemstack is correct //Check if itemstack is correct
if (!(itemStack.getItem() instanceof BlockItem) || Block.byItem(itemStack.getItem()) != newBlockState.getBlock()) { if (!(itemStack.getItem() instanceof ItemBlock) || Block.getBlockFromItem(itemStack.getItem()) != newBlockState.getBlock()) {
// EffortlessBuilding.log(player, "Cannot (re)place block", true); // EffortlessBuilding.log(player, "Cannot (re)place block", true);
// EffortlessBuilding.log("SurvivalHelper#canPlace: itemstack " + itemStack.toString() + " does not match blockstate " + newBlockState.toString()); // EffortlessBuilding.log("SurvivalHelper#canPlace: itemstack " + itemStack.toString() + " does not match blockstate " + newBlockState.toString());
//Happens when breaking blocks, no need to notify in that case //Happens when breaking blocks, no need to notify in that case
return false; return false;
} }
Block block = ((BlockItem) itemStack.getItem()).getBlock(); Block block = ((ItemBlock) itemStack.getItem()).getBlock();
return !itemStack.isEmpty() && canPlayerEdit(player, world, pos, itemStack) && return !itemStack.isEmpty() && canPlayerEdit(player, world, pos, itemStack) &&
mayPlace(world, block, newBlockState, pos, skipCollisionCheck, sidePlacedOn, player) && mayPlace(world, block, newBlockState, pos, skipCollisionCheck, sidePlacedOn, player) &&
canReplace(world, player, pos); canReplace(world, player, pos);
} }
//Can be harvested with hand? (or in creative) //Can be harvested with hand? (or in creative)
private static boolean canReplace(World world, PlayerEntity player, BlockPos pos) { private static boolean canReplace(World world, EntityPlayer player, BlockPos pos){
if (player.isCreative()) return true; if (player.isCreative()) return true;
BlockState state = world.getBlockState(pos); IBlockState state = world.getBlockState(pos);
state = state.getBlock().getActualState(state, world, pos);
switch (BuildConfig.survivalBalancers.quickReplaceMiningLevel.get()) { switch (BuildConfig.survivalBalancers.quickReplaceMiningLevel) {
case -1: case -1: return state.getMaterial().isToolNotRequired();
return !state.requiresCorrectToolForDrops(); case 0: return state.getBlock().getHarvestLevel(state) <= 0;
case 0: case 1: return state.getBlock().getHarvestLevel(state) <= 1;
return state.getBlock().getHarvestLevel(state) <= 0; case 2: return state.getBlock().getHarvestLevel(state) <= 2;
case 1: case 3: return state.getBlock().getHarvestLevel(state) <= 3;
return state.getBlock().getHarvestLevel(state) <= 1; }
case 2:
return state.getBlock().getHarvestLevel(state) <= 2;
case 3:
return state.getBlock().getHarvestLevel(state) <= 3;
}
return false; return false;
} }
//From EntityPlayer#canPlayerEdit //From EntityPlayer#canPlayerEdit
private static boolean canPlayerEdit(PlayerEntity player, World world, BlockPos pos, ItemStack stack) { private static boolean canPlayerEdit(EntityPlayer player, World world, BlockPos pos, ItemStack stack)
if (!world.mayInteract(player, pos)) return false; {
if (player.capabilities.allowEdit)
{
//True in creative and survival mode
return true;
}
else
{
//Adventure mode
Block block = world.getBlockState(pos).getBlock();
return stack.canPlaceOn(block) || stack.canEditBlocks();
}
}
if (player.abilities.mayBuild) { //From World#mayPlace
//True in creative and survival mode private static boolean mayPlace(World world, Block blockIn, IBlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, EnumFacing sidePlacedOn, @Nullable Entity placer)
return true; {
} else { IBlockState iblockstate1 = world.getBlockState(pos);
//Adventure mode AxisAlignedBB axisalignedbb = skipCollisionCheck ? Block.NULL_AABB : blockIn.getDefaultState().getCollisionBoundingBox(world, pos);
CachedBlockInfo blockworldstate = new CachedBlockInfo(world, pos, false);
return stack.hasAdventureModePlaceTagForBlock(world.getTagManager(), blockworldstate);
} if (axisalignedbb != Block.NULL_AABB && !world.checkNoEntityCollision(axisalignedbb.offset(pos)))
} {
return false;
}
//From World#mayPlace //Check if double slab
private static boolean mayPlace(World world, Block blockIn, BlockState newBlockState, BlockPos pos, boolean skipCollisionCheck, Direction sidePlacedOn, @Nullable Entity placer) { if (placer != null && doesBecomeDoubleSlab(((EntityPlayer) placer), pos, sidePlacedOn)) {
BlockState iblockstate1 = world.getBlockState(pos); return true;
VoxelShape voxelShape = skipCollisionCheck ? null : blockIn.defaultBlockState().getCollisionShape(world, pos); }
if (voxelShape != null && !world.isUnobstructed(placer, voxelShape)) { //Check if same block
return false; //Necessary otherwise extra items will be dropped
} if (iblockstate1 == newBlockState) {
return false;
}
//Check if double slab if (iblockstate1.getMaterial() == Material.CIRCUITS && blockIn == Blocks.ANVIL)
if (placer != null && doesBecomeDoubleSlab(((PlayerEntity) placer), pos, sidePlacedOn)) { {
return true; return true;
} }
//Check if same block //Check quickreplace
//Necessary otherwise extra items will be dropped if (placer instanceof EntityPlayer && ModifierSettingsManager.getModifierSettings(((EntityPlayer) placer)).doQuickReplace()) {
if (iblockstate1 == newBlockState) { return true;
return false; }
}
//TODO 1.14 check what Material.CIRCUITS has become return iblockstate1.getBlock().isReplaceable(world, pos) && blockIn.canPlaceBlockOnSide(world, pos, sidePlacedOn);
if (iblockstate1.getMaterial() == Material.BUILDABLE_GLASS && blockIn == Blocks.ANVIL) { }
return true;
}
//Check quickreplace
if (placer instanceof PlayerEntity && ModifierSettingsManager.getModifierSettings(((PlayerEntity) placer)).doQuickReplace()) {
return true;
}
//TODO 1.13 replaceable
return iblockstate1.getMaterial().isReplaceable() /*&& canPlaceBlockOnSide(world, pos, sidePlacedOn)*/;
}
//Can break using held tool? (or in creative)
public static boolean canBreak(World world, PlayerEntity player, BlockPos pos) {
BlockState blockState = world.getBlockState(pos);
if (!world.getFluidState(pos).isEmpty()) return false;
if (player.isCreative()) return true; //Can break using held tool? (or in creative)
public static boolean canBreak(World world, EntityPlayer player, BlockPos pos) {
IBlockState blockState = world.getBlockState(pos);
if (blockState.getBlock() instanceof BlockLiquid) return false;
return canHarvestBlock(blockState.getBlock(), player, world, pos); if (player.isCreative()) return true;
}
//From ForgeHooks#canHarvestBlock return canHarvestBlock(blockState.getBlock(), player, world, pos);
public static boolean canHarvestBlock(@Nonnull Block block, @Nonnull PlayerEntity player, @Nonnull World world, @Nonnull BlockPos pos) { }
BlockState state = world.getBlockState(pos);
//Dont break bedrock //From ForgeHooks#canHarvestBlock
if (state.getDestroySpeed(world, pos) < 0) { public static boolean canHarvestBlock(@Nonnull Block block, @Nonnull EntityPlayer player, @Nonnull IBlockAccess world, @Nonnull BlockPos pos)
return false; {
} IBlockState state = world.getBlockState(pos);
state = state.getBlock().getActualState(state, world, pos);
if (!state.requiresCorrectToolForDrops()) { //Dont break bedrock
return true; if (state.getBlockHardness((World) world, pos) < 0) {
} return false;
}
ItemStack stack = player.getMainHandItem(); if (state.getMaterial().isToolNotRequired())
ToolType tool = block.getHarvestTool(state); {
if (stack.isEmpty() || tool == null) { return true;
return player.hasCorrectToolForDrops(state); }
}
if (stack.getDamageValue() >= stack.getMaxDamage()) return false; ItemStack stack = player.getHeldItemMainhand();
String tool = block.getHarvestTool(state);
if (stack.isEmpty() || tool == null)
{
return player.canHarvestBlock(state);
}
int toolLevel = stack.getItem().getHarvestLevel(stack, tool, player, state); if (stack.getItemDamage() >= stack.getMaxDamage()) return false;
if (toolLevel < 0) {
return player.hasCorrectToolForDrops(state);
}
return toolLevel >= block.getHarvestLevel(state); int toolLevel = stack.getItem().getHarvestLevel(stack, tool, player, state);
} if (toolLevel < 0)
{
return player.canHarvestBlock(state);
}
public static boolean doesBecomeDoubleSlab(PlayerEntity player, BlockPos pos, Direction facing) { return toolLevel >= block.getHarvestLevel(state);
BlockState placedBlockState = player.level.getBlockState(pos); }
ItemStack itemstack = player.getItemInHand(Hand.MAIN_HAND); public static boolean doesBecomeDoubleSlab(EntityPlayer player, BlockPos pos, EnumFacing facing) {
if (CompatHelper.isItemBlockProxy(itemstack)) IBlockState placedBlockState = player.world.getBlockState(pos);
itemstack = CompatHelper.getItemBlockFromStack(itemstack);
if (itemstack.isEmpty() || !(itemstack.getItem() instanceof BlockItem) || !(((BlockItem) itemstack.getItem()).getBlock() instanceof SlabBlock)) ItemStack itemstack = player.getHeldItem(EnumHand.MAIN_HAND);
return false; if (CompatHelper.isItemBlockProxy(itemstack))
SlabBlock heldSlab = (SlabBlock) ((BlockItem) itemstack.getItem()).getBlock(); itemstack = CompatHelper.getItemBlockFromStack(itemstack);
if (placedBlockState.getBlock() == heldSlab) { if (itemstack.isEmpty() || !(itemstack.getItem() instanceof ItemSlab)) return false;
//TODO 1.13 BlockSlab heldSlab = (BlockSlab) ((ItemSlab) itemstack.getItem()).getBlock();
// IProperty<?> variantProperty = heldSlab.getVariantProperty();
// Comparable<?> placedVariant = placedBlockState.getValue(variantProperty); if (placedBlockState.getBlock() == heldSlab) {
// BlockSlab.EnumBlockHalf placedHalf = placedBlockState.getValue(BlockSlab.HALF); IProperty<?> variantProperty = heldSlab.getVariantProperty();
// Comparable<?> placedVariant = placedBlockState.getValue(variantProperty);
// Comparable<?> heldVariant = heldSlab.getTypeForItem(itemstack); BlockSlab.EnumBlockHalf placedHalf = placedBlockState.getValue(BlockSlab.HALF);
//
// if ((facing == EnumFacing.UP && placedHalf == BlockSlab.EnumBlockHalf.BOTTOM || facing == EnumFacing.DOWN && placedHalf == BlockSlab.EnumBlockHalf.TOP) && placedVariant == heldVariant) Comparable<?> heldVariant = heldSlab.getTypeForItem(itemstack);
// {
// return true; if ((facing == EnumFacing.UP && placedHalf == BlockSlab.EnumBlockHalf.BOTTOM || facing == EnumFacing.DOWN && placedHalf == BlockSlab.EnumBlockHalf.TOP) && placedVariant == heldVariant)
// } {
} return true;
return false; }
} }
return false;
}
} }

View File

@@ -1,46 +0,0 @@
package nl.requios.effortlessbuilding.item;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagContainer;
import javax.annotation.Nullable;
public class DiamondRandomizerBagItem extends AbstractRandomizerBagItem{
public static final int INV_SIZE = 27;
@Override
public int getInventorySize() {
return 27;
}
@Override
public INamedContainerProvider getContainerProvider(ItemStack bag) {
return new ContainerProvider(bag);
}
public static class ContainerProvider implements INamedContainerProvider {
private final ItemStack bag;
public ContainerProvider(ItemStack bag) {
this.bag = bag;
}
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("effortlessbuilding:diamond_randomizer_bag");
}
@Nullable
@Override
public Container createMenu(int containerId, PlayerInventory playerInventory, PlayerEntity player) {
return new DiamondRandomizerBagContainer(containerId, playerInventory, ((AbstractRandomizerBagItem)bag.getItem()).getBagInventory(bag));
}
}
}

View File

@@ -1,46 +0,0 @@
package nl.requios.effortlessbuilding.item;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagContainer;
import javax.annotation.Nullable;
public class GoldenRandomizerBagItem extends AbstractRandomizerBagItem{
public static final int INV_SIZE = 9;
@Override
public int getInventorySize() {
return 9;
}
@Override
public INamedContainerProvider getContainerProvider(ItemStack bag) {
return new ContainerProvider(bag);
}
public static class ContainerProvider implements INamedContainerProvider {
private final ItemStack bag;
public ContainerProvider(ItemStack bag) {
this.bag = bag;
}
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("effortlessbuilding:golden_randomizer_bag");
}
@Nullable
@Override
public Container createMenu(int containerId, PlayerInventory playerInventory, PlayerEntity player) {
return new GoldenRandomizerBagContainer(containerId, playerInventory, ((AbstractRandomizerBagItem)bag.getItem()).getBagInventory(bag));
}
}
}

View File

@@ -1,30 +1,25 @@
package nl.requios.effortlessbuilding.item; package nl.requios.effortlessbuilding.item;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.util.ITooltipFlag; import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.fluid.Fluids; import net.minecraft.item.Item;
import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack;
import net.minecraft.item.*; import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType; import net.minecraft.util.EnumActionResult;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.Hand; import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
@@ -32,42 +27,120 @@ import nl.requios.effortlessbuilding.capability.ItemHandlerCapabilityProvider;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
@MethodsReturnNonnullByDefault public class ItemRandomizerBag extends Item {
@ParametersAreNonnullByDefault public static final int INV_SIZE = 5;
public abstract class AbstractRandomizerBagItem extends Item {
private static long currentSeed = 1337; private static long currentSeed = 1337;
private static final Random rand = new Random(currentSeed); private static Random rand = new Random(currentSeed);
public AbstractRandomizerBagItem() { public ItemRandomizerBag() {
super(new Item.Properties().tab(ItemGroup.TAB_TOOLS).stacksTo(1)); this.setRegistryName(EffortlessBuilding.MODID, "randomizer_bag");
this.setTranslationKey(this.getRegistryName().toString());
this.maxStackSize = 1;
this.setCreativeTab(CreativeTabs.TOOLS);
} }
public abstract int getInventorySize(); @Override
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) {
public abstract INamedContainerProvider getContainerProvider(ItemStack item); if (player.isSneaking()) {
if (world.isRemote) return EnumActionResult.SUCCESS;
//Open inventory
player.openGui(EffortlessBuilding.instance, EffortlessBuilding.RANDOMIZER_BAG_GUI, world, 0, 0, 0);
} else {
if (world.isRemote) return EnumActionResult.SUCCESS;
//Only place manually if in normal vanilla mode
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
if (buildMode != BuildModes.BuildModeEnum.NORMAL || modifierSettings.doQuickReplace()) {
return EnumActionResult.FAIL;
}
//Use item
//Get bag inventory
ItemStack bag = player.getHeldItem(hand);
IItemHandler bagInventory = getBagInventory(bag);
if (bagInventory == null)
return EnumActionResult.FAIL;
ItemStack toPlace = pickRandomStack(bagInventory);
if (toPlace.isEmpty()) return EnumActionResult.FAIL;
//Previously: use onItemUse to place block (no synergy)
//bag.setItemDamage(toPlace.getMetadata());
//toPlace.onItemUse(player, world, pos, hand, facing, hitX, hitY, hitZ);
if (!world.getBlockState(pos).getBlock().isReplaceable(world, pos)) {
pos = pos.offset(facing);
}
IBlockState blockState = Block.getBlockFromItem(toPlace.getItem()).getStateForPlacement(world, pos, facing,
hitX, hitY, hitZ, toPlace.getMetadata(), player, hand);
SurvivalHelper.placeBlock(world, player, pos, blockState, toPlace, facing, new Vec3d(hitX, hitY, hitZ), false, false, true);
//Synergy
//Works without calling
// BlockSnapshot blockSnapshot = new BlockSnapshot(player.world, pos, blockState);
// BlockEvent.PlaceEvent placeEvent = new BlockEvent.PlaceEvent(blockSnapshot, blockState, player, hand);
// Mirror.onBlockPlaced(placeEvent);
// Array.onBlockPlaced(placeEvent);
}
return EnumActionResult.SUCCESS;
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
ItemStack bag = player.getHeldItem(hand);
if (player.isSneaking()) {
if (world.isRemote) return new ActionResult<>(EnumActionResult.SUCCESS, bag);
//Open inventory
player.openGui(EffortlessBuilding.instance, EffortlessBuilding.RANDOMIZER_BAG_GUI, world, 0, 0, 0);
} else {
//Use item
//Get bag inventory
IItemHandler bagInventory = getBagInventory(bag);
if (bagInventory == null)
return new ActionResult<>(EnumActionResult.FAIL, bag);
ItemStack toUse = pickRandomStack(bagInventory);
if (toUse.isEmpty()) return new ActionResult<>(EnumActionResult.FAIL, bag);
return toUse.useItemRightClick(world, player, hand);
}
return new ActionResult<>(EnumActionResult.PASS, bag);
}
/** /**
* Get the inventory of a randomizer bag by checking the capability. * Get the inventory of a randomizer bag by checking the capability.
*
* @param bag
* @return
*/ */
public IItemHandler getBagInventory(ItemStack bag) { public static IItemHandler getBagInventory(ItemStack bag) {
return bag.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null).orElse(null); if (!bag.hasCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null)) return null;
return bag.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null);
} }
/** /**
* Pick a random slot from the bag. Empty slots will never get chosen. * Pick a random slot from the bag. Empty slots will never get chosen.
*
* @param bagInventory
* @return
*/ */
public ItemStack pickRandomStack(IItemHandler bagInventory) { public static ItemStack pickRandomStack(IItemHandler bagInventory) {
//Find how many stacks are non-empty, and save them in a list //Find how many stacks are non-empty, and save them in a list
int nonempty = 0; int nonempty = 0;
List<ItemStack> nonEmptyStacks = new ArrayList<>(); List<ItemStack> nonEmptyStacks = new ArrayList<>(INV_SIZE);
List<Integer> originalSlots = new ArrayList<>(getInventorySize()); List<Integer> originalSlots = new ArrayList<>(INV_SIZE);
for (int i = 0; i < bagInventory.getSlots(); i++) { for (int i = 0; i < bagInventory.getSlots(); i++) {
ItemStack stack = bagInventory.getStackInSlot(i); ItemStack stack = bagInventory.getStackInSlot(i);
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
@@ -92,7 +165,7 @@ public abstract class AbstractRandomizerBagItem extends Item {
return bagInventory.getStackInSlot(originalSlot); return bagInventory.getStackInSlot(originalSlot);
} }
public ItemStack findStack(IItemHandler bagInventory, Item item) { public static ItemStack findStack(IItemHandler bagInventory, Item item) {
for (int i = 0; i < bagInventory.getSlots(); i++) { for (int i = 0; i < bagInventory.getSlots(); i++) {
ItemStack stack = bagInventory.getStackInSlot(i); ItemStack stack = bagInventory.getStackInSlot(i);
if (!stack.isEmpty() && stack.getItem() == item) { if (!stack.isEmpty() && stack.getItem() == item) {
@@ -102,6 +175,28 @@ public abstract class AbstractRandomizerBagItem extends Item {
return ItemStack.EMPTY; return ItemStack.EMPTY;
} }
@Override
public int getMaxItemUseDuration(ItemStack stack) {
return 1;
}
@Nullable
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable NBTTagCompound nbt) {
return new ItemHandlerCapabilityProvider();
}
@Override
public void addInformation(ItemStack stack, @Nullable World world, List<String> tooltip, ITooltipFlag flag) {
tooltip.add(TextFormatting.BLUE + "Rightclick" + TextFormatting.GRAY + " to place a random block");
tooltip.add(TextFormatting.BLUE + "Sneak + rightclick" + TextFormatting.GRAY + " to open inventory");
}
@Override
public String getTranslationKey() {
return super.getTranslationKey();
}
public static void resetRandomness() { public static void resetRandomness() {
rand.setSeed(currentSeed); rand.setSeed(currentSeed);
} }
@@ -110,112 +205,4 @@ public abstract class AbstractRandomizerBagItem extends Item {
currentSeed = Calendar.getInstance().getTimeInMillis(); currentSeed = Calendar.getInstance().getTimeInMillis();
rand.setSeed(currentSeed); rand.setSeed(currentSeed);
} }
@Override
public ActionResultType useOn(ItemUseContext ctx) {
PlayerEntity player = ctx.getPlayer();
World world = ctx.getLevel();
BlockPos pos = ctx.getClickedPos();
Direction facing = ctx.getClickedFace();
ItemStack item = ctx.getItemInHand();
Vector3d hitVec = ctx.getClickLocation();
if (player == null) return ActionResultType.FAIL;
if (ctx.getPlayer() != null && ctx.getPlayer().isShiftKeyDown()) { //ctx.isPlacerSneaking()
if (world.isClientSide) return ActionResultType.SUCCESS;
//Open inventory
NetworkHooks.openGui((ServerPlayerEntity) player, getContainerProvider(item));
} else {
if (world.isClientSide) return ActionResultType.SUCCESS;
//Only place manually if in normal vanilla mode
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
if (buildMode != BuildModes.BuildModeEnum.NORMAL || modifierSettings.doQuickReplace()) {
return ActionResultType.FAIL;
}
//Use item
//Get bag inventory
//TODO offhand support
ItemStack bag = player.getItemInHand(Hand.MAIN_HAND);
IItemHandler bagInventory = getBagInventory(bag);
if (bagInventory == null)
return ActionResultType.FAIL;
ItemStack toPlace = pickRandomStack(bagInventory);
if (toPlace.isEmpty()) return ActionResultType.FAIL;
//Previously: use onItemUse to place block (no synergy)
//bag.setItemDamage(toPlace.getMetadata());
//toPlace.onItemUse(player, world, pos, hand, facing, hitX, hitY, hitZ);
//TODO replaceable
if (!world.getBlockState(pos).getBlock().canBeReplaced(world.getBlockState(pos), Fluids.EMPTY)) {
pos = pos.relative(facing);
}
BlockItemUseContext blockItemUseContext = new BlockItemUseContext(new ItemUseContext(player, Hand.MAIN_HAND, new BlockRayTraceResult(hitVec, facing, pos, false)));
BlockState blockState = Block.byItem(toPlace.getItem()).getStateForPlacement(blockItemUseContext);
SurvivalHelper.placeBlock(world, player, pos, blockState, toPlace, facing, hitVec, false, false, true);
//Synergy
//Works without calling
// BlockSnapshot blockSnapshot = new BlockSnapshot(player.world, pos, blockState);
// BlockEvent.PlaceEvent placeEvent = new BlockEvent.PlaceEvent(blockSnapshot, blockState, player, hand);
// Mirror.onBlockPlaced(placeEvent);
// Array.onBlockPlaced(placeEvent);
}
return ActionResultType.SUCCESS;
}
@Override
public ActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
ItemStack bag = player.getItemInHand(hand);
if (player.isShiftKeyDown()) {
if (world.isClientSide) return new ActionResult<>(ActionResultType.SUCCESS, bag);
//Open inventory
NetworkHooks.openGui((ServerPlayerEntity) player, getContainerProvider(bag));
} else {
//Use item
//Get bag inventory
IItemHandler bagInventory = getBagInventory(bag);
if (bagInventory == null)
return new ActionResult<>(ActionResultType.FAIL, bag);
ItemStack toUse = pickRandomStack(bagInventory);
if (toUse.isEmpty()) return new ActionResult<>(ActionResultType.FAIL, bag);
return toUse.use(world, player, hand);
}
return new ActionResult<>(ActionResultType.PASS, bag);
}
@Override
public int getUseDuration(ItemStack p_77626_1_) {
return 1;
}
@Nullable
@Override
public ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundNBT nbt) {
return new ItemHandlerCapabilityProvider(getInventorySize());
}
@Override
public void appendHoverText(ItemStack stack, @Nullable World world, List<ITextComponent> tooltip, ITooltipFlag flag) {
tooltip.add(new StringTextComponent(TextFormatting.BLUE + "Rightclick" + TextFormatting.GRAY + " to place a random block"));
tooltip.add(new StringTextComponent(TextFormatting.BLUE + "Sneak + rightclick" + TextFormatting.GRAY + " to open inventory"));
if (world != null && world.players().size() > 1) {
tooltip.add(new StringTextComponent(TextFormatting.YELLOW + "Experimental on servers: may lose inventory"));
}
}
@Override
public String getDescriptionId() {
return this.getRegistryName().toString();
}
} }

View File

@@ -0,0 +1,67 @@
package nl.requios.effortlessbuilding.item;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
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.*;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import javax.annotation.Nullable;
import java.util.List;
public class ItemReachUpgrade1 extends Item {
public ItemReachUpgrade1() {
this.setRegistryName(EffortlessBuilding.MODID, "reach_upgrade1");
this.setTranslationKey(this.getRegistryName().toString());
this.maxStackSize = 1;
this.setCreativeTab(CreativeTabs.TOOLS);
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
if (player.isCreative()) {
if (world.isRemote) EffortlessBuilding.log(player, "Reach upgrades are not necessary in creative.");
if (world.isRemote) EffortlessBuilding.log(player, "Still want increased reach? Use the config.");
return new ActionResult<>(EnumActionResult.PASS, player.getHeldItem(hand));
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
int currentLevel = modifierSettings.getReachUpgrade();
if (currentLevel == 0) {
modifierSettings.setReachUpgrade(1);
if (world.isRemote) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player));
player.setHeldItem(hand, ItemStack.EMPTY);
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("entity.player.levelup"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel > 0) {
if (world.isRemote) EffortlessBuilding.log(player, "Already used this upgrade! Current reach is " + ReachHelper
.getMaxReach(player) + ".");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
}
return new ActionResult<>(EnumActionResult.PASS, player.getHeldItem(hand));
}
@Override
public void addInformation(ItemStack stack, @Nullable World world, List<String> tooltip, ITooltipFlag flag) {
tooltip.add(TextFormatting.GRAY + "Consume to increase reach to " + TextFormatting.BLUE + BuildConfig.reach.maxReachLevel1);
}
@Override
public String getTranslationKey() {
return super.getTranslationKey();
}
}

View File

@@ -0,0 +1,71 @@
package nl.requios.effortlessbuilding.item;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import javax.annotation.Nullable;
import java.util.List;
public class ItemReachUpgrade2 extends Item {
public ItemReachUpgrade2() {
this.setRegistryName(EffortlessBuilding.MODID, "reach_upgrade2");
this.setTranslationKey(this.getRegistryName().toString());
this.maxStackSize = 1;
this.setCreativeTab(CreativeTabs.TOOLS);
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
if (player.isCreative()) {
if (world.isRemote) EffortlessBuilding.log(player, "Reach upgrades are not necessary in creative.");
if (world.isRemote) EffortlessBuilding.log(player, "Still want increased reach? Use the config.");
return new ActionResult<>(EnumActionResult.PASS, player.getHeldItem(hand));
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
int currentLevel = modifierSettings.getReachUpgrade();
if (currentLevel == 1) {
modifierSettings.setReachUpgrade(2);
if (world.isRemote) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player));
player.setHeldItem(hand, ItemStack.EMPTY);
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("entity.player.levelup"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel < 1) {
if (world.isRemote) EffortlessBuilding.log(player, "Use Reach Upgrade 1 first.");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel > 1) {
if (world.isRemote) EffortlessBuilding.log(player, "Already used this upgrade! Current reach is " + ReachHelper
.getMaxReach(player) + ".");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
}
return new ActionResult<>(EnumActionResult.PASS, player.getHeldItem(hand));
}
@Override
public void addInformation(ItemStack stack, @Nullable World world, List<String> tooltip, ITooltipFlag flag) {
tooltip.add(TextFormatting.GRAY + "Consume to increase reach to " + TextFormatting.BLUE + BuildConfig.reach.maxReachLevel2);
tooltip.add(TextFormatting.GRAY + "Previous upgrades need to be consumed first");
}
@Override
public String getTranslationKey() {
return super.getTranslationKey();
}
}

View File

@@ -0,0 +1,74 @@
package nl.requios.effortlessbuilding.item;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import javax.annotation.Nullable;
import java.util.List;
public class ItemReachUpgrade3 extends Item {
public ItemReachUpgrade3() {
this.setRegistryName(EffortlessBuilding.MODID, "reach_upgrade3");
this.setTranslationKey(this.getRegistryName().toString());
this.maxStackSize = 1;
this.setCreativeTab(CreativeTabs.TOOLS);
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
if (player.isCreative()) {
if (world.isRemote) EffortlessBuilding.log(player, "Reach upgrades are not necessary in creative.");
if (world.isRemote) EffortlessBuilding.log(player, "Still want increased reach? Use the config.");
return new ActionResult<>(EnumActionResult.PASS, player.getHeldItem(hand));
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
int currentLevel = modifierSettings.getReachUpgrade();
if (currentLevel == 2) {
modifierSettings.setReachUpgrade(3);
if (world.isRemote) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player));
player.setHeldItem(hand, ItemStack.EMPTY);
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("entity.player.levelup"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel < 2) {
if (currentLevel == 0)
if (world.isRemote) EffortlessBuilding.log(player, "Use Reach Upgrade 1 and 2 first.");
if (currentLevel == 1)
if (world.isRemote) EffortlessBuilding.log(player, "Use Reach Upgrade 2 first.");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel > 2) {
if (world.isRemote) EffortlessBuilding.log(player, "Already used this upgrade! Current reach is " + ReachHelper
.getMaxReach(player) + ".");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
}
return new ActionResult<>(EnumActionResult.PASS, player.getHeldItem(hand));
}
@Override
public void addInformation(ItemStack stack, @Nullable World world, List<String> tooltip, ITooltipFlag flag) {
tooltip.add(TextFormatting.GRAY + "Consume to increase reach to " + TextFormatting.BLUE + BuildConfig.reach.maxReachLevel3);
tooltip.add(TextFormatting.GRAY + "Previous upgrades need to be consumed first");
}
@Override
public String getTranslationKey() {
return super.getTranslationKey();
}
}

View File

@@ -1,46 +0,0 @@
package nl.requios.effortlessbuilding.item;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import nl.requios.effortlessbuilding.gui.RandomizerBagContainer;
import javax.annotation.Nullable;
public class RandomizerBagItem extends AbstractRandomizerBagItem{
public static final int INV_SIZE = 5;
@Override
public int getInventorySize() {
return 5;
}
@Override
public INamedContainerProvider getContainerProvider(ItemStack bag) {
return new ContainerProvider(bag);
}
public static class ContainerProvider implements INamedContainerProvider {
private final ItemStack bag;
public ContainerProvider(ItemStack bag) {
this.bag = bag;
}
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("effortlessbuilding:randomizer_bag");
}
@Nullable
@Override
public Container createMenu(int containerId, PlayerInventory playerInventory, PlayerEntity player) {
return new RandomizerBagContainer(containerId, playerInventory, ((AbstractRandomizerBagItem)bag.getItem()).getBagInventory(bag));
}
}
}

View File

@@ -1,69 +0,0 @@
package nl.requios.effortlessbuilding.item;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class ReachUpgrade1Item extends Item {
public ReachUpgrade1Item() {
super(new Item.Properties().tab(ItemGroup.TAB_TOOLS).stacksTo(1));
}
@Override
public ActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
if (player.isCreative()) {
if (world.isClientSide) EffortlessBuilding.log(player, "Reach upgrades are not necessary in creative.");
if (world.isClientSide) EffortlessBuilding.log(player, "Still want increased reach? Use the config.");
return new ActionResult<>(ActionResultType.PASS, player.getItemInHand(hand));
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
int currentLevel = modifierSettings.getReachUpgrade();
if (currentLevel == 0) {
modifierSettings.setReachUpgrade(1);
if (world.isClientSide) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player));
player.setItemInHand(hand, ItemStack.EMPTY);
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("entity.player.levelup"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel > 0) {
if (world.isClientSide)
EffortlessBuilding.log(player, "Already used this upgrade! Current reach is " + ReachHelper
.getMaxReach(player) + ".");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
}
return new ActionResult<>(ActionResultType.PASS, player.getItemInHand(hand));
}
@Override
public void appendHoverText(ItemStack stack, @Nullable World world, List<ITextComponent> tooltip, ITooltipFlag flag) {
tooltip.add(new StringTextComponent(TextFormatting.GRAY + "Consume to increase reach to " + TextFormatting.BLUE + BuildConfig.reach.maxReachLevel1.get()));
}
@Override
public String getDescriptionId() {
return this.getRegistryName().toString();
}
}

View File

@@ -1,74 +0,0 @@
package nl.requios.effortlessbuilding.item;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class ReachUpgrade2Item extends Item {
public ReachUpgrade2Item() {
super(new Item.Properties().tab(ItemGroup.TAB_TOOLS).stacksTo(1));
}
@Override
public ActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
if (player.isCreative()) {
if (world.isClientSide) EffortlessBuilding.log(player, "Reach upgrades are not necessary in creative.");
if (world.isClientSide) EffortlessBuilding.log(player, "Still want increased reach? Use the config.");
return new ActionResult<>(ActionResultType.PASS, player.getItemInHand(hand));
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
int currentLevel = modifierSettings.getReachUpgrade();
if (currentLevel == 1) {
modifierSettings.setReachUpgrade(2);
if (world.isClientSide) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player));
player.setItemInHand(hand, ItemStack.EMPTY);
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("entity.player.levelup"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel < 1) {
if (world.isClientSide) EffortlessBuilding.log(player, "Use Reach Upgrade 1 first.");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel > 1) {
if (world.isClientSide)
EffortlessBuilding.log(player, "Already used this upgrade! Current reach is " + ReachHelper
.getMaxReach(player) + ".");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
}
return new ActionResult<>(ActionResultType.PASS, player.getItemInHand(hand));
}
@Override
public void appendHoverText(ItemStack stack, @Nullable World world, List<ITextComponent> tooltip, ITooltipFlag flag) {
tooltip.add(new StringTextComponent(TextFormatting.GRAY + "Consume to increase reach to " + TextFormatting.BLUE + BuildConfig.reach.maxReachLevel2.get()));
tooltip.add(new StringTextComponent(TextFormatting.GRAY + "Previous upgrades need to be consumed first"));
}
@Override
public String getDescriptionId() {
return this.getRegistryName().toString();
}
}

View File

@@ -1,77 +0,0 @@
package nl.requios.effortlessbuilding.item;
import mcp.MethodsReturnNonnullByDefault;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.helper.ReachHelper;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class ReachUpgrade3Item extends Item {
public ReachUpgrade3Item() {
super(new Item.Properties().tab(ItemGroup.TAB_TOOLS).stacksTo(1));
}
@Override
public ActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
if (player.isCreative()) {
if (world.isClientSide) EffortlessBuilding.log(player, "Reach upgrades are not necessary in creative.");
if (world.isClientSide) EffortlessBuilding.log(player, "Still want increased reach? Use the config.");
return new ActionResult<>(ActionResultType.PASS, player.getItemInHand(hand));
}
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
int currentLevel = modifierSettings.getReachUpgrade();
if (currentLevel == 2) {
modifierSettings.setReachUpgrade(3);
if (world.isClientSide) EffortlessBuilding.log(player, "Upgraded reach to " + ReachHelper.getMaxReach(player));
player.setItemInHand(hand, ItemStack.EMPTY);
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("entity.player.levelup"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel < 2) {
if (currentLevel == 0)
if (world.isClientSide) EffortlessBuilding.log(player, "Use Reach Upgrade 1 and 2 first.");
if (currentLevel == 1)
if (world.isClientSide) EffortlessBuilding.log(player, "Use Reach Upgrade 2 first.");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
} else if (currentLevel > 2) {
if (world.isClientSide)
EffortlessBuilding.log(player, "Already used this upgrade! Current reach is " + ReachHelper
.getMaxReach(player) + ".");
SoundEvent soundEvent = new SoundEvent(new ResourceLocation("item.armor.equip_leather"));
player.playSound(soundEvent, 1f, 1f);
}
return new ActionResult<>(ActionResultType.PASS, player.getItemInHand(hand));
}
@Override
public void appendHoverText(ItemStack stack, @Nullable World world, List<ITextComponent> tooltip, ITooltipFlag flag) {
tooltip.add(new StringTextComponent(TextFormatting.GRAY + "Consume to increase reach to " + TextFormatting.BLUE + BuildConfig.reach.maxReachLevel3.get()));
tooltip.add(new StringTextComponent(TextFormatting.GRAY + "Previous upgrades need to be consumed first"));
}
@Override
public String getDescriptionId() {
return this.getRegistryName().toString();
}
}

View File

@@ -1,91 +1,94 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.BlockSet; import nl.requios.effortlessbuilding.buildmodifier.BlockSet;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.function.Supplier;
/*** /***
* Sends a message to the client asking to add a block to the undo stack. * Sends a message to the client asking to add a block to the undo stack.
*/ */
public class AddUndoMessage { public class AddUndoMessage implements IMessage {
private final BlockPos coordinate; private BlockPos coordinate;
private final BlockState previousBlockState; private IBlockState previousBlockState;
private final BlockState newBlockState; private IBlockState newBlockState;
public AddUndoMessage() { public AddUndoMessage() {
coordinate = BlockPos.ZERO; coordinate = BlockPos.ORIGIN;
previousBlockState = null; previousBlockState = null;
newBlockState = null; newBlockState = null;
} }
public AddUndoMessage(BlockPos coordinate, BlockState previousBlockState, BlockState newBlockState) { public AddUndoMessage(BlockPos coordinate, IBlockState previousBlockState, IBlockState newBlockState) {
this.coordinate = coordinate; this.coordinate = coordinate;
this.previousBlockState = previousBlockState; this.previousBlockState = previousBlockState;
this.newBlockState = newBlockState; this.newBlockState = newBlockState;
} }
public static void encode(AddUndoMessage message, PacketBuffer buf) { public BlockPos getCoordinate() {
buf.writeInt(message.coordinate.getX()); return coordinate;
buf.writeInt(message.coordinate.getY()); }
buf.writeInt(message.coordinate.getZ());
buf.writeInt(Block.getId(message.previousBlockState));
buf.writeInt(Block.getId(message.newBlockState));
}
public static AddUndoMessage decode(PacketBuffer buf) { public IBlockState getPreviousBlockState() {
BlockPos coordinate = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt()); return previousBlockState;
BlockState previousBlockState = Block.stateById(buf.readInt()); }
BlockState newBlockState = Block.stateById(buf.readInt());
return new AddUndoMessage(coordinate, previousBlockState, newBlockState);
}
public BlockPos getCoordinate() { public IBlockState getNewBlockState() {
return coordinate; return newBlockState;
} }
public BlockState getPreviousBlockState() { @Override
return previousBlockState; public void toBytes(ByteBuf buf) {
} buf.writeInt(this.coordinate.getX());
buf.writeInt(this.coordinate.getY());
buf.writeInt(this.coordinate.getZ());
buf.writeInt(Block.getStateId(this.previousBlockState));
buf.writeInt(Block.getStateId(this.newBlockState));
}
public BlockState getNewBlockState() { @Override
return newBlockState; public void fromBytes(ByteBuf buf) {
} coordinate = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
previousBlockState = Block.getStateById(buf.readInt());
newBlockState = Block.getStateById(buf.readInt());
}
public static class Handler { // The params of the IMessageHandler are <REQ, REPLY>
public static void handle(AddUndoMessage message, Supplier<NetworkEvent.Context> ctx) { public static class MessageHandler implements IMessageHandler<AddUndoMessage, IMessage> {
ctx.get().enqueueWork(() -> { // Do note that the default constructor is required, but implicitly defined in this case
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) {
//Received clientside
PlayerEntity player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx); @Override
//Add to undo stack clientside public IMessage onMessage(AddUndoMessage message, MessageContext ctx) {
//Only the appropriate player that needs to add this to the undo stack gets this message //EffortlessBuilding.log("message received on " + ctx.side + " side");
UndoRedo.addUndo(player, new BlockSet(
new ArrayList<BlockPos>() {{ if (ctx.side == Side.CLIENT){
add(message.getCoordinate()); //Received clientside
}},
new ArrayList<BlockState>() {{ EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
add(message.getPreviousBlockState()); EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
}},
new ArrayList<BlockState>() {{ //Add to undo stack clientside
add(message.getNewBlockState()); UndoRedo.addUndo(player, new BlockSet(
}}, new ArrayList<BlockPos>() {{add(message.getCoordinate());}},
new Vector3d(0, 0, 0), new ArrayList<IBlockState>() {{add(message.getPreviousBlockState());}},
message.getCoordinate(), message.getCoordinate())); new ArrayList<IBlockState>() {{add(message.getNewBlockState());}},
} new Vec3d(0,0,0),
}); message.getCoordinate(), message.getCoordinate()));
ctx.get().setPacketHandled(true); });
} }
} return null;
}
}
} }

View File

@@ -1,92 +1,95 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import net.minecraft.network.PacketBuffer; import io.netty.buffer.ByteBuf;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import java.util.function.Supplier;
/*** /***
* Sends a message to the server indicating that a player wants to break a block * Sends a message to the server indicating that a player wants to break a block
*/ */
public class BlockBrokenMessage { public class BlockBrokenMessage implements IMessage {
private final boolean blockHit; private boolean blockHit;
private final BlockPos blockPos; private BlockPos blockPos;
private final Direction sideHit; private EnumFacing sideHit;
private final Vector3d hitVec; private Vec3d hitVec;
public BlockBrokenMessage() { public BlockBrokenMessage() {
this.blockHit = false; this.blockHit = false;
this.blockPos = BlockPos.ZERO; this.blockPos = BlockPos.ORIGIN;
this.sideHit = Direction.UP; this.sideHit = EnumFacing.UP;
this.hitVec = new Vector3d(0, 0, 0); this.hitVec = new Vec3d(0, 0, 0);
} }
public BlockBrokenMessage(BlockRayTraceResult result) { public BlockBrokenMessage(RayTraceResult result) {
this.blockHit = result.getType() == RayTraceResult.Type.BLOCK; this.blockHit = result.typeOfHit == RayTraceResult.Type.BLOCK;
this.blockPos = result.getBlockPos(); this.blockPos = result.getBlockPos();
this.sideHit = result.getDirection(); this.sideHit = result.sideHit;
this.hitVec = result.getLocation(); this.hitVec = result.hitVec;
} }
public BlockBrokenMessage(boolean blockHit, BlockPos blockPos, Direction sideHit, Vector3d hitVec) { public boolean isBlockHit() {
this.blockHit = blockHit; return blockHit;
this.blockPos = blockPos; }
this.sideHit = sideHit;
this.hitVec = hitVec;
}
public static void encode(BlockBrokenMessage message, PacketBuffer buf) { public BlockPos getBlockPos() {
buf.writeBoolean(message.blockHit); return blockPos;
buf.writeInt(message.blockPos.getX()); }
buf.writeInt(message.blockPos.getY());
buf.writeInt(message.blockPos.getZ());
buf.writeInt(message.sideHit.get3DDataValue());
buf.writeDouble(message.hitVec.x);
buf.writeDouble(message.hitVec.y);
buf.writeDouble(message.hitVec.z);
}
public static BlockBrokenMessage decode(PacketBuffer buf) { public EnumFacing getSideHit() {
boolean blockHit = buf.readBoolean(); return sideHit;
BlockPos blockPos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt()); }
Direction sideHit = Direction.from3DDataValue(buf.readInt());
Vector3d hitVec = new Vector3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
return new BlockBrokenMessage(blockHit, blockPos, sideHit, hitVec);
}
public boolean isBlockHit() { public Vec3d getHitVec() {
return blockHit; return hitVec;
} }
public BlockPos getBlockPos() { @Override
return blockPos; public void toBytes(ByteBuf buf) {
} buf.writeBoolean(blockHit);
buf.writeInt(blockPos.getX());
buf.writeInt(blockPos.getY());
buf.writeInt(blockPos.getZ());
buf.writeInt(sideHit.getIndex());
buf.writeDouble(hitVec.x);
buf.writeDouble(hitVec.y);
buf.writeDouble(hitVec.z);
}
public Direction getSideHit() { @Override
return sideHit; public void fromBytes(ByteBuf buf) {
} blockHit = buf.readBoolean();
blockPos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
sideHit = EnumFacing.byIndex(buf.readInt());
hitVec = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
}
public Vector3d getHitVec() { // The params of the IMessageHandler are <REQ, REPLY>
return hitVec; public static class MessageHandler implements IMessageHandler<BlockBrokenMessage, IMessage> {
} // Do note that the default constructor is required, but implicitly defined in this case
@Override
public IMessage onMessage(BlockBrokenMessage message, MessageContext ctx) {
//EffortlessBuilding.log("message received on " + ctx.side + " side");
if (ctx.side == Side.SERVER) {
//Received serverside
EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
BuildModes.onBlockBrokenMessage(ctx.getServerHandler().player, message);
});
}
// No response packet
return null;
}
}
public static class Handler {
public static void handle(BlockBrokenMessage message, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> {
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.SERVER) {
//Received serverside
BuildModes.onBlockBrokenMessage(ctx.get().getSender(), message);
}
});
ctx.get().setPacketHandled(true);
}
}
} }

View File

@@ -1,108 +1,113 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import net.minecraft.network.PacketBuffer; import io.netty.buffer.ByteBuf;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.LogicalSide; import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import nl.requios.effortlessbuilding.render.BlockPreviewRenderer; import nl.requios.effortlessbuilding.render.BlockPreviewRenderer;
import java.util.function.Supplier;
/*** /***
* Sends a message to the server indicating that a player wants to place a block. * Sends a message to the server indicating that a player wants to place a block.
* Received clientside: server has placed blocks and its letting the client know. * Received clientside: server has placed blocks and its letting the client know.
*/ */
public class BlockPlacedMessage { public class BlockPlacedMessage implements IMessage {
private final boolean blockHit; private boolean blockHit;
private final BlockPos blockPos; private BlockPos blockPos;
private final Direction sideHit; private EnumFacing sideHit;
private final Vector3d hitVec; private Vec3d hitVec;
private final boolean placeStartPos; //prevent double placing in normal mode private boolean placeStartPos; //prevent double placing in normal mode
public BlockPlacedMessage() { public BlockPlacedMessage() {
this.blockHit = false; this.blockHit = false;
this.blockPos = BlockPos.ZERO; this.blockPos = BlockPos.ORIGIN;
this.sideHit = Direction.UP; this.sideHit = EnumFacing.UP;
this.hitVec = new Vector3d(0, 0, 0); this.hitVec = new Vec3d(0, 0, 0);
this.placeStartPos = true; this.placeStartPos = true;
} }
public BlockPlacedMessage(BlockRayTraceResult result, boolean placeStartPos) { public BlockPlacedMessage(RayTraceResult result, boolean placeStartPos) {
this.blockHit = result.getType() == RayTraceResult.Type.BLOCK; this.blockHit = result.typeOfHit == RayTraceResult.Type.BLOCK;
this.blockPos = result.getBlockPos(); this.blockPos = result.getBlockPos();
this.sideHit = result.getDirection(); this.sideHit = result.sideHit;
this.hitVec = result.getLocation(); this.hitVec = result.hitVec;
this.placeStartPos = placeStartPos; this.placeStartPos = placeStartPos;
} }
public BlockPlacedMessage(boolean blockHit, BlockPos blockPos, Direction sideHit, Vector3d hitVec, boolean placeStartPos) { public boolean isBlockHit() {
this.blockHit = blockHit; return blockHit;
this.blockPos = blockPos; }
this.sideHit = sideHit;
this.hitVec = hitVec;
this.placeStartPos = placeStartPos;
}
public static void encode(BlockPlacedMessage message, PacketBuffer buf) { public BlockPos getBlockPos() {
buf.writeBoolean(message.blockHit); return blockPos;
buf.writeInt(message.blockPos.getX()); }
buf.writeInt(message.blockPos.getY());
buf.writeInt(message.blockPos.getZ());
buf.writeInt(message.sideHit.get3DDataValue());
buf.writeDouble(message.hitVec.x);
buf.writeDouble(message.hitVec.y);
buf.writeDouble(message.hitVec.z);
buf.writeBoolean(message.placeStartPos);
}
public static BlockPlacedMessage decode(PacketBuffer buf) { public EnumFacing getSideHit() {
boolean blockHit = buf.readBoolean(); return sideHit;
BlockPos blockPos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt()); }
Direction sideHit = Direction.from3DDataValue(buf.readInt());
Vector3d hitVec = new Vector3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
boolean placeStartPos = buf.readBoolean();
return new BlockPlacedMessage(blockHit, blockPos, sideHit, hitVec, placeStartPos);
}
public boolean isBlockHit() { public Vec3d getHitVec() {
return blockHit; return hitVec;
} }
public BlockPos getBlockPos() { public boolean getPlaceStartPos() {
return blockPos; return placeStartPos;
} }
public Direction getSideHit() { @Override
return sideHit; public void toBytes(ByteBuf buf) {
} buf.writeBoolean(blockHit);
buf.writeInt(blockPos.getX());
buf.writeInt(blockPos.getY());
buf.writeInt(blockPos.getZ());
buf.writeInt(sideHit.getIndex());
buf.writeDouble(hitVec.x);
buf.writeDouble(hitVec.y);
buf.writeDouble(hitVec.z);
buf.writeBoolean(placeStartPos);
}
public Vector3d getHitVec() { @Override
return hitVec; public void fromBytes(ByteBuf buf) {
} blockHit = buf.readBoolean();
blockPos = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
sideHit = EnumFacing.byIndex(buf.readInt());
hitVec = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
placeStartPos = buf.readBoolean();
}
public boolean getPlaceStartPos() { // The params of the IMessageHandler are <REQ, REPLY>
return placeStartPos; public static class MessageHandler implements IMessageHandler<BlockPlacedMessage, IMessage> {
} // Do note that the default constructor is required, but implicitly defined in this case
public static class Handler { @Override
public static void handle(BlockPlacedMessage message, Supplier<NetworkEvent.Context> ctx) { public IMessage onMessage(BlockPlacedMessage message, MessageContext ctx) {
ctx.get().enqueueWork(() -> { //EffortlessBuilding.log("message received on " + ctx.side + " side");
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) {
//Received clientside if (ctx.side == Side.CLIENT){
//Nod RenderHandler to do the dissolve shader effect //Received clientside
BlockPreviewRenderer.onBlocksPlaced(); EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
} else { //Nod RenderHandler to do the dissolve shader effect
//Received serverside BlockPreviewRenderer.onBlocksPlaced();
BuildModes.onBlockPlacedMessage(ctx.get().getSender(), message); });
} return null;
}); } else {
ctx.get().setPacketHandled(true); //Received serverside
} EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
} BuildModes.onBlockPlacedMessage(ctx.getServerHandler().player, message);
});
// No response packet
return null;
}
}
}
} }

View File

@@ -1,33 +1,45 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import net.minecraft.entity.player.PlayerEntity; import io.netty.buffer.ByteBuf;
import net.minecraft.network.PacketBuffer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import java.util.function.Supplier;
/** /**
* Sends a message to the server indicating that a buildmode needs to be canceled for a player * Sends a message to the server indicating that a buildmode needs to be canceled for a player
*/ */
public class CancelModeMessage { public class CancelModeMessage implements IMessage {
public static void encode(CancelModeMessage message, PacketBuffer buf) { @Override
} public void toBytes(ByteBuf buf) {
public static CancelModeMessage decode(PacketBuffer buf) { }
return new CancelModeMessage();
}
public static class Handler { @Override
public static void handle(CancelModeMessage message, Supplier<NetworkEvent.Context> ctx) { public void fromBytes(ByteBuf buf) {
ctx.get().enqueueWork(() -> {
PlayerEntity player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
BuildModes.initializeMode(player); }
});
ctx.get().setPacketHandled(true); // The params of the IMessageHandler are <REQ, REPLY>
} public static class MessageHandler implements IMessageHandler<CancelModeMessage, IMessage> {
} // Do note that the default constructor is required, but implicitly defined in this case
@Override
public IMessage onMessage(CancelModeMessage message, MessageContext ctx) {
// Execute the action on the main server thread by adding it as a scheduled task
IThreadListener threadListener = EffortlessBuilding.proxy.getThreadListenerFromContext(ctx);
threadListener.addScheduledTask(() -> {
EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
BuildModes.initializeMode(player);
});
// No response packet
return null;
}
}
} }

View File

@@ -1,42 +1,57 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import net.minecraft.entity.player.PlayerEntity; import io.netty.buffer.ByteBuf;
import net.minecraft.network.PacketBuffer; import net.minecraft.block.Block;
import net.minecraftforge.fml.LogicalSide; import net.minecraft.block.state.IBlockState;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.BlockSet;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo; import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.proxy.ClientProxy;
import java.util.function.Supplier; import java.util.ArrayList;
/*** /***
* Sends a message to the client asking to clear the undo and redo stacks. * Sends a message to the client asking to clear the undo and redo stacks.
*/ */
public class ClearUndoMessage { public class ClearUndoMessage implements IMessage {
public ClearUndoMessage() { public ClearUndoMessage() {
} }
public static void encode(ClearUndoMessage message, PacketBuffer buf) { @Override
public void toBytes(ByteBuf buf) {
}
} @Override
public void fromBytes(ByteBuf buf) {
}
public static ClearUndoMessage decode(PacketBuffer buf) { // The params of the IMessageHandler are <REQ, REPLY>
return new ClearUndoMessage(); public static class MessageHandler implements IMessageHandler<ClearUndoMessage, IMessage> {
} // Do note that the default constructor is required, but implicitly defined in this case
public static class Handler { @Override
public static void handle(ClearUndoMessage message, Supplier<NetworkEvent.Context> ctx) { public IMessage onMessage(ClearUndoMessage message, MessageContext ctx) {
ctx.get().enqueueWork(() -> { //EffortlessBuilding.log("message received on " + ctx.side + " side");
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) {
//Received clientside
PlayerEntity player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
//Add to undo stack clientside if (ctx.side == Side.CLIENT){
UndoRedo.clear(player); //Received clientside
}
}); EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
ctx.get().setPacketHandled(true); EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
}
} //Add to undo stack clientside
UndoRedo.clear(player);
});
}
return null;
}
}
} }

View File

@@ -1,44 +1,62 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import net.minecraft.entity.player.PlayerEntity; import io.netty.buffer.ByteBuf;
import net.minecraft.network.PacketBuffer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import java.util.function.Supplier; import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.*;
/** /**
* Shares mode settings (see ModeSettingsManager) between server and client * Shares mode settings (see ModeSettingsManager) between server and client
*/ */
public class ModeActionMessage { public class ModeActionMessage implements IMessage {
private ModeOptions.ActionEnum action; private ModeOptions.ActionEnum action;
public ModeActionMessage() { public ModeActionMessage() {
} }
public ModeActionMessage(ModeOptions.ActionEnum action) { public ModeActionMessage(ModeOptions.ActionEnum action) {
this.action = action; this.action = action;
} }
public static void encode(ModeActionMessage message, PacketBuffer buf) { @Override
buf.writeInt(message.action.ordinal()); public void toBytes(ByteBuf buf) {
} buf.writeInt(action.ordinal());
}
public static ModeActionMessage decode(PacketBuffer buf) { @Override
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.values()[buf.readInt()]; public void fromBytes(ByteBuf buf) {
return new ModeActionMessage(action); action = ModeOptions.ActionEnum.values()[buf.readInt()];
} }
public static class Handler { // The params of the IMessageHandler are <REQ, REPLY>
public static void handle(ModeActionMessage message, Supplier<NetworkEvent.Context> ctx) { public static class MessageHandler implements IMessageHandler<ModeActionMessage, IMessage> {
ctx.get().enqueueWork(() -> { // Do note that the default constructor is required, but implicitly defined in this case
PlayerEntity player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
ModeOptions.performAction(player, message.action); @Override
}); public IMessage onMessage(ModeActionMessage message, MessageContext ctx) {
ctx.get().setPacketHandled(true); //EffortlessBuilding.log("message received on " + ctx.side + " side");
}
} // The value that was sent
ModeOptions.ActionEnum action = message.action;
// Execute the action on the main server thread by adding it as a scheduled task
IThreadListener threadListener = EffortlessBuilding.proxy.getThreadListenerFromContext(ctx);
threadListener.addScheduledTask(() -> {
EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
ModeOptions.performAction(player, action);
});
// No response packet
return null;
}
}
} }

View File

@@ -1,50 +1,66 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import net.minecraft.entity.player.PlayerEntity; import io.netty.buffer.ByteBuf;
import net.minecraft.network.PacketBuffer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.ModeSettings;
import java.util.function.Supplier; import static nl.requios.effortlessbuilding.buildmode.ModeSettingsManager.*;
/** /**
* Shares mode settings (see ModeSettingsManager) between server and client * Shares mode settings (see ModeSettingsManager) between server and client
*/ */
public class ModeSettingsMessage { public class ModeSettingsMessage implements IMessage {
private ModeSettings modeSettings; private ModeSettings modeSettings;
public ModeSettingsMessage() { public ModeSettingsMessage() {
} }
public ModeSettingsMessage(ModeSettings modeSettings) { public ModeSettingsMessage(ModeSettings modeSettings) {
this.modeSettings = modeSettings; this.modeSettings = modeSettings;
} }
public static void encode(ModeSettingsMessage message, PacketBuffer buf) { @Override
buf.writeInt(message.modeSettings.getBuildMode().ordinal()); public void toBytes(ByteBuf buf) {
} buf.writeInt(modeSettings.getBuildMode().ordinal());
}
public static ModeSettingsMessage decode(PacketBuffer buf) { @Override
BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.values()[buf.readInt()]; public void fromBytes(ByteBuf buf) {
BuildModes.BuildModeEnum buildMode = BuildModes.BuildModeEnum.values()[buf.readInt()];
return new ModeSettingsMessage(new ModeSettings(buildMode)); modeSettings = new ModeSettings(buildMode);
} }
public static class Handler { // The params of the IMessageHandler are <REQ, REPLY>
public static void handle(ModeSettingsMessage message, Supplier<NetworkEvent.Context> ctx) { public static class MessageHandler implements IMessageHandler<ModeSettingsMessage, IMessage> {
ctx.get().enqueueWork(() -> { // Do note that the default constructor is required, but implicitly defined in this case
PlayerEntity player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
// Sanitize @Override
ModeSettingsManager.sanitize(message.modeSettings, player); public IMessage onMessage(ModeSettingsMessage message, MessageContext ctx) {
//EffortlessBuilding.log("message received on " + ctx.side + " side");
ModeSettingsManager.setModeSettings(player, message.modeSettings); // The value that was sent
}); ModeSettings modeSettings = message.modeSettings;
ctx.get().setPacketHandled(true);
} // Execute the action on the main server thread by adding it as a scheduled task
} IThreadListener threadListener = EffortlessBuilding.proxy.getThreadListenerFromContext(ctx);
threadListener.addScheduledTask(() -> {
EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
// Sanitize
ModeSettingsManager.sanitize(modeSettings, player);
ModeSettingsManager.setModeSettings(player, modeSettings);
});
// No response packet
return null;
}
}
} }

View File

@@ -1,142 +1,154 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import net.minecraft.entity.player.PlayerEntity; import io.netty.buffer.ByteBuf;
import net.minecraft.network.PacketBuffer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.Array; import nl.requios.effortlessbuilding.buildmodifier.Array;
import nl.requios.effortlessbuilding.buildmodifier.Mirror; import nl.requios.effortlessbuilding.buildmodifier.Mirror;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; import nl.requios.effortlessbuilding.buildmodifier.RadialMirror;
import java.util.function.Supplier; import static nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.*;
import static nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
/** /**
* Shares modifier settings (see ModifierSettingsManager) between server and client * Shares modifier settings (see ModifierSettingsManager) between server and client
*/ */
public class ModifierSettingsMessage { public class ModifierSettingsMessage implements IMessage {
private ModifierSettings modifierSettings; private ModifierSettings modifierSettings;
public ModifierSettingsMessage() { public ModifierSettingsMessage() {
} }
public ModifierSettingsMessage(ModifierSettings modifierSettings) { public ModifierSettingsMessage(ModifierSettings modifierSettings) {
this.modifierSettings = modifierSettings; this.modifierSettings = modifierSettings;
} }
public static void encode(ModifierSettingsMessage message, PacketBuffer buf) { @Override
//MIRROR public void toBytes(ByteBuf buf) {
Mirror.MirrorSettings m = message.modifierSettings.getMirrorSettings(); //MIRROR
buf.writeBoolean(m != null); Mirror.MirrorSettings m = modifierSettings.getMirrorSettings();
if (m != null) { buf.writeBoolean(m != null);
buf.writeBoolean(m.enabled); if (m != null) {
buf.writeDouble(m.position.x); buf.writeBoolean(m.enabled);
buf.writeDouble(m.position.y); buf.writeDouble(m.position.x);
buf.writeDouble(m.position.z); buf.writeDouble(m.position.y);
buf.writeBoolean(m.mirrorX); buf.writeDouble(m.position.z);
buf.writeBoolean(m.mirrorY); buf.writeBoolean(m.mirrorX);
buf.writeBoolean(m.mirrorZ); buf.writeBoolean(m.mirrorY);
buf.writeInt(m.radius); buf.writeBoolean(m.mirrorZ);
buf.writeBoolean(m.drawLines); buf.writeInt(m.radius);
buf.writeBoolean(m.drawPlanes); buf.writeBoolean(m.drawLines);
} buf.writeBoolean(m.drawPlanes);
}
//ARRAY //ARRAY
Array.ArraySettings a = message.modifierSettings.getArraySettings(); Array.ArraySettings a = modifierSettings.getArraySettings();
buf.writeBoolean(a != null); buf.writeBoolean(a != null);
if (a != null) { if (a != null) {
buf.writeBoolean(a.enabled); buf.writeBoolean(a.enabled);
buf.writeInt(a.offset.getX()); buf.writeInt(a.offset.getX());
buf.writeInt(a.offset.getY()); buf.writeInt(a.offset.getY());
buf.writeInt(a.offset.getZ()); buf.writeInt(a.offset.getZ());
buf.writeInt(a.count); buf.writeInt(a.count);
} }
buf.writeBoolean(message.modifierSettings.doQuickReplace()); buf.writeBoolean(modifierSettings.doQuickReplace());
buf.writeInt(message.modifierSettings.getReachUpgrade()); buf.writeInt(modifierSettings.getReachUpgrade());
//RADIAL MIRROR //RADIAL MIRROR
RadialMirror.RadialMirrorSettings r = message.modifierSettings.getRadialMirrorSettings(); RadialMirror.RadialMirrorSettings r = modifierSettings.getRadialMirrorSettings();
buf.writeBoolean(r != null); buf.writeBoolean(r != null);
if (r != null) { if (r != null) {
buf.writeBoolean(r.enabled); buf.writeBoolean(r.enabled);
buf.writeDouble(r.position.x); buf.writeDouble(r.position.x);
buf.writeDouble(r.position.y); buf.writeDouble(r.position.y);
buf.writeDouble(r.position.z); buf.writeDouble(r.position.z);
buf.writeInt(r.slices); buf.writeInt(r.slices);
buf.writeBoolean(r.alternate); buf.writeBoolean(r.alternate);
buf.writeInt(r.radius); buf.writeInt(r.radius);
buf.writeBoolean(r.drawLines); buf.writeBoolean(r.drawLines);
buf.writeBoolean(r.drawPlanes); buf.writeBoolean(r.drawPlanes);
} }
} }
public static ModifierSettingsMessage decode(PacketBuffer buf) { @Override
//MIRROR public void fromBytes(ByteBuf buf) {
Mirror.MirrorSettings m = new Mirror.MirrorSettings(); //MIRROR
if (buf.readBoolean()) { Mirror.MirrorSettings m = new Mirror.MirrorSettings();
boolean mirrorEnabled = buf.readBoolean(); if (buf.readBoolean()) {
Vector3d mirrorPosition = new Vector3d(buf.readDouble(), buf.readDouble(), buf.readDouble()); boolean mirrorEnabled = buf.readBoolean();
boolean mirrorX = buf.readBoolean(); Vec3d mirrorPosition = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
boolean mirrorY = buf.readBoolean(); boolean mirrorX = buf.readBoolean();
boolean mirrorZ = buf.readBoolean(); boolean mirrorY = buf.readBoolean();
int mirrorRadius = buf.readInt(); boolean mirrorZ = buf.readBoolean();
boolean mirrorDrawLines = buf.readBoolean(); int mirrorRadius = buf.readInt();
boolean mirrorDrawPlanes = buf.readBoolean(); boolean mirrorDrawLines = buf.readBoolean();
m = new Mirror.MirrorSettings(mirrorEnabled, mirrorPosition, mirrorX, mirrorY, mirrorZ, mirrorRadius, boolean mirrorDrawPlanes = buf.readBoolean();
mirrorDrawLines, mirrorDrawPlanes); m = new Mirror.MirrorSettings(mirrorEnabled, mirrorPosition, mirrorX, mirrorY, mirrorZ, mirrorRadius,
} mirrorDrawLines, mirrorDrawPlanes);
}
//ARRAY //ARRAY
Array.ArraySettings a = new Array.ArraySettings(); Array.ArraySettings a = new Array.ArraySettings();
if (buf.readBoolean()) { if (buf.readBoolean()) {
boolean arrayEnabled = buf.readBoolean(); boolean arrayEnabled = buf.readBoolean();
BlockPos arrayOffset = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt()); BlockPos arrayOffset = new BlockPos(buf.readInt(), buf.readInt(), buf.readInt());
int arrayCount = buf.readInt(); int arrayCount = buf.readInt();
a = new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount); a = new Array.ArraySettings(arrayEnabled, arrayOffset, arrayCount);
} }
boolean quickReplace = buf.readBoolean(); boolean quickReplace = buf.readBoolean();
int reachUpgrade = buf.readInt(); int reachUpgrade = buf.readInt();
//RADIAL MIRROR //RADIAL MIRROR
RadialMirror.RadialMirrorSettings r = new RadialMirror.RadialMirrorSettings(); RadialMirror.RadialMirrorSettings r = new RadialMirror.RadialMirrorSettings();
if (buf.readBoolean()) { if (buf.readBoolean()) {
boolean radialMirrorEnabled = buf.readBoolean(); boolean radialMirrorEnabled = buf.readBoolean();
Vector3d radialMirrorPosition = new Vector3d(buf.readDouble(), buf.readDouble(), buf.readDouble()); Vec3d radialMirrorPosition = new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble());
int radialMirrorSlices = buf.readInt(); int radialMirrorSlices = buf.readInt();
boolean radialMirrorAlternate = buf.readBoolean(); boolean radialMirrorAlternate = buf.readBoolean();
int radialMirrorRadius = buf.readInt(); int radialMirrorRadius = buf.readInt();
boolean radialMirrorDrawLines = buf.readBoolean(); boolean radialMirrorDrawLines = buf.readBoolean();
boolean radialMirrorDrawPlanes = buf.readBoolean(); boolean radialMirrorDrawPlanes = buf.readBoolean();
r = new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPosition, radialMirrorSlices, r = new RadialMirror.RadialMirrorSettings(radialMirrorEnabled, radialMirrorPosition, radialMirrorSlices,
radialMirrorAlternate, radialMirrorRadius, radialMirrorDrawLines, radialMirrorDrawPlanes); radialMirrorAlternate, radialMirrorRadius, radialMirrorDrawLines, radialMirrorDrawPlanes);
} }
ModifierSettings modifierSettings = new ModifierSettings(m, a, r, quickReplace, reachUpgrade); modifierSettings = new ModifierSettings(m, a, r, quickReplace, reachUpgrade);
return new ModifierSettingsMessage(modifierSettings); }
}
public static class Handler { // The params of the IMessageHandler are <REQ, REPLY>
public static void handle(ModifierSettingsMessage message, Supplier<NetworkEvent.Context> ctx) { public static class MessageHandler implements IMessageHandler<ModifierSettingsMessage, IMessage> {
ctx.get().enqueueWork(() -> { // Do note that the default constructor is required, but implicitly defined in this case
PlayerEntity player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
// Sanitize @Override
ModifierSettingsManager.sanitize(message.modifierSettings, player); public IMessage onMessage(ModifierSettingsMessage message, MessageContext ctx) {
//EffortlessBuilding.log("message received on " + ctx.side + " side");
ModifierSettingsManager.setModifierSettings(player, message.modifierSettings); // The value that was sent
}); ModifierSettings modifierSettings = message.modifierSettings;
ctx.get().setPacketHandled(true);
} // Execute the action on the main server thread by adding it as a scheduled task
} IThreadListener threadListener = EffortlessBuilding.proxy.getThreadListenerFromContext(ctx);
threadListener.addScheduledTask(() -> {
EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
// Sanitize
ModifierSettingsManager.sanitize(modifierSettings, player);
ModifierSettingsManager.setModifierSettings(player, modifierSettings);
});
// No response packet
return null;
}
}
} }

View File

@@ -1,32 +0,0 @@
package nl.requios.effortlessbuilding.network;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;
import nl.requios.effortlessbuilding.EffortlessBuilding;
public class PacketHandler {
private static final String PROTOCOL_VERSION = "1";
public static final SimpleChannel INSTANCE = NetworkRegistry.ChannelBuilder
.named(new ResourceLocation(EffortlessBuilding.MODID, "main_channel"))
.clientAcceptedVersions(PROTOCOL_VERSION::equals)
.serverAcceptedVersions(PROTOCOL_VERSION::equals)
.networkProtocolVersion(() -> PROTOCOL_VERSION)
.simpleChannel();
public static void register() {
int id = 0;
INSTANCE.registerMessage(id++, ModifierSettingsMessage.class, ModifierSettingsMessage::encode, ModifierSettingsMessage::decode, ModifierSettingsMessage.Handler::handle);
INSTANCE.registerMessage(id++, ModeSettingsMessage.class, ModeSettingsMessage::encode, ModeSettingsMessage::decode, ModeSettingsMessage.Handler::handle);
INSTANCE.registerMessage(id++, ModeActionMessage.class, ModeActionMessage::encode, ModeActionMessage::decode, ModeActionMessage.Handler::handle);
INSTANCE.registerMessage(id++, BlockPlacedMessage.class, BlockPlacedMessage::encode, BlockPlacedMessage::decode, BlockPlacedMessage.Handler::handle);
INSTANCE.registerMessage(id++, BlockBrokenMessage.class, BlockBrokenMessage::encode, BlockBrokenMessage::decode, BlockBrokenMessage.Handler::handle);
INSTANCE.registerMessage(id++, CancelModeMessage.class, CancelModeMessage::encode, CancelModeMessage::decode, CancelModeMessage.Handler::handle);
INSTANCE.registerMessage(id++, RequestLookAtMessage.class, RequestLookAtMessage::encode, RequestLookAtMessage::decode, RequestLookAtMessage.Handler::handle);
INSTANCE.registerMessage(id++, AddUndoMessage.class, AddUndoMessage::encode, AddUndoMessage::decode, AddUndoMessage.Handler::handle);
INSTANCE.registerMessage(id++, ClearUndoMessage.class, ClearUndoMessage::encode, ClearUndoMessage::decode, ClearUndoMessage.Handler::handle);
}
}

View File

@@ -1,62 +1,73 @@
package nl.requios.effortlessbuilding.network; package nl.requios.effortlessbuilding.network;
import net.minecraft.entity.player.PlayerEntity; import io.netty.buffer.ByteBuf;
import net.minecraft.network.PacketBuffer; import net.minecraft.block.Block;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.LogicalSide; import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraft.util.math.Vec3d;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmodifier.BlockSet;
import nl.requios.effortlessbuilding.buildmodifier.UndoRedo;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.ClientProxy;
import java.util.function.Supplier; import java.util.ArrayList;
/*** /***
* Sends a message to the client asking for its lookat (objectmouseover) data. * Sends a message to the client asking for its lookat (objectmouseover) data.
* This is then sent back with a BlockPlacedMessage. * This is then sent back with a BlockPlacedMessage.
*/ */
public class RequestLookAtMessage { public class RequestLookAtMessage implements IMessage {
private final boolean placeStartPos; private boolean placeStartPos;
public RequestLookAtMessage() { public RequestLookAtMessage() {
placeStartPos = false; placeStartPos = false;
} }
public RequestLookAtMessage(boolean placeStartPos) { public RequestLookAtMessage(boolean placeStartPos) {
this.placeStartPos = placeStartPos; this.placeStartPos = placeStartPos;
} }
public static void encode(RequestLookAtMessage message, PacketBuffer buf) { public boolean getPlaceStartPos() {
buf.writeBoolean(message.placeStartPos); return placeStartPos;
} }
public static RequestLookAtMessage decode(PacketBuffer buf) { @Override
boolean placeStartPos = buf.readBoolean(); public void toBytes(ByteBuf buf) {
return new RequestLookAtMessage(placeStartPos); buf.writeBoolean(this.placeStartPos);
} }
public boolean getPlaceStartPos() { @Override
return placeStartPos; public void fromBytes(ByteBuf buf) {
} placeStartPos = buf.readBoolean();
}
public static class Handler { // The params of the IMessageHandler are <REQ, REPLY>
public static void handle(RequestLookAtMessage message, Supplier<NetworkEvent.Context> ctx) { public static class MessageHandler implements IMessageHandler<RequestLookAtMessage, IMessage> {
ctx.get().enqueueWork(() -> { // Do note that the default constructor is required, but implicitly defined in this case
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) {
//Received clientside
//Send back your info
PlayerEntity player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
//Prevent double placing in normal mode with placeStartPos false @Override
//Unless QuickReplace is on, then we do need to place start pos. public IMessage onMessage(RequestLookAtMessage message, MessageContext ctx) {
if (ClientProxy.previousLookAt.getType() == RayTraceResult.Type.BLOCK) { //EffortlessBuilding.log("message received on " + ctx.side + " side");
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage((BlockRayTraceResult) ClientProxy.previousLookAt, message.getPlaceStartPos()));
} else { if (ctx.side == Side.CLIENT){
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage()); //Received clientside
} //Send back your info
}
}); // EffortlessBuilding.proxy.getThreadListenerFromContext(ctx).addScheduledTask(() -> {
ctx.get().setPacketHandled(true); // EntityPlayer player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
} //
} // });
//Prevent double placing in normal mode with placeStartPos false.
//Unless QuickReplace is on, then we do need to place start pos.
return new BlockPlacedMessage(ClientProxy.previousLookAt, message.getPlaceStartPos());
}
return null;
}
}
} }

View File

@@ -1,71 +0,0 @@
package nl.requios.effortlessbuilding.network;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.network.NetworkEvent;
import nl.requios.effortlessbuilding.EffortlessBuilding;
import java.util.function.Supplier;
public class TranslatedLogMessage {
private final String prefix;
private final String translationKey;
private final String suffix;
private final boolean actionBar;
public TranslatedLogMessage() {
prefix = "";
translationKey = "";
suffix = "";
actionBar = false;
}
public TranslatedLogMessage(String prefix, String translationKey, String suffix, boolean actionBar) {
this.prefix = prefix;
this.translationKey = translationKey;
this.suffix = suffix;
this.actionBar = actionBar;
}
public static void encode(TranslatedLogMessage message, PacketBuffer buf) {
buf.writeUtf(message.prefix);
buf.writeUtf(message.translationKey);
buf.writeUtf(message.suffix);
buf.writeBoolean(message.actionBar);
}
public static TranslatedLogMessage decode(PacketBuffer buf) {
return new TranslatedLogMessage(buf.readUtf(), buf.readUtf(), buf.readUtf(), buf.readBoolean());
}
public String getPrefix() {
return prefix;
}
public String getTranslationKey() {
return translationKey;
}
public String getSuffix() {
return suffix;
}
public boolean isActionBar() {
return actionBar;
}
public static class Handler {
public static void handle(TranslatedLogMessage message, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> {
if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT) {
//Received clientside
PlayerEntity player = EffortlessBuilding.proxy.getPlayerEntityFromContext(ctx);
EffortlessBuilding.logTranslate(player, message.prefix, message.translationKey, message.suffix, message.actionBar);
}
});
ctx.get().setPacketHandled(true);
}
}
}

View File

@@ -1,363 +1,417 @@
package nl.requios.effortlessbuilding.proxy; package nl.requios.effortlessbuilding.proxy;
import mcp.MethodsReturnNonnullByDefault; import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.SoundType; import net.minecraft.block.SoundType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.ScreenManager; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.resources.I18n; import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.KeyBinding; import net.minecraft.client.settings.KeyBinding;
import net.minecraft.client.util.InputMappings; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.BlockItem; import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand; import net.minecraft.util.EnumHand;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceContext;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.client.event.InputEvent; import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.client.settings.IKeyConflictContext;
import net.minecraftforge.client.settings.KeyConflictContext; import net.minecraftforge.client.settings.KeyConflictContext;
import net.minecraftforge.client.settings.KeyModifier; import net.minecraftforge.client.settings.KeyModifier;
import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DeferredWorkQueue;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.InputEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
import nl.requios.effortlessbuilding.buildmode.ModeOptions; import nl.requios.effortlessbuilding.buildmode.ModeOptions;
import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager; import nl.requios.effortlessbuilding.buildmode.ModeSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.gui.DiamondRandomizerBagScreen;
import nl.requios.effortlessbuilding.gui.GoldenRandomizerBagScreen;
import nl.requios.effortlessbuilding.gui.RandomizerBagScreen;
import nl.requios.effortlessbuilding.gui.buildmode.PlayerSettingsGui;
import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu; import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu;
import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui; import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui;
import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.network.*; import nl.requios.effortlessbuilding.render.RenderHandler;
import nl.requios.effortlessbuilding.render.ShaderHandler; import nl.requios.effortlessbuilding.render.ShaderHandler;
import org.lwjgl.glfw.GLFW; import nl.requios.effortlessbuilding.network.*;
import org.lwjgl.input.Keyboard;
import javax.annotation.ParametersAreNonnullByDefault; import javax.annotation.Nullable;
import java.util.function.Supplier; import java.util.HashMap;
@Mod.EventBusSubscriber(value = {Dist.CLIENT}) @Mod.EventBusSubscriber(Side.CLIENT)
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class ClientProxy implements IProxy { public class ClientProxy implements IProxy {
public static KeyBinding[] keyBindings; public static KeyBinding[] keyBindings;
public static RayTraceResult previousLookAt; public static RayTraceResult previousLookAt;
public static RayTraceResult currentLookAt; public static RayTraceResult currentLookAt;
public static int ticksInGame = 0; private static int placeCooldown = 0;
private static int placeCooldown = 0; private static int breakCooldown = 0;
private static int breakCooldown = 0;
private static boolean shadersInitialized = false;
@Override public static int ticksInGame = 0;
public void setup(FMLCommonSetupEvent event) {
}
@Override private static final HashMap<BuildModes.BuildModeEnum, TextureAtlasSprite> buildModeIcons = new HashMap<>();
public void clientSetup(FMLClientSetupEvent event) { private static final HashMap<ModeOptions.ActionEnum, TextureAtlasSprite> modeOptionIcons = new HashMap<>();
// register key bindings
keyBindings = new KeyBinding[6];
// instantiate the key bindings @Override
keyBindings[0] = new KeyBinding("key.effortlessbuilding.hud.desc", KeyConflictContext.UNIVERSAL, InputMappings.getKey(GLFW.GLFW_KEY_KP_ADD, 0), "key.effortlessbuilding.category"); public void preInit(FMLPreInitializationEvent event) {
keyBindings[1] = new KeyBinding("key.effortlessbuilding.replace.desc", KeyConflictContext.IN_GAME, InputMappings.getKey(GLFW.GLFW_KEY_KP_SUBTRACT, 0), "key.effortlessbuilding.category"); ShaderHandler.init();
keyBindings[2] = new KeyBinding("key.effortlessbuilding.mode.desc", KeyConflictContext.IN_GAME, InputMappings.getKey(GLFW.GLFW_KEY_LEFT_ALT, 0), "key.effortlessbuilding.category"); }
keyBindings[3] = new KeyBinding("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputMappings.getKey(GLFW.GLFW_KEY_Z, 0), "key.effortlessbuilding.category");
keyBindings[4] = new KeyBinding("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, InputMappings.getKey(GLFW.GLFW_KEY_Y, 0), "key.effortlessbuilding.category");
keyBindings[5] = new KeyBinding("key.effortlessbuilding.altplacement.desc", KeyConflictContext.IN_GAME, InputMappings.getKey(GLFW.GLFW_KEY_LEFT_CONTROL, 0), "key.effortlessbuilding.category");
// register all the key bindings @Override
for (KeyBinding keyBinding : keyBindings) { public void init(FMLInitializationEvent event) {
ClientRegistry.registerKeyBinding(keyBinding); // register key bindings
} keyBindings = new KeyBinding[7];
ScreenManager.register(EffortlessBuilding.RANDOMIZER_BAG_CONTAINER.get(), RandomizerBagScreen::new); // instantiate the key bindings
ScreenManager.register(EffortlessBuilding.GOLDEN_RANDOMIZER_BAG_CONTAINER.get(), GoldenRandomizerBagScreen::new); keyBindings[0] = new KeyBinding("key.effortlessbuilding.hud.desc", KeyConflictContext.UNIVERSAL, Keyboard.KEY_ADD, "key.effortlessbuilding.category");
ScreenManager.register(EffortlessBuilding.DIAMOND_RANDOMIZER_BAG_CONTAINER.get(), DiamondRandomizerBagScreen::new); keyBindings[1] = new KeyBinding("key.effortlessbuilding.replace.desc", KeyConflictContext.IN_GAME, Keyboard.KEY_SUBTRACT, "key.effortlessbuilding.category");
} keyBindings[2] = new KeyBinding("key.effortlessbuilding.creative.desc", KeyConflictContext.IN_GAME, Keyboard.KEY_NONE, "key.effortlessbuilding.category");
keyBindings[3] = new KeyBinding("key.effortlessbuilding.mode.desc", KeyConflictContext.IN_GAME, Keyboard.KEY_LMENU, "key.effortlessbuilding.category") {
@Override
public boolean conflicts(KeyBinding other) {
//Does not conflict with Chisels and Bits radial menu
if (other.getKeyCode() == getKeyCode() && other.getKeyDescription().equals("mod.chiselsandbits.other.mode")) return false;
return super.conflicts(other);
}
};
keyBindings[4] = new KeyBinding("key.effortlessbuilding.undo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, Keyboard.KEY_Z, "key.effortlessbuilding.category");
keyBindings[5] = new KeyBinding("key.effortlessbuilding.redo.desc", KeyConflictContext.IN_GAME, KeyModifier.CONTROL, Keyboard.KEY_Y, "key.effortlessbuilding.category");
keyBindings[6] = new KeyBinding("key.effortlessbuilding.altplacement.desc", KeyConflictContext.IN_GAME, Keyboard.KEY_LCONTROL, "key.effortlessbuilding.category");
// keyBindings[7] = new KeyBinding("Reload shaders", Keyboard.KEY_TAB, "key.effortlessbuilding.category");
@SubscribeEvent // register all the key bindings
public static void onClientTick(TickEvent.ClientTickEvent event) { for (int i = 0; i < keyBindings.length; ++i) {
ClientRegistry.registerKeyBinding(keyBindings[i]);
}
}
if (event.phase == TickEvent.Phase.START) { @Override
onMouseInput(); public void postInit(FMLPostInitializationEvent event) {
//Update previousLookAt }
RayTraceResult objectMouseOver = Minecraft.getInstance().hitResult;
//Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS)
if (objectMouseOver == null) return;
if (currentLookAt == null) { @Override
currentLookAt = objectMouseOver; public EntityPlayer getPlayerEntityFromContext(MessageContext ctx) {
previousLookAt = objectMouseOver; return (ctx.side.isClient() ? Minecraft.getMinecraft().player : ctx.getServerHandler().player);
return; }
}
if (objectMouseOver.getType() == RayTraceResult.Type.BLOCK) { @Override
if (currentLookAt.getType() != RayTraceResult.Type.BLOCK) { public IThreadListener getThreadListenerFromContext(MessageContext ctx) {
currentLookAt = objectMouseOver; return (ctx.side.isClient() ? Minecraft.getMinecraft() : ((EntityPlayerMP) getPlayerEntityFromContext(ctx)).getServerWorld());
previousLookAt = objectMouseOver; }
} else {
if (((BlockRayTraceResult) currentLookAt).getBlockPos() != ((BlockRayTraceResult) objectMouseOver).getBlockPos()) {
previousLookAt = currentLookAt;
currentLookAt = objectMouseOver;
}
}
}
} else if (event.phase == TickEvent.Phase.END) { @Override
Screen gui = Minecraft.getInstance().screen; public void serverStarting(FMLServerStartingEvent event) {
if (gui == null || !gui.isPauseScreen()) { //This will get called clientside
ticksInGame++; }
}
//Init shaders in the first tick. Doing it anywhere before this seems to crash the game. @SubscribeEvent
if (!shadersInitialized) { public static void registerModels(ModelRegistryEvent event) {
ShaderHandler.init(); for (Block block : EffortlessBuilding.BLOCKS) {
shadersInitialized = true; ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(block), 0, new ModelResourceLocation(block.getRegistryName(), "inventory"));
} }
}
} for (Item item : EffortlessBuilding.ITEMS) {
ModelLoader.setCustomModelResourceLocation(item, 0, new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
}
private static void onMouseInput() { @SubscribeEvent
Minecraft mc = Minecraft.getInstance(); public static void onEntityJoinWorld(EntityJoinWorldEvent event) {
ClientPlayerEntity player = mc.player; if (event.getEntity() == Minecraft.getMinecraft().player) {
if (player == null) return; event.getWorld().addEventListener(new RenderHandler());
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); }
}
if (Minecraft.getInstance().screen != null || @SubscribeEvent
buildMode == BuildModes.BuildModeEnum.NORMAL || public static void onTextureStitch(final TextureStitchEvent.Pre event) {
RadialMenu.instance.isVisible()) { //register icon textures
return; final TextureMap map = event.getMap();
}
if (mc.options.keyUse.isDown()) { for ( final BuildModes.BuildModeEnum mode : BuildModes.BuildModeEnum.values() )
{
final ResourceLocation sprite = new ResourceLocation("effortlessbuilding", "icons/" + mode.name().toLowerCase());
buildModeIcons.put( mode, map.registerSprite(sprite));
}
//KeyBinding.setKeyBindState(mc.gameSettings.keyBindUseItem.getKeyCode(), false); for ( final ModeOptions.ActionEnum action : ModeOptions.ActionEnum.values() )
{
final ResourceLocation sprite = new ResourceLocation("effortlessbuilding", "icons/" + action.name().toLowerCase());
modeOptionIcons.put( action, map.registerSprite(sprite));
}
}
if (placeCooldown <= 0) { public static TextureAtlasSprite getBuildModeIcon(BuildModes.BuildModeEnum mode) {
placeCooldown = 4; return buildModeIcons.get(mode);
}
ItemStack currentItemStack = player.getItemInHand(Hand.MAIN_HAND); public static TextureAtlasSprite getModeOptionIcon(ModeOptions.ActionEnum action) {
if (currentItemStack.getItem() instanceof BlockItem || return modeOptionIcons.get(action);
(CompatHelper.isItemBlockProxy(currentItemStack) && !player.isShiftKeyDown())) { }
ItemStack itemStack = CompatHelper.getItemBlockFromStack(currentItemStack); @SubscribeEvent
public static void onClientTick(TickEvent.ClientTickEvent event) {
//find position in distance if (event.phase == TickEvent.Phase.START) {
RayTraceResult lookingAt = getLookingAt(player); onMouseInput();
if (lookingAt != null && lookingAt.getType() == RayTraceResult.Type.BLOCK) {
BlockRayTraceResult blockLookingAt = (BlockRayTraceResult) lookingAt;
BuildModes.onBlockPlacedMessage(player, new BlockPlacedMessage(blockLookingAt, true)); //Update previousLookAt
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage(blockLookingAt, true)); RayTraceResult objectMouseOver = Minecraft.getMinecraft().objectMouseOver;
//Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS)
if (objectMouseOver == null) return;
//play sound if further than normal if (currentLookAt == null) {
if ((blockLookingAt.getLocation().subtract(player.getEyePosition(1f))).lengthSqr() > 25f && currentLookAt = objectMouseOver;
itemStack.getItem() instanceof BlockItem) { previousLookAt = objectMouseOver;
return;
}
BlockState state = ((BlockItem) itemStack.getItem()).getBlock().defaultBlockState(); if (objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK) {
BlockPos blockPos = blockLookingAt.getBlockPos(); if (currentLookAt.typeOfHit != RayTraceResult.Type.BLOCK) {
SoundType soundType = state.getBlock().getSoundType(state, player.level, blockPos, player); currentLookAt = objectMouseOver;
player.level.playSound(player, player.blockPosition(), soundType.getPlaceSound(), SoundCategory.BLOCKS, previousLookAt = objectMouseOver;
0.4f, soundType.getPitch()); } else {
player.swing(Hand.MAIN_HAND); if (currentLookAt.getBlockPos() != objectMouseOver.getBlockPos()) {
} previousLookAt = currentLookAt;
} else { currentLookAt = objectMouseOver;
BuildModes.onBlockPlacedMessage(player, new BlockPlacedMessage()); }
PacketHandler.INSTANCE.sendToServer(new BlockPlacedMessage()); }
} }
} } else if (event.phase == TickEvent.Phase.END){
} else if (buildMode == BuildModes.BuildModeEnum.NORMAL_PLUS) { GuiScreen gui = Minecraft.getMinecraft().currentScreen;
placeCooldown--; if(gui == null || !gui.doesGuiPauseGame()) {
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) placeCooldown = 0; ticksInGame++;
} }
} else { }
placeCooldown = 0;
}
if (mc.options.keyAttack.isDown()) { }
//Break block in distance in creative (or survival if enabled in config) private static void onMouseInput() {
if (breakCooldown <= 0) { Minecraft mc = Minecraft.getMinecraft();
breakCooldown = 4; EntityPlayerSP player = mc.player;
if (player == null) return;
BuildModes.BuildModeEnum buildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
//Early out if cant break far, coming from own mouse event (not block broken event) if (Minecraft.getMinecraft().currentScreen != null ||
//To make breaking blocks in survival possible like array buildMode == BuildModes.BuildModeEnum.NORMAL ||
//TODO this causes not being able to cancel placement in survival RadialMenu.instance.isVisible()) {
// moving it to after buildmodes fixes that, but introduces this bug return;
if (!ReachHelper.canBreakFar(player)) return; }
RayTraceResult lookingAt = getLookingAt(player); if (mc.gameSettings.keyBindUseItem.isKeyDown()) {
if (lookingAt != null && lookingAt.getType() == RayTraceResult.Type.BLOCK) { //KeyBinding.setKeyBindState(mc.gameSettings.keyBindUseItem.getKeyCode(), false);
BlockRayTraceResult blockLookingAt = (BlockRayTraceResult) lookingAt;
BuildModes.onBlockBrokenMessage(player, new BlockBrokenMessage(blockLookingAt)); if (placeCooldown <= 0) {
PacketHandler.INSTANCE.sendToServer(new BlockBrokenMessage(blockLookingAt)); placeCooldown = 4;
//play sound if further than normal ItemStack currentItemStack = player.getHeldItem(EnumHand.MAIN_HAND);
if ((blockLookingAt.getLocation().subtract(player.getEyePosition(1f))).lengthSqr() > 25f) { if (currentItemStack.getItem() instanceof ItemBlock ||
(CompatHelper.isItemBlockProxy(currentItemStack) && !player.isSneaking())) {
BlockPos blockPos = blockLookingAt.getBlockPos(); ItemStack itemStack = CompatHelper.getItemBlockFromStack(currentItemStack);
BlockState state = player.level.getBlockState(blockPos);
SoundType soundtype = state.getBlock().getSoundType(state, player.level, blockPos, player);
player.level.playSound(player, player.blockPosition(), soundtype.getBreakSound(), SoundCategory.BLOCKS,
0.4f, soundtype.getPitch());
player.swing(Hand.MAIN_HAND);
}
} else {
BuildModes.onBlockBrokenMessage(player, new BlockBrokenMessage());
PacketHandler.INSTANCE.sendToServer(new BlockBrokenMessage());
}
} else if (buildMode == BuildModes.BuildModeEnum.NORMAL_PLUS) {
breakCooldown--;
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) breakCooldown = 0;
}
//EffortlessBuilding.packetHandler.sendToServer(new CancelModeMessage()); //find position in distance
RayTraceResult lookingAt = getLookingAt(player);
BuildModes.onBlockPlacedMessage(player, lookingAt == null ? new BlockPlacedMessage() : new BlockPlacedMessage(lookingAt, true));
EffortlessBuilding.packetHandler.sendToServer(lookingAt == null ? new BlockPlacedMessage() : new BlockPlacedMessage(lookingAt, true));
} else { //play sound if further than normal
breakCooldown = 0; if (lookingAt != null && lookingAt.typeOfHit == RayTraceResult.Type.BLOCK &&
} (lookingAt.hitVec.subtract(player.getPositionEyes(1f))).lengthSquared() > 25f &&
} itemStack.getItem() instanceof ItemBlock) {
@SubscribeEvent(receiveCanceled = true) IBlockState state = ((ItemBlock) itemStack.getItem()).getBlock().getDefaultState();
public static void onKeyPress(InputEvent.KeyInputEvent event) { BlockPos blockPos = lookingAt.getBlockPos();
ClientPlayerEntity player = Minecraft.getInstance().player; SoundType soundType = state.getBlock().getSoundType(state, player.world, blockPos, player);
if (player == null) player.world.playSound(player, player.getPosition(), soundType.getPlaceSound(), SoundCategory.BLOCKS,
return; 0.4f, soundType.getPitch() * 1f);
player.swingArm(EnumHand.MAIN_HAND);
}
}
} else if (buildMode == BuildModes.BuildModeEnum.NORMAL_PLUS) {
placeCooldown--;
if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) placeCooldown = 0;
}
} else {
placeCooldown = 0;
}
//Remember to send packet to server if necessary if (mc.gameSettings.keyBindAttack.isKeyDown()) {
//Show Modifier Settings GUI
if (keyBindings[0].consumeClick()) {
openModifierSettings();
}
//QuickReplace toggle //Break block in distance in creative (or survival if enabled in config)
if (keyBindings[1].consumeClick()) { if (breakCooldown <= 0) {
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); breakCooldown = 4;
modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace());
EffortlessBuilding.log(player, "Set " + TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + (
modifierSettings.doQuickReplace() ? "on" : "off"));
PacketHandler.INSTANCE.sendToServer(new ModifierSettingsMessage(modifierSettings));
}
//Radial menu //Early out if cant break far, coming from own mouse event (not block broken event)
if (keyBindings[2].isDown()) { //To make breaking blocks in survival possible like array
if (ReachHelper.getMaxReach(player) > 0) { //TODO this causes not being able to cancel placement in survival
if (!RadialMenu.instance.isVisible()) { // moving it to after buildmodes fixes that, but introduces this bug
Minecraft.getInstance().setScreen(RadialMenu.instance); if (!ReachHelper.canBreakFar(player)) return;
}
} else {
EffortlessBuilding.log(player, "Build modes are disabled until your reach has increased. Increase your reach with craftable reach upgrades.");
}
}
//Undo (Ctrl+Z) RayTraceResult lookingAt = getLookingAt(player);
if (keyBindings[3].consumeClick()) { BuildModes.onBlockBrokenMessage(player, lookingAt == null ? new BlockBrokenMessage() : new BlockBrokenMessage(lookingAt));
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.UNDO; EffortlessBuilding.packetHandler.sendToServer(lookingAt == null ? new BlockBrokenMessage() : new BlockBrokenMessage(lookingAt));
ModeOptions.performAction(player, action);
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
}
//Redo (Ctrl+Y) //play sound if further than normal
if (keyBindings[4].consumeClick()) { if (lookingAt != null && lookingAt.typeOfHit == RayTraceResult.Type.BLOCK &&
ModeOptions.ActionEnum action = ModeOptions.ActionEnum.REDO; (lookingAt.hitVec.subtract(player.getPositionEyes(1f))).lengthSquared() > 25f) {
ModeOptions.performAction(player, action);
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(action));
}
//Change placement mode BlockPos blockPos = lookingAt.getBlockPos();
if (keyBindings[5].consumeClick()) { IBlockState state = player.world.getBlockState(blockPos);
//Toggle between first two actions of the first option of the current build mode SoundType soundtype = state.getBlock().getSoundType(state, player.world, blockPos, player);
BuildModes.BuildModeEnum currentBuildMode = ModeSettingsManager.getModeSettings(player).getBuildMode(); player.world.playSound(player, player.getPosition(), soundtype.getBreakSound(), SoundCategory.BLOCKS,
if (currentBuildMode.options.length > 0) { 0.4f, soundtype.getPitch() * 1f);
ModeOptions.OptionEnum option = currentBuildMode.options[0]; player.swingArm(EnumHand.MAIN_HAND);
if (option.actions.length >= 2) { }
if (ModeOptions.getOptionSetting(option) == option.actions[0]) { } else if (buildMode == BuildModes.BuildModeEnum.NORMAL_PLUS) {
ModeOptions.performAction(player, option.actions[1]); breakCooldown--;
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(option.actions[1])); if (ModeOptions.getBuildSpeed() == ModeOptions.ActionEnum.FAST_SPEED) breakCooldown = 0;
} else { }
ModeOptions.performAction(player, option.actions[0]);
PacketHandler.INSTANCE.sendToServer(new ModeActionMessage(option.actions[0]));
}
}
}
}
}
public static void openModifierSettings() { //EffortlessBuilding.packetHandler.sendToServer(new CancelModeMessage());
Minecraft mc = Minecraft.getInstance();
PlayerEntity player = mc.player;
if (player == null) return;
//Disabled if max reach is 0, might be set in the config that way. } else {
if (ReachHelper.getMaxReach(player) == 0) { breakCooldown = 0;
EffortlessBuilding.log(player, "Build modifiers are disabled until your reach has increased. Increase your reach with craftable reach upgrades."); }
} else {
mc.setScreen(new ModifierSettingsGui());
}
}
public static void openPlayerSettings() { if (mc.gameSettings.keyBindAttack.isPressed()) {
Minecraft mc = Minecraft.getInstance(); if (RadialMenu.instance.isVisible()) {
mc.setScreen(new PlayerSettingsGui()); EffortlessBuilding.log(player, "mouse click");
} }
}
@SubscribeEvent }
public static void onGuiOpen(GuiOpenEvent event) {
PlayerEntity player = Minecraft.getInstance().player;
if (player != null) {
BuildModes.initializeMode(player);
}
}
public static boolean isKeybindDown(int keybindIndex) { @SubscribeEvent(priority = EventPriority.NORMAL, receiveCanceled = true)
return InputMappings.isKeyDown( public static void onKeyPress(InputEvent.KeyInputEvent event) {
Minecraft.getInstance().getWindow().getWindow(), EntityPlayerSP player = Minecraft.getMinecraft().player;
ClientProxy.keyBindings[2].getKey().getValue());
}
public static RayTraceResult getLookingAt(PlayerEntity player) { //Remember to send packet to server if necessary
World world = player.level; //Show Modifier Settings GUI
if (keyBindings[0].isPressed()) {
openModifierSettings();
}
//base distance off of player ability (config) //QuickReplace toggle
float raytraceRange = ReachHelper.getPlacementReach(player); if (keyBindings[1].isPressed()) {
ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace());
EffortlessBuilding.log(player, "Set "+ TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + (
modifierSettings.doQuickReplace() ? "on" : "off"));
EffortlessBuilding.packetHandler.sendToServer(new ModifierSettingsMessage(modifierSettings));
}
Vector3d look = player.getLookAngle(); //Creative/survival mode toggle
Vector3d start = new Vector3d(player.getX(), player.getY() + player.getEyeHeight(), player.getZ()); if (keyBindings[2].isPressed()) {
Vector3d end = new Vector3d(player.getX() + look.x * raytraceRange, player.getY() + player.getEyeHeight() + look.y * raytraceRange, player.getZ() + look.z * raytraceRange); if (player.isCreative()) {
// return player.rayTrace(raytraceRange, 1f, RayTraceFluidMode.NEVER); player.sendChatMessage("/gamemode 0");
//TODO 1.14 check if correct } else {
return world.clip(new RayTraceContext(start, end, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, player)); player.sendChatMessage("/gamemode 1");
} }
}
public PlayerEntity getPlayerEntityFromContext(Supplier<NetworkEvent.Context> ctx) { //Undo (Ctrl+Z)
return (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT ? Minecraft.getInstance().player : ctx.get().getSender()); if (keyBindings[4].isPressed()) {
} ModeOptions.ActionEnum action = ModeOptions.ActionEnum.UNDO;
ModeOptions.performAction(player, action);
EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(action));
}
@Override //Redo (Ctrl+Y)
public void logTranslate(PlayerEntity player, String prefix, String translationKey, String suffix, boolean actionBar) { if (keyBindings[5].isPressed()) {
EffortlessBuilding.log(Minecraft.getInstance().player, prefix + I18n.get(translationKey) + suffix, actionBar); ModeOptions.ActionEnum action = ModeOptions.ActionEnum.REDO;
} ModeOptions.performAction(player, action);
EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(action));
}
//Change placement mode
if (keyBindings[6].isPressed()) {
//Toggle between first two actions of the first option of the current build mode
BuildModes.BuildModeEnum currentBuildMode = ModeSettingsManager.getModeSettings(player).getBuildMode();
if (currentBuildMode.options.length > 0) {
ModeOptions.OptionEnum option = currentBuildMode.options[0];
if (option.actions.length >= 2) {
if (ModeOptions.getOptionSetting(option) == option.actions[0]) {
ModeOptions.performAction(player, option.actions[1]);
EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(option.actions[1]));
} else {
ModeOptions.performAction(player, option.actions[0]);
EffortlessBuilding.packetHandler.sendToServer(new ModeActionMessage(option.actions[0]));
}
}
}
}
//For shader development
if (keyBindings.length >= 8 && keyBindings[7].isPressed()) {
ShaderHandler.init();
EffortlessBuilding.log(player, "Reloaded shaders");
}
}
public static void openModifierSettings() {
Minecraft mc = Minecraft.getMinecraft();
EntityPlayerSP player = mc.player;
RadialMenu.instance.setVisibility(0f);
//Disabled if max reach is 0, might be set in the config that way.
if (ReachHelper.getMaxReach(player) == 0) {
EffortlessBuilding.log(player, "Build modifiers are disabled until your reach has increased. Increase your reach with craftable reach upgrades.");
} else {
if (mc.currentScreen == null) {
mc.displayGuiScreen(new ModifierSettingsGui());
} else {
player.closeScreen();
}
}
}
@SubscribeEvent
public static void onGuiOpen(GuiOpenEvent event) {
EntityPlayer player = Minecraft.getMinecraft().player;
if (player != null) {
BuildModes.initializeMode(player);
}
}
@Nullable
public static RayTraceResult getLookingAt(EntityPlayer player) {
// World world = player.world;
//base distance off of player ability (config)
float raytraceRange = ReachHelper.getPlacementReach(player);
// Vec3d look = player.getLookVec();
// Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
// Vec3d end = new Vec3d(player.posX + look.x * raytraceRange, player.posY + player.getEyeHeight() + look.y * raytraceRange, player.posZ + look.z * raytraceRange);
return player.rayTrace(raytraceRange, 1f);
// return world.rayTraceBlocks(start, end, false, false, false);
}
public static void logTranslate(String key) {
EffortlessBuilding.log(Minecraft.getMinecraft().player, I18n.format(key), true);
}
} }

View File

@@ -1,18 +1,43 @@
package nl.requios.effortlessbuilding.proxy; package nl.requios.effortlessbuilding.proxy;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import java.util.function.Supplier; public interface IProxy
{
/**
* Register entities and networking.
*/
void preInit(FMLPreInitializationEvent event);
public interface IProxy { /**
void setup(final FMLCommonSetupEvent event); * Register event listeners, recipes and advancements.
*/
void init(FMLInitializationEvent event);
void clientSetup(final FMLClientSetupEvent event); /**
* For doing inter-mod stuff like checking which mods are loaded or if you want a complete view of things across
* mods like having a list of all registered items to aid random item generation.
*/
void postInit(FMLPostInitializationEvent event);
PlayerEntity getPlayerEntityFromContext(Supplier<NetworkEvent.Context> ctx); /**
* Server commands should be registered here.
*/
void serverStarting(FMLServerStartingEvent event);
void logTranslate(PlayerEntity player, String prefix, String translationKey, String suffix, boolean actionBar); /**
* Returns a side-appropriate EntityPlayer for use during message handling.
*
* @param ctx the context
* @return the player entity from context
*/
EntityPlayer getPlayerEntityFromContext(MessageContext ctx);
IThreadListener getThreadListenerFromContext(MessageContext ctx);
} }

View File

@@ -1,33 +1,45 @@
package nl.requios.effortlessbuilding.proxy; package nl.requios.effortlessbuilding.proxy;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraft.util.IThreadListener;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import nl.requios.effortlessbuilding.network.PacketHandler; import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import nl.requios.effortlessbuilding.network.TranslatedLogMessage; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import java.util.function.Supplier; public class ServerProxy implements IProxy
{
//Only physical server! Singleplayer server is seen as clientproxy
@Override
public void preInit(FMLPreInitializationEvent event)
{
}
public class ServerProxy implements IProxy { @Override
//Only physical server! Singleplayer server is seen as clientproxy public void init(FMLInitializationEvent event)
@Override {
public void setup(FMLCommonSetupEvent event) { }
} @Override
public void postInit(FMLPostInitializationEvent event)
{
}
@Override @Override
public void clientSetup(FMLClientSetupEvent event) { public void serverStarting(FMLServerStartingEvent event)
} {
}
public PlayerEntity getPlayerEntityFromContext(Supplier<NetworkEvent.Context> ctx) { @Override
return ctx.get().getSender(); public EntityPlayer getPlayerEntityFromContext(MessageContext ctx)
} {
return ctx.getServerHandler().player;
}
@Override @Override
public void logTranslate(PlayerEntity player, String prefix, String translationKey, String suffix, boolean actionBar) { public IThreadListener getThreadListenerFromContext(MessageContext ctx) {
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), new TranslatedLogMessage(prefix, translationKey, suffix, actionBar)); return ((EntityPlayerMP) getPlayerEntityFromContext(ctx)).getServerWorld();
} }
} }

View File

@@ -1,25 +1,21 @@
package nl.requios.effortlessbuilding.render; package nl.requios.effortlessbuilding.render;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.vertex.IVertexBuilder;
import net.minecraft.block.BlockState;
import net.minecraft.block.SoundType; import net.minecraft.block.SoundType;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.renderer.BlockRendererDispatcher; import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction; import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.*;
import net.minecraft.util.math.BlockRayTraceResult; import net.minecraftforge.fml.relauncher.Side;
import net.minecraft.util.math.MathHelper; import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import nl.requios.effortlessbuilding.BuildConfig; import nl.requios.effortlessbuilding.BuildConfig;
import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.EffortlessBuilding;
import nl.requios.effortlessbuilding.buildmode.BuildModes; import nl.requios.effortlessbuilding.buildmode.BuildModes;
@@ -30,354 +26,411 @@ import nl.requios.effortlessbuilding.buildmodifier.BuildModifiers;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager;
import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings; import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager.ModifierSettings;
import nl.requios.effortlessbuilding.compatibility.CompatHelper; import nl.requios.effortlessbuilding.compatibility.CompatHelper;
import nl.requios.effortlessbuilding.helper.InventoryHelper;
import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.ReachHelper;
import nl.requios.effortlessbuilding.helper.SurvivalHelper; import nl.requios.effortlessbuilding.helper.SurvivalHelper;
import nl.requios.effortlessbuilding.item.RandomizerBagItem; import nl.requios.effortlessbuilding.item.ItemRandomizerBag;
import nl.requios.effortlessbuilding.proxy.ClientProxy; import nl.requios.effortlessbuilding.proxy.ClientProxy;
import org.lwjgl.opengl.ARBMultitexture;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Consumer;
@OnlyIn(Dist.CLIENT) @SideOnly(Side.CLIENT)
public class BlockPreviewRenderer { public class BlockPreviewRenderer {
private static final List<PlacedData> placedDataList = new ArrayList<>(); private static List<BlockPos> previousCoordinates;
private static List<BlockPos> previousCoordinates; private static List<IBlockState> previousBlockStates;
private static List<BlockState> previousBlockStates; private static List<ItemStack> previousItemStacks;
private static List<ItemStack> previousItemStacks; private static BlockPos previousFirstPos;
private static BlockPos previousFirstPos; private static BlockPos previousSecondPos;
private static BlockPos previousSecondPos; private static int soundTime = 0;
private static int soundTime = 0;
public static void render(MatrixStack matrixStack, IRenderTypeBuffer.Impl renderTypeBuffer, PlayerEntity player, ModifierSettings modifierSettings, ModeSettings modeSettings) { static class PlacedData {
float time;
List<BlockPos> coordinates;
List<IBlockState> blockStates;
List<ItemStack> itemStacks;
BlockPos firstPos;
BlockPos secondPos;
boolean breaking;
//Render placed blocks with dissolve effect public PlacedData(float time, List<BlockPos> coordinates, List<IBlockState> blockStates,
//Use fancy shader if config allows, otherwise no dissolve List<ItemStack> itemStacks, BlockPos firstPos, BlockPos secondPos, boolean breaking) {
if (BuildConfig.visuals.useShaders.get()) { this.time = time;
for (int i = 0; i < placedDataList.size(); i++) { this.coordinates = coordinates;
PlacedData placed = placedDataList.get(i); this.blockStates = blockStates;
if (placed.coordinates != null && !placed.coordinates.isEmpty()) { this.itemStacks = itemStacks;
this.firstPos = firstPos;
this.secondPos = secondPos;
this.breaking = breaking;
}
}
double totalTime = MathHelper.clampedLerp(30, 60, placed.firstPos.distSqr(placed.secondPos) / 100.0) * BuildConfig.visuals.dissolveTimeMultiplier.get(); private static List<PlacedData> placedDataList = new ArrayList<>();
float dissolve = (ClientProxy.ticksInGame - placed.time) / (float) totalTime;
renderBlockPreviews(matrixStack, renderTypeBuffer, placed.coordinates, placed.blockStates, placed.itemStacks, dissolve, placed.firstPos, placed.secondPos, false, placed.breaking);
}
}
}
//Expire
placedDataList.removeIf(placed -> {
double totalTime = MathHelper.clampedLerp(30, 60, placed.firstPos.distSqr(placed.secondPos) / 100.0) * BuildConfig.visuals.dissolveTimeMultiplier.get();
return placed.time + totalTime < ClientProxy.ticksInGame;
});
//Render block previews private static final int primaryTextureUnit = 0;
RayTraceResult lookingAt = ClientProxy.getLookingAt(player); private static final int secondaryTextureUnit = 2;
if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.NORMAL)
lookingAt = Minecraft.getInstance().hitResult;
ItemStack mainhand = player.getMainHandItem(); public static void render(EntityPlayer player, ModifierSettings modifierSettings, ModeSettings modeSettings) {
boolean toolInHand = !(!mainhand.isEmpty() && CompatHelper.isItemBlockProxy(mainhand));
BlockPos startPos = null; //Render placed blocks with dissolve effect
Direction sideHit = null; //Use fancy shader if config allows, otherwise no dissolve
Vector3d hitVec = null; if (BuildConfig.visuals.useShaders) {
RenderHandler.beginBlockPreviews();
for (int i = 0; i < placedDataList.size(); i++) {
PlacedData placed = placedDataList.get(i);
if (placed.coordinates != null && !placed.coordinates.isEmpty()) {
//Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS) double totalTime = MathHelper.clampedLerp(30, 60, placed.firstPos.distanceSq(placed.secondPos) / 100.0) * BuildConfig.visuals.dissolveTimeMultiplier;
if (lookingAt != null && lookingAt.getType() == RayTraceResult.Type.BLOCK) { float dissolve = (ClientProxy.ticksInGame - placed.time) / (float) totalTime;
BlockRayTraceResult blockLookingAt = (BlockRayTraceResult) lookingAt; renderBlockPreviews(placed.coordinates, placed.blockStates, placed.itemStacks, dissolve, placed.firstPos, placed.secondPos, false, placed.breaking);
startPos = blockLookingAt.getBlockPos(); }
}
RenderHandler.endBlockPreviews();
}
//Expire
placedDataList.removeIf(placed -> {
double totalTime = MathHelper.clampedLerp(30, 60, placed.firstPos.distanceSq(placed.secondPos) / 100.0) * BuildConfig.visuals.dissolveTimeMultiplier;
return placed.time + totalTime < ClientProxy.ticksInGame;
});
//Check if tool (or none) in hand //Render block previews
//TODO 1.13 replaceable RayTraceResult lookingAt = ClientProxy.getLookingAt(player);
boolean replaceable = player.level.getBlockState(startPos).getMaterial().isReplaceable(); if (modeSettings.getBuildMode() == BuildModes.BuildModeEnum.NORMAL) lookingAt = Minecraft.getMinecraft().objectMouseOver;
boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos, blockLookingAt.getDirection());
if (!modifierSettings.doQuickReplace() && !toolInHand && !replaceable && !becomesDoubleSlab) {
startPos = startPos.relative(blockLookingAt.getDirection());
}
//Get under tall grass and other replaceable blocks ItemStack mainhand = player.getHeldItemMainhand();
if (modifierSettings.doQuickReplace() && !toolInHand && replaceable) { boolean toolInHand = !(!mainhand.isEmpty() && CompatHelper.isItemBlockProxy(mainhand));
startPos = startPos.below();
}
sideHit = blockLookingAt.getDirection(); BlockPos startPos = null;
hitVec = blockLookingAt.getLocation(); EnumFacing sideHit = null;
} Vec3d hitVec = null;
//Dont render if in normal mode and modifiers are disabled //Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS)
//Unless alwaysShowBlockPreview is true in config if (lookingAt != null && lookingAt.typeOfHit == RayTraceResult.Type.BLOCK) {
if (doRenderBlockPreviews(modifierSettings, modeSettings, startPos)) { startPos = lookingAt.getBlockPos();
//Keep blockstate the same for every block in the buildmode //Check if tool (or none) in hand
//So dont rotate blocks when in the middle of placing wall etc. boolean replaceable = player.world.getBlockState(startPos).getBlock().isReplaceable(player.world, startPos);
if (BuildModes.isActive(player)) { boolean becomesDoubleSlab = SurvivalHelper.doesBecomeDoubleSlab(player, startPos, lookingAt.sideHit);
IBuildMode buildModeInstance = modeSettings.getBuildMode().instance; if (!modifierSettings.doQuickReplace() && !toolInHand && !replaceable && !becomesDoubleSlab) {
if (buildModeInstance.getSideHit(player) != null) sideHit = buildModeInstance.getSideHit(player); startPos = startPos.offset(lookingAt.sideHit);
if (buildModeInstance.getHitVec(player) != null) hitVec = buildModeInstance.getHitVec(player); }
}
if (sideHit != null) { //Get under tall grass and other replaceable blocks
if (modifierSettings.doQuickReplace() && !toolInHand && replaceable) {
startPos = startPos.down();
}
//Should be red? sideHit = lookingAt.sideHit;
boolean breaking = BuildModes.currentlyBreakingClient.get(player) != null && BuildModes.currentlyBreakingClient.get(player); hitVec = lookingAt.hitVec;
}
//get coordinates //Dont render if in normal mode and modifiers are disabled
List<BlockPos> startCoordinates = BuildModes.findCoordinates(player, startPos, breaking || modifierSettings.doQuickReplace()); //Unless alwaysShowBlockPreview is true in config
if (doRenderBlockPreviews(modifierSettings, modeSettings, startPos)) {
//Remember first and last point for the shader //Keep blockstate the same for every block in the buildmode
BlockPos firstPos = BlockPos.ZERO, secondPos = BlockPos.ZERO; //So dont rotate blocks when in the middle of placing wall etc.
if (!startCoordinates.isEmpty()) { if (BuildModes.isActive(player)) {
firstPos = startCoordinates.get(0); IBuildMode buildModeInstance = modeSettings.getBuildMode().instance;
secondPos = startCoordinates.get(startCoordinates.size() - 1); if (buildModeInstance.getSideHit(player) != null) sideHit = buildModeInstance.getSideHit(player);
} if (buildModeInstance.getHitVec(player) != null) hitVec = buildModeInstance.getHitVec(player);
}
//Limit number of blocks you can place if (sideHit != null) {
int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
if (startCoordinates.size() > limit) {
startCoordinates = startCoordinates.subList(0, limit);
}
List<BlockPos> newCoordinates = BuildModifiers.findCoordinates(player, startCoordinates); //Should be red?
boolean breaking = BuildModes.currentlyBreakingClient.get(player) != null && BuildModes.currentlyBreakingClient.get(player);
sortOnDistanceToPlayer(newCoordinates, player); //get coordinates
List<BlockPos> startCoordinates = BuildModes.findCoordinates(player, startPos, breaking || modifierSettings.doQuickReplace());
hitVec = new Vector3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)), BlockPos firstPos = BlockPos.ORIGIN, secondPos = BlockPos.ORIGIN;
Math.abs(hitVec.z - ((int) hitVec.z))); //Remember first and last pos for the shader
if (!startCoordinates.isEmpty()) {
firstPos = startCoordinates.get(0);
secondPos = startCoordinates.get(startCoordinates.size() - 1);
}
//Get blockstates //Limit number of blocks you can place
List<ItemStack> itemStacks = new ArrayList<>(); int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player);
List<BlockState> blockStates = new ArrayList<>(); if (startCoordinates.size() > limit) {
if (breaking) { startCoordinates = startCoordinates.subList(0, limit);
//Find blockstate of world }
for (BlockPos coordinate : newCoordinates) {
blockStates.add(player.level.getBlockState(coordinate)); List<BlockPos> newCoordinates = BuildModifiers.findCoordinates(player, startCoordinates);
}
} else { sortOnDistanceToPlayer(newCoordinates, player);
blockStates = BuildModifiers.findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks);
} hitVec = new Vec3d(Math.abs(hitVec.x - ((int) hitVec.x)), Math.abs(hitVec.y - ((int) hitVec.y)),
Math.abs(hitVec.z - ((int) hitVec.z)));
//Get blockstates
List<ItemStack> itemStacks = new ArrayList<>();
List<IBlockState> blockStates = new ArrayList<>();
if (breaking) {
//Find blockstate of world
for (BlockPos coordinate : newCoordinates) {
blockStates.add(player.world.getBlockState(coordinate));
}
} else {
blockStates = BuildModifiers.findBlockStates(player, startCoordinates, hitVec, sideHit, itemStacks);
}
//Check if they are different from previous //Check if they are different from previous
//TODO fix triggering when moving player //TODO fix triggering when moving player
if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) { if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) {
previousCoordinates = newCoordinates; previousCoordinates = newCoordinates;
//remember the rest for placed blocks //remember the rest for placed blocks
previousBlockStates = blockStates; previousBlockStates = blockStates;
previousItemStacks = itemStacks; previousItemStacks = itemStacks;
previousFirstPos = firstPos; previousFirstPos = firstPos;
previousSecondPos = secondPos; previousSecondPos = secondPos;
//if so, renew randomness of randomizer bag //if so, renew randomness of randomizer bag
RandomizerBagItem.renewRandomness(); ItemRandomizerBag.renewRandomness();
//and play sound (max once every tick) //and play sound (max once every tick)
if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientProxy.ticksInGame - 0) { if (newCoordinates.size() > 1 && blockStates.size() > 1 && soundTime < ClientProxy.ticksInGame - 0) {
soundTime = ClientProxy.ticksInGame; soundTime = ClientProxy.ticksInGame;
if (blockStates.get(0) != null) { if (blockStates.get(0) != null) {
SoundType soundType = blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.level, SoundType soundType = blockStates.get(0).getBlock().getSoundType(blockStates.get(0), player.world,
newCoordinates.get(0), player); newCoordinates.get(0), player);
player.level.playSound(player, player.blockPosition(), breaking ? soundType.getBreakSound() : soundType.getPlaceSound(), player.world.playSound(player, player.getPosition(), breaking ? soundType.getBreakSound() : soundType.getPlaceSound(),
SoundCategory.BLOCKS, 0.3f, 0.8f); SoundCategory.BLOCKS, 0.3f, 0.8f);
} }
} }
} }
//Render block previews //Render block previews
if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) { if (blockStates.size() != 0 && newCoordinates.size() == blockStates.size()) {
int blockCount; int blockCount;
//Use fancy shader if config allows, otherwise outlines //Use fancy shader if config allows, otherwise outlines
if (BuildConfig.visuals.useShaders.get() && newCoordinates.size() < BuildConfig.visuals.shaderTreshold.get()) { if (BuildConfig.visuals.useShaders && newCoordinates.size() < BuildConfig.visuals.shaderTreshold) {
blockCount = renderBlockPreviews(matrixStack, renderTypeBuffer, newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, !breaking, breaking);
} else {
IVertexBuilder buffer = RenderHandler.beginLines(renderTypeBuffer);
Vector3d color = new Vector3d(1f, 1f, 1f); RenderHandler.beginBlockPreviews();
if (breaking) color = new Vector3d(1f, 0f, 0f);
for (int i = newCoordinates.size() - 1; i >= 0; i--) { blockCount = renderBlockPreviews(newCoordinates, blockStates, itemStacks, 0f, firstPos, secondPos, !breaking, breaking);
VoxelShape collisionShape = blockStates.get(i).getCollisionShape(player.level, newCoordinates.get(i));
RenderHandler.renderBlockOutline(matrixStack, buffer, newCoordinates.get(i), collisionShape, color);
}
RenderHandler.endLines(renderTypeBuffer); RenderHandler.endBlockPreviews();
} else {
blockCount = newCoordinates.size(); RenderHandler.beginLines();
}
//Display block count and dimensions in actionbar Vec3d color = new Vec3d(1f, 1f, 1f);
if (BuildModes.isActive(player)) { if (breaking) color = new Vec3d(1f, 0f, 0f);
//Find min and max values (not simply firstPos and secondPos because that doesn't work with circles) for (int i = newCoordinates.size() - 1; i >= 0; i--) {
int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE; AxisAlignedBB boundingBox = blockStates.get(i).getBoundingBox(player.world, newCoordinates.get(i));
int minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE; RenderHandler.renderBlockOutline(newCoordinates.get(i), boundingBox, color);
int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE; }
for (BlockPos pos : startCoordinates) {
if (pos.getX() < minX) minX = pos.getX();
if (pos.getX() > maxX) maxX = pos.getX();
if (pos.getY() < minY) minY = pos.getY();
if (pos.getY() > maxY) maxY = pos.getY();
if (pos.getZ() < minZ) minZ = pos.getZ();
if (pos.getZ() > maxZ) maxZ = pos.getZ();
}
BlockPos dim = new BlockPos(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1);
String dimensions = "("; RenderHandler.endLines();
if (dim.getX() > 1) dimensions += dim.getX() + "x";
if (dim.getZ() > 1) dimensions += dim.getZ() + "x";
if (dim.getY() > 1) dimensions += dim.getY() + "x";
dimensions = dimensions.substring(0, dimensions.length() - 1);
if (dimensions.length() > 1) dimensions += ")";
EffortlessBuilding.log(player, blockCount + " blocks " + dimensions, true); blockCount = newCoordinates.size();
} }
}
//Display block count and dimensions in actionbar
if (BuildModes.isActive(player)) {
//Find min and max values (not simply firstPos and secondPos because that doesn't work with circles)
int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
int minY = Integer.MAX_VALUE, maxY = Integer.MIN_VALUE;
int minZ = Integer.MAX_VALUE, maxZ = Integer.MIN_VALUE;
for (BlockPos pos : startCoordinates) {
if (pos.getX() < minX) minX = pos.getX();
if (pos.getX() > maxX) maxX = pos.getX();
if (pos.getY() < minY) minY = pos.getY();
if (pos.getY() > maxY) maxY = pos.getY();
if (pos.getZ() < minZ) minZ = pos.getZ();
if (pos.getZ() > maxZ) maxZ = pos.getZ();
}
BlockPos dim = new BlockPos(maxX - minX + 1, maxY - minY + 1, maxZ - minZ + 1);
String dimensions = "(";
if (dim.getX() > 1) dimensions += dim.getX() + "x";
if (dim.getZ() > 1) dimensions += dim.getZ() + "x";
if (dim.getY() > 1) dimensions += dim.getY() + "x";
dimensions = dimensions.substring(0, dimensions.length() - 1);
if (dimensions.length() > 1) dimensions += ")";
EffortlessBuilding.log(player, blockCount + " blocks " + dimensions, true);
}
}
} }
IVertexBuilder buffer = RenderHandler.beginLines(renderTypeBuffer); RenderHandler.beginLines();
//Draw outlines if tool in hand //Draw outlines if tool in hand
//Find proper raytrace: either normal range or increased range depending on canBreakFar //Find proper raytrace: either normal range or increased range depending on canBreakFar
RayTraceResult objectMouseOver = Minecraft.getInstance().hitResult; RayTraceResult objectMouseOver = Minecraft.getMinecraft().objectMouseOver;
RayTraceResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver; RayTraceResult breakingRaytrace = ReachHelper.canBreakFar(player) ? lookingAt : objectMouseOver;
if (toolInHand && breakingRaytrace != null && breakingRaytrace.getType() == RayTraceResult.Type.BLOCK) { if (toolInHand && breakingRaytrace != null && breakingRaytrace.typeOfHit == RayTraceResult.Type.BLOCK) {
BlockRayTraceResult blockBreakingRaytrace = (BlockRayTraceResult) breakingRaytrace; List<BlockPos> breakCoordinates = BuildModifiers.findCoordinates(player, breakingRaytrace.getBlockPos());
List<BlockPos> breakCoordinates = BuildModifiers.findCoordinates(player, blockBreakingRaytrace.getBlockPos());
//Only render first outline if further than normal reach //Only render first outline if further than normal reach
boolean excludeFirst = objectMouseOver != null && objectMouseOver.getType() == RayTraceResult.Type.BLOCK; boolean excludeFirst = objectMouseOver != null && objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK;
for (int i = excludeFirst ? 1 : 0; i < breakCoordinates.size(); i++) { for (int i = excludeFirst ? 1 : 0; i < breakCoordinates.size(); i++) {
BlockPos coordinate = breakCoordinates.get(i); BlockPos coordinate = breakCoordinates.get(i);
BlockState blockState = player.level.getBlockState(coordinate); IBlockState blockState = player.world.getBlockState(coordinate);
if (!blockState.getBlock().isAir(blockState, player.level, coordinate)) { if (!blockState.getBlock().isAir(blockState, player.world, coordinate)) {
if (SurvivalHelper.canBreak(player.level, player, coordinate) || i == 0) { if (SurvivalHelper.canBreak(player.world, player, coordinate) || i == 0) {
VoxelShape collisionShape = blockState.getCollisionShape(player.level, coordinate); AxisAlignedBB boundingBox = blockState.getBoundingBox(player.world, coordinate);
RenderHandler.renderBlockOutline(matrixStack, buffer, coordinate, collisionShape, new Vector3d(0f, 0f, 0f)); RenderHandler.renderBlockOutline(coordinate, boundingBox, new Vec3d(0f, 0f, 0f));
} }
} }
} }
} }
RenderHandler.endLines(renderTypeBuffer); RenderHandler.endLines();
} }
} }
//Whether to draw any block previews or outlines //Whether to draw any block previews or outlines
public static boolean doRenderBlockPreviews(ModifierSettings modifierSettings, ModeSettings modeSettings, BlockPos startPos) { public static boolean doRenderBlockPreviews(ModifierSettings modifierSettings, ModeSettings modeSettings, BlockPos startPos) {
return modeSettings.getBuildMode() != BuildModes.BuildModeEnum.NORMAL || return modeSettings.getBuildMode() != BuildModes.BuildModeEnum.NORMAL ||
(startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) || (startPos != null && BuildModifiers.isEnabled(modifierSettings, startPos)) ||
BuildConfig.visuals.alwaysShowBlockPreview.get(); BuildConfig.visuals.alwaysShowBlockPreview;
} }
protected static int renderBlockPreviews(MatrixStack matrixStack, IRenderTypeBuffer.Impl renderTypeBuffer, List<BlockPos> coordinates, List<BlockState> blockStates, protected static int renderBlockPreviews(List<BlockPos> coordinates, List<IBlockState> blockStates,
List<ItemStack> itemStacks, float dissolve, BlockPos firstPos, List<ItemStack> itemStacks, float dissolve, BlockPos firstPos,
BlockPos secondPos, boolean checkCanPlace, boolean red) { BlockPos secondPos, boolean checkCanPlace, boolean red) {
PlayerEntity player = Minecraft.getInstance().player; EntityPlayer player = Minecraft.getMinecraft().player;
ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
BlockRendererDispatcher dispatcher = Minecraft.getInstance().getBlockRenderer(); BlockRendererDispatcher dispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher();
int blocksValid = 0; int blocksValid = 0;
if (coordinates.isEmpty()) return blocksValid; if (coordinates.isEmpty()) return blocksValid;
for (int i = coordinates.size() - 1; i >= 0; i--) { for (int i = coordinates.size() - 1; i >= 0; i--) {
BlockPos blockPos = coordinates.get(i); BlockPos blockPos = coordinates.get(i);
BlockState blockState = blockStates.get(i); IBlockState blockState = blockStates.get(i);
ItemStack itemstack = itemStacks.isEmpty() ? ItemStack.EMPTY : itemStacks.get(i); ItemStack itemstack = itemStacks.isEmpty() ? ItemStack.EMPTY : itemStacks.get(i);
if (CompatHelper.isItemBlockProxy(itemstack)) if (CompatHelper.isItemBlockProxy(itemstack))
itemstack = CompatHelper.getItemBlockByState(itemstack, blockState); itemstack = CompatHelper.getItemBlockByState(itemstack, blockState);
//Check if can place //Check if can place
//If check is turned off, check if blockstate is the same (for dissolve effect) //If check is turned off, check if blockstate is the same (for dissolve effect)
if ((!checkCanPlace /*&& player.world.getNewBlockState(blockPos) == blockState*/) || //TODO enable (breaks the breaking shader) if ((!checkCanPlace /*&& player.world.getNewBlockState(blockPos) == blockState*/) || //TODO enable (breaks breaking shader)
SurvivalHelper.canPlace(player.level, player, blockPos, blockState, itemstack, modifierSettings.doQuickReplace(), Direction.UP)) { SurvivalHelper.canPlace(player.world, player, blockPos, blockState, itemstack, modifierSettings.doQuickReplace(), EnumFacing.UP)) {
RenderHandler.renderBlockPreview(matrixStack, renderTypeBuffer, dispatcher, blockPos, blockState, dissolve, firstPos, secondPos, red); ShaderHandler.useShader(ShaderHandler.dissolve, generateShaderCallback(dissolve,
blocksValid++; new Vec3d(blockPos), new Vec3d(firstPos), new Vec3d(secondPos),
} blockPos == secondPos, red));
} RenderHandler.renderBlockPreview(dispatcher, blockPos, blockState);
return blocksValid; blocksValid++;
} }
}
return blocksValid;
}
public static void onBlocksPlaced() { public static void onBlocksPlaced() {
onBlocksPlaced(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos); onBlocksPlaced(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos);
} }
public static void onBlocksPlaced(List<BlockPos> coordinates, List<ItemStack> itemStacks, List<BlockState> blockStates, public static void onBlocksPlaced(List<BlockPos> coordinates, List<ItemStack> itemStacks, List<IBlockState> blockStates,
BlockPos firstPos, BlockPos secondPos) { BlockPos firstPos, BlockPos secondPos) {
ClientPlayerEntity player = Minecraft.getInstance().player; EntityPlayerSP player = Minecraft.getMinecraft().player;
ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Check if block previews are enabled //Check if block previews are enabled
if (doRenderBlockPreviews(modifierSettings, modeSettings, firstPos)) { if (doRenderBlockPreviews(modifierSettings, modeSettings, firstPos)) {
//Save current coordinates, blockstates and itemstacks //Save current coordinates, blockstates and itemstacks
if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() && if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() &&
coordinates.size() > 1 && coordinates.size() < BuildConfig.visuals.shaderTreshold.get()) { coordinates.size() > 1 && coordinates.size() < BuildConfig.visuals.shaderTreshold) {
placedDataList.add(new PlacedData(ClientProxy.ticksInGame, coordinates, blockStates, placedDataList.add(new PlacedData(ClientProxy.ticksInGame, coordinates, blockStates,
itemStacks, firstPos, secondPos, false)); itemStacks, firstPos, secondPos, false));
} }
} }
} }
public static void onBlocksBroken() { public static void onBlocksBroken() {
onBlocksBroken(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos); onBlocksBroken(previousCoordinates, previousItemStacks, previousBlockStates, previousFirstPos, previousSecondPos);
} }
public static void onBlocksBroken(List<BlockPos> coordinates, List<ItemStack> itemStacks, List<BlockState> blockStates, public static void onBlocksBroken(List<BlockPos> coordinates, List<ItemStack> itemStacks, List<IBlockState> blockStates,
BlockPos firstPos, BlockPos secondPos) { BlockPos firstPos, BlockPos secondPos) {
ClientPlayerEntity player = Minecraft.getInstance().player; EntityPlayerSP player = Minecraft.getMinecraft().player;
ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player);
ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player); ModeSettings modeSettings = ModeSettingsManager.getModeSettings(player);
//Check if block previews are enabled //Check if block previews are enabled
if (doRenderBlockPreviews(modifierSettings, modeSettings, firstPos)) { if (doRenderBlockPreviews(modifierSettings, modeSettings, firstPos)) {
//Save current coordinates, blockstates and itemstacks //Save current coordinates, blockstates and itemstacks
if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() && if (!coordinates.isEmpty() && blockStates.size() == coordinates.size() &&
coordinates.size() > 1 && coordinates.size() < BuildConfig.visuals.shaderTreshold.get()) { coordinates.size() > 1 && coordinates.size() < BuildConfig.visuals.shaderTreshold) {
sortOnDistanceToPlayer(coordinates, player); sortOnDistanceToPlayer(coordinates, player);
placedDataList.add(new PlacedData(ClientProxy.ticksInGame, coordinates, blockStates, placedDataList.add(new PlacedData(ClientProxy.ticksInGame, coordinates, blockStates,
itemStacks, firstPos, secondPos, true)); itemStacks, firstPos, secondPos, true));
} }
} }
} }
private static void sortOnDistanceToPlayer(List<BlockPos> coordinates, PlayerEntity player) { private static Consumer<Integer> generateShaderCallback(final float dissolve, final Vec3d blockpos,
final Vec3d firstpos, final Vec3d secondpos,
final boolean highlight, final boolean red) {
Minecraft mc = Minecraft.getMinecraft();
return (Integer shader) -> {
int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "dissolve");
int highlightUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "highlight");
int redUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "red");
int blockposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "blockpos");
int firstposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "firstpos");
int secondposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "secondpos");
int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image");
int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask");
Collections.sort(coordinates, (lhs, rhs) -> { GlStateManager.enableTexture2D();
// -1 - less than, 1 - greater than, 0 - equal GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
double lhsDistanceToPlayer = Vector3d.atLowerCornerOf(lhs).subtract(player.getEyePosition(1f)).lengthSqr();
double rhsDistanceToPlayer = Vector3d.atLowerCornerOf(rhs).subtract(player.getEyePosition(1f)).lengthSqr();
return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer);
});
} //mask
ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit);
OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(ShaderHandler.shaderMaskTextureLocation).getGlTextureId());
static class PlacedData { //image
float time; ARBShaderObjects.glUniform1iARB(imageUniform, primaryTextureUnit);
List<BlockPos> coordinates; OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + primaryTextureUnit);
List<BlockState> blockStates; GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE).getGlTextureId());
List<ItemStack> itemStacks;
BlockPos firstPos;
BlockPos secondPos;
boolean breaking;
public PlacedData(float time, List<BlockPos> coordinates, List<BlockState> blockStates, //blockpos
List<ItemStack> itemStacks, BlockPos firstPos, BlockPos secondPos, boolean breaking) { ARBShaderObjects.glUniform3fARB(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z);
this.time = time; ARBShaderObjects.glUniform3fARB(firstposUniform, (float) firstpos.x, (float) firstpos.y, (float) firstpos.z);
this.coordinates = coordinates; ARBShaderObjects.glUniform3fARB(secondposUniform, (float) secondpos.x, (float) secondpos.y, (float) secondpos.z);
this.blockStates = blockStates;
this.itemStacks = itemStacks; //dissolve
this.firstPos = firstPos; ARBShaderObjects.glUniform1fARB(percentileUniform, dissolve);
this.secondPos = secondPos; //highlight
this.breaking = breaking; ARBShaderObjects.glUniform1iARB(highlightUniform, highlight ? 1 : 0);
} //red
} ARBShaderObjects.glUniform1iARB(redUniform, red ? 1 : 0);
};
}
private static void sortOnDistanceToPlayer(List<BlockPos> coordinates, EntityPlayer player) {
Collections.sort(coordinates, (lhs, rhs) -> {
// -1 - less than, 1 - greater than, 0 - equal
double lhsDistanceToPlayer = new Vec3d(lhs).subtract(player.getPositionEyes(1f)).lengthSquared();
double rhsDistanceToPlayer = new Vec3d(rhs).subtract(player.getPositionEyes(1f)).lengthSquared();
return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer);
});
}
} }

View File

@@ -1,172 +0,0 @@
package nl.requios.effortlessbuilding.render;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderState;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import org.lwjgl.opengl.*;
import java.util.OptionalDouble;
import java.util.function.Consumer;
public class BuildRenderTypes extends RenderType {
public static final RenderType LINES;
public static final RenderType PLANES;
private static final int primaryTextureUnit = 0;
private static final int secondaryTextureUnit = 2;
static {
final LineState LINE = new LineState(OptionalDouble.of(2.0));
final int INITIAL_BUFFER_SIZE = 128;
RenderType.State renderState;
//LINES
renderState = State.builder()
.setLineState(LINE)
.setLayeringState(VIEW_OFFSET_Z_LAYERING)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setTextureState(NO_TEXTURE)
.setDepthTestState(NO_DEPTH_TEST)
.setLightmapState(NO_LIGHTMAP)
.setWriteMaskState(COLOR_DEPTH_WRITE)
.setCullState(NO_CULL)
.createCompositeState(false);
LINES = RenderType.create("eb_lines",
DefaultVertexFormats.POSITION_COLOR, GL11.GL_LINES, INITIAL_BUFFER_SIZE, false, false, renderState);
//PLANES
renderState = State.builder()
.setLineState(LINE)
.setLayeringState(VIEW_OFFSET_Z_LAYERING)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setTextureState(NO_TEXTURE)
.setDepthTestState(NO_DEPTH_TEST)
.setLightmapState(NO_LIGHTMAP)
.setWriteMaskState(COLOR_WRITE)
.setCullState(NO_CULL)
.createCompositeState(false);
PLANES = RenderType.create("eb_planes",
DefaultVertexFormats.POSITION_COLOR, GL11.GL_TRIANGLE_STRIP, INITIAL_BUFFER_SIZE, false, false, renderState);
}
// Dummy constructor needed to make java happy
public BuildRenderTypes(String p_i225992_1_, VertexFormat p_i225992_2_, int p_i225992_3_, int p_i225992_4_, boolean p_i225992_5_, boolean p_i225992_6_, Runnable p_i225992_7_, Runnable p_i225992_8_) {
super(p_i225992_1_, p_i225992_2_, p_i225992_3_, p_i225992_4_, p_i225992_5_, p_i225992_6_, p_i225992_7_, p_i225992_8_);
}
public static RenderType getBlockPreviewRenderType(float dissolve, BlockPos blockPos, BlockPos firstPos,
BlockPos secondPos, boolean red) {
// RenderSystem.pushLightingAttributes();
// RenderSystem.pushTextureAttributes();
// RenderSystem.enableCull();
// RenderSystem.enableTexture();
// Minecraft.getInstance().textureManager.bindTexture(ShaderHandler.shaderMaskTextureLocation);
//
// RenderSystem.enableBlend();
// RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// RenderSystem.blendColor(1f, 1f, 1f, 0.8f);
//end
// ShaderHandler.releaseShader();
//highjacking texturing state (which does nothing by default) to do my own things
String stateName = "eb_texturing_" + dissolve + "_" + blockPos + "_" + firstPos + "_" + secondPos + "_" + red;
TexturingState MY_TEXTURING = new TexturingState(stateName, () -> {
// RenderSystem.pushLightingAttributes();
// RenderSystem.pushTextureAttributes();
ShaderHandler.useShader(ShaderHandler.dissolve, generateShaderCallback(dissolve, Vector3d.atLowerCornerOf(blockPos), Vector3d.atLowerCornerOf(firstPos), Vector3d.atLowerCornerOf(secondPos), blockPos == secondPos, red));
RenderSystem.blendColor(1f, 1f, 1f, 0.8f);
}, ShaderHandler::releaseShader);
RenderType.State renderState = RenderType.State.builder()
.setTextureState(new TextureState(ShaderHandler.shaderMaskTextureLocation, false, false))
.setTexturingState(MY_TEXTURING)
.setTransparencyState(TRANSLUCENT_TRANSPARENCY)
.setDiffuseLightingState(NO_DIFFUSE_LIGHTING)
.setAlphaState(DEFAULT_ALPHA)
.setCullState(new CullState(true))
.setLightmapState(new LightmapState(false))
.setOverlayState(new OverlayState(false))
.createCompositeState(true);
//Unique name for every combination, otherwise it will reuse the previous one
String name = "eb_block_previews_" + dissolve + "_" + blockPos + "_" + firstPos + "_" + secondPos + "_" + red;
return RenderType.create(name,
DefaultVertexFormats.BLOCK, GL11.GL_QUADS, 256, true, true, renderState);
}
private static Consumer<Integer> generateShaderCallback(final float dissolve, final Vector3d blockpos,
final Vector3d firstpos, final Vector3d secondpos,
final boolean highlight, final boolean red) {
Minecraft mc = Minecraft.getInstance();
return (Integer shader) -> {
int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "dissolve");
int highlightUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "highlight");
int redUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "red");
int blockposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "blockpos");
int firstposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "firstpos");
int secondposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "secondpos");
int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image");
int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask");
RenderSystem.enableTexture();
GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
//mask
ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit);
glActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit);
mc.getTextureManager().bind(ShaderHandler.shaderMaskTextureLocation);//getTexture(ShaderHandler.shaderMaskTextureLocation).bindTexture();
//GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.getTextureManager().getTexture(ShaderHandler.shaderMaskTextureLocation).getGlTextureId());
//image
ARBShaderObjects.glUniform1iARB(imageUniform, primaryTextureUnit);
glActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + primaryTextureUnit);
mc.getTextureManager().bind(AtlasTexture.LOCATION_BLOCKS);//.getTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE).bindTexture();
//GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.getTextureManager().getTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE).getGlTextureId());
//blockpos
ARBShaderObjects.glUniform3fARB(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z);
ARBShaderObjects.glUniform3fARB(firstposUniform, (float) firstpos.x, (float) firstpos.y, (float) firstpos.z);
ARBShaderObjects.glUniform3fARB(secondposUniform, (float) secondpos.x, (float) secondpos.y, (float) secondpos.z);
//dissolve
ARBShaderObjects.glUniform1fARB(percentileUniform, dissolve);
//highlight
ARBShaderObjects.glUniform1iARB(highlightUniform, highlight ? 1 : 0);
//red
ARBShaderObjects.glUniform1iARB(redUniform, red ? 1 : 0);
};
}
public static void glActiveTexture(int texture) {
if (GL.getCapabilities().GL_ARB_multitexture && !GL.getCapabilities().OpenGL13) {
ARBMultitexture.glActiveTextureARB(texture);
} else {
GL13.glActiveTexture(texture);
}
}
private class ShaderInfo {
float dissolve;
Vector3d blockPos;
Vector3d firstPos;
Vector3d secondPos;
boolean red;
public ShaderInfo(float dissolve, Vector3d blockPos, Vector3d firstPos, Vector3d secondPos, boolean red) {
this.dissolve = dissolve;
this.blockPos = blockPos;
this.firstPos = firstPos;
this.secondPos = secondPos;
this.red = red;
}
}
}

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