Compare commits
No commits in common. "main" and "1.0.4" have entirely different histories.
549
LICENSE
549
LICENSE
@ -1,428 +1,121 @@
|
|||||||
Attribution-ShareAlike 4.0 International
|
Creative Commons Legal Code
|
||||||
|
|
||||||
=======================================================================
|
CC0 1.0 Universal
|
||||||
|
|
||||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||||
does not provide legal services or legal advice. Distribution of
|
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||||
Creative Commons public licenses does not create a lawyer-client or
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||||
other relationship. Creative Commons makes its licenses and related
|
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||||
information available on an "as-is" basis. Creative Commons gives no
|
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||||
warranties regarding its licenses, any material licensed under their
|
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||||
terms and conditions, or any related information. Creative Commons
|
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||||
disclaims all liability for damages resulting from their use to the
|
HEREUNDER.
|
||||||
fullest extent possible.
|
|
||||||
|
Statement of Purpose
|
||||||
Using Creative Commons Public Licenses
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer
|
||||||
Creative Commons public licenses provide a standard set of terms and
|
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||||
conditions that creators and other rights holders may use to share
|
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||||
original works of authorship and other material subject to copyright
|
authorship and/or a database (each, a "Work").
|
||||||
and certain other rights specified in the public license below. The
|
|
||||||
following considerations are for informational purposes only, are not
|
Certain owners wish to permanently relinquish those rights to a Work for
|
||||||
exhaustive, and do not form part of our licenses.
|
the purpose of contributing to a commons of creative, cultural and
|
||||||
|
scientific works ("Commons") that the public can reliably and without fear
|
||||||
Considerations for licensors: Our public licenses are
|
of later claims of infringement build upon, modify, incorporate in other
|
||||||
intended for use by those authorized to give the public
|
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||||
permission to use material in ways otherwise restricted by
|
and for any purposes, including without limitation commercial purposes.
|
||||||
copyright and certain other rights. Our licenses are
|
These owners may contribute to the Commons to promote the ideal of a free
|
||||||
irrevocable. Licensors should read and understand the terms
|
culture and the further production of creative, cultural and scientific
|
||||||
and conditions of the license they choose before applying it.
|
works, or to gain reputation or greater distribution for their Work in
|
||||||
Licensors should also secure all rights necessary before
|
part through the use and efforts of others.
|
||||||
applying our licenses so that the public can reuse the
|
|
||||||
material as expected. Licensors should clearly mark any
|
For these and/or other purposes and motivations, and without any
|
||||||
material not subject to the license. This includes other CC-
|
expectation of additional consideration or compensation, the person
|
||||||
licensed material, or material used under an exception or
|
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||||
limitation to copyright. More considerations for licensors:
|
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||||
wiki.creativecommons.org/Considerations_for_licensors
|
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||||
|
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||||
Considerations for the public: By using one of our public
|
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||||
licenses, a licensor grants the public permission to use the
|
|
||||||
licensed material under specified terms and conditions. If
|
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||||
the licensor's permission is not necessary for any reason--for
|
protected by copyright and related or neighboring rights ("Copyright and
|
||||||
example, because of any applicable exception or limitation to
|
Related Rights"). Copyright and Related Rights include, but are not
|
||||||
copyright--then that use is not regulated by the license. Our
|
limited to, the following:
|
||||||
licenses grant only permissions under copyright and certain
|
|
||||||
other rights that a licensor has authority to grant. Use of
|
i. the right to reproduce, adapt, distribute, perform, display,
|
||||||
the licensed material may still be restricted for other
|
communicate, and translate a Work;
|
||||||
reasons, including because others have copyright or other
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
rights in the material. A licensor may make special requests,
|
iii. publicity and privacy rights pertaining to a person's image or
|
||||||
such as asking that all changes be marked or described.
|
likeness depicted in a Work;
|
||||||
Although not required by our licenses, you are encouraged to
|
iv. rights protecting against unfair competition in regards to a Work,
|
||||||
respect those requests where reasonable. More considerations
|
subject to the limitations in paragraph 4(a), below;
|
||||||
for the public:
|
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||||
wiki.creativecommons.org/Considerations_for_licensees
|
in a Work;
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||||
=======================================================================
|
European Parliament and of the Council of 11 March 1996 on the legal
|
||||||
|
protection of databases, and under any national implementation
|
||||||
Creative Commons Attribution-ShareAlike 4.0 International Public
|
thereof, including any amended or successor version of such
|
||||||
License
|
directive); and
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the
|
||||||
By exercising the Licensed Rights (defined below), You accept and agree
|
world based on applicable law or treaty, and any national
|
||||||
to be bound by the terms and conditions of this Creative Commons
|
implementations thereof.
|
||||||
Attribution-ShareAlike 4.0 International Public License ("Public
|
|
||||||
License"). To the extent this Public License may be interpreted as a
|
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||||
contract, You are granted the Licensed Rights in consideration of Your
|
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||||
acceptance of these terms and conditions, and the Licensor grants You
|
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||||
such rights in consideration of benefits the Licensor receives from
|
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||||
making the Licensed Material available under these terms and
|
of action, whether now known or unknown (including existing as well as
|
||||||
conditions.
|
future claims and causes of action), in the Work (i) in all territories
|
||||||
|
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||||
|
treaty (including future time extensions), (iii) in any current or future
|
||||||
Section 1 -- Definitions.
|
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||||
|
including without limitation commercial, advertising or promotional
|
||||||
a. Adapted Material means material subject to Copyright and Similar
|
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||||
Rights that is derived from or based upon the Licensed Material
|
member of the public at large and to the detriment of Affirmer's heirs and
|
||||||
and in which the Licensed Material is translated, altered,
|
successors, fully intending that such Waiver shall not be subject to
|
||||||
arranged, transformed, or otherwise modified in a manner requiring
|
revocation, rescission, cancellation, termination, or any other legal or
|
||||||
permission under the Copyright and Similar Rights held by the
|
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||||
Licensor. For purposes of this Public License, where the Licensed
|
as contemplated by Affirmer's express Statement of Purpose.
|
||||||
Material is a musical work, performance, or sound recording,
|
|
||||||
Adapted Material is always produced where the Licensed Material is
|
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||||
synched in timed relation with a moving image.
|
be judged legally invalid or ineffective under applicable law, then the
|
||||||
|
Waiver shall be preserved to the maximum extent permitted taking into
|
||||||
b. Adapter's License means the license You apply to Your Copyright
|
account Affirmer's express Statement of Purpose. In addition, to the
|
||||||
and Similar Rights in Your contributions to Adapted Material in
|
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||||
accordance with the terms and conditions of this Public License.
|
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||||
|
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||||
c. BY-SA Compatible License means a license listed at
|
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||||
creativecommons.org/compatiblelicenses, approved by Creative
|
maximum duration provided by applicable law or treaty (including future
|
||||||
Commons as essentially the equivalent of this Public License.
|
time extensions), (iii) in any current or future medium and for any number
|
||||||
|
of copies, and (iv) for any purpose whatsoever, including without
|
||||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
limitation commercial, advertising or promotional purposes (the
|
||||||
closely related to copyright including, without limitation,
|
"License"). The License shall be deemed effective as of the date CC0 was
|
||||||
performance, broadcast, sound recording, and Sui Generis Database
|
applied by Affirmer to the Work. Should any part of the License for any
|
||||||
Rights, without regard to how the rights are labeled or
|
reason be judged legally invalid or ineffective under applicable law, such
|
||||||
categorized. For purposes of this Public License, the rights
|
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
of the License, and in such case Affirmer hereby affirms that he or she
|
||||||
Rights.
|
will not (i) exercise any of his or her remaining Copyright and Related
|
||||||
|
Rights in the Work or (ii) assert any associated claims and causes of
|
||||||
e. Effective Technological Measures means those measures that, in the
|
action with respect to the Work, in either case contrary to Affirmer's
|
||||||
absence of proper authority, may not be circumvented under laws
|
express Statement of Purpose.
|
||||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
|
||||||
Treaty adopted on December 20, 1996, and/or similar international
|
4. Limitations and Disclaimers.
|
||||||
agreements.
|
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
surrendered, licensed or otherwise affected by this document.
|
||||||
any other exception or limitation to Copyright and Similar Rights
|
b. Affirmer offers the Work as-is and makes no representations or
|
||||||
that applies to Your use of the Licensed Material.
|
warranties of any kind concerning the Work, express, implied,
|
||||||
|
statutory or otherwise, including without limitation warranties of
|
||||||
g. License Elements means the license attributes listed in the name
|
title, merchantability, fitness for a particular purpose, non
|
||||||
of a Creative Commons Public License. The License Elements of this
|
infringement, or the absence of latent or other defects, accuracy, or
|
||||||
Public License are Attribution and ShareAlike.
|
the present or absence of errors, whether or not discoverable, all to
|
||||||
|
the greatest extent permissible under applicable law.
|
||||||
h. Licensed Material means the artistic or literary work, database,
|
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||||
or other material to which the Licensor applied this Public
|
that may apply to the Work or any use thereof, including without
|
||||||
License.
|
limitation any person's Copyright and Related Rights in the Work.
|
||||||
|
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||||
i. Licensed Rights means the rights granted to You subject to the
|
consents, permissions or other rights required for any use of the
|
||||||
terms and conditions of this Public License, which are limited to
|
Work.
|
||||||
all Copyright and Similar Rights that apply to Your use of the
|
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||||
Licensed Material and that the Licensor has authority to license.
|
party to this document and has no duty or obligation with respect to
|
||||||
|
this CC0 or use of the Work.
|
||||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
|
||||||
under this Public License.
|
|
||||||
|
|
||||||
k. Share means to provide material to the public by any means or
|
|
||||||
process that requires permission under the Licensed Rights, such
|
|
||||||
as reproduction, public display, public performance, distribution,
|
|
||||||
dissemination, communication, or importation, and to make material
|
|
||||||
available to the public including in ways that members of the
|
|
||||||
public may access the material from a place and at a time
|
|
||||||
individually chosen by them.
|
|
||||||
|
|
||||||
l. Sui Generis Database Rights means rights other than copyright
|
|
||||||
resulting from Directive 96/9/EC of the European Parliament and of
|
|
||||||
the Council of 11 March 1996 on the legal protection of databases,
|
|
||||||
as amended and/or succeeded, as well as other essentially
|
|
||||||
equivalent rights anywhere in the world.
|
|
||||||
|
|
||||||
m. You means the individual or entity exercising the Licensed Rights
|
|
||||||
under this Public License. Your has a corresponding meaning.
|
|
||||||
|
|
||||||
|
|
||||||
Section 2 -- Scope.
|
|
||||||
|
|
||||||
a. License grant.
|
|
||||||
|
|
||||||
1. Subject to the terms and conditions of this Public License,
|
|
||||||
the Licensor hereby grants You a worldwide, royalty-free,
|
|
||||||
non-sublicensable, non-exclusive, irrevocable license to
|
|
||||||
exercise the Licensed Rights in the Licensed Material to:
|
|
||||||
|
|
||||||
a. reproduce and Share the Licensed Material, in whole or
|
|
||||||
in part; and
|
|
||||||
|
|
||||||
b. produce, reproduce, and Share Adapted Material.
|
|
||||||
|
|
||||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
|
||||||
Exceptions and Limitations apply to Your use, this Public
|
|
||||||
License does not apply, and You do not need to comply with
|
|
||||||
its terms and conditions.
|
|
||||||
|
|
||||||
3. Term. The term of this Public License is specified in Section
|
|
||||||
6(a).
|
|
||||||
|
|
||||||
4. Media and formats; technical modifications allowed. The
|
|
||||||
Licensor authorizes You to exercise the Licensed Rights in
|
|
||||||
all media and formats whether now known or hereafter created,
|
|
||||||
and to make technical modifications necessary to do so. The
|
|
||||||
Licensor waives and/or agrees not to assert any right or
|
|
||||||
authority to forbid You from making technical modifications
|
|
||||||
necessary to exercise the Licensed Rights, including
|
|
||||||
technical modifications necessary to circumvent Effective
|
|
||||||
Technological Measures. For purposes of this Public License,
|
|
||||||
simply making modifications authorized by this Section 2(a)
|
|
||||||
(4) never produces Adapted Material.
|
|
||||||
|
|
||||||
5. Downstream recipients.
|
|
||||||
|
|
||||||
a. Offer from the Licensor -- Licensed Material. Every
|
|
||||||
recipient of the Licensed Material automatically
|
|
||||||
receives an offer from the Licensor to exercise the
|
|
||||||
Licensed Rights under the terms and conditions of this
|
|
||||||
Public License.
|
|
||||||
|
|
||||||
b. Additional offer from the Licensor -- Adapted Material.
|
|
||||||
Every recipient of Adapted Material from You
|
|
||||||
automatically receives an offer from the Licensor to
|
|
||||||
exercise the Licensed Rights in the Adapted Material
|
|
||||||
under the conditions of the Adapter's License You apply.
|
|
||||||
|
|
||||||
c. No downstream restrictions. You may not offer or impose
|
|
||||||
any additional or different terms or conditions on, or
|
|
||||||
apply any Effective Technological Measures to, the
|
|
||||||
Licensed Material if doing so restricts exercise of the
|
|
||||||
Licensed Rights by any recipient of the Licensed
|
|
||||||
Material.
|
|
||||||
|
|
||||||
6. No endorsement. Nothing in this Public License constitutes or
|
|
||||||
may be construed as permission to assert or imply that You
|
|
||||||
are, or that Your use of the Licensed Material is, connected
|
|
||||||
with, or sponsored, endorsed, or granted official status by,
|
|
||||||
the Licensor or others designated to receive attribution as
|
|
||||||
provided in Section 3(a)(1)(A)(i).
|
|
||||||
|
|
||||||
b. Other rights.
|
|
||||||
|
|
||||||
1. Moral rights, such as the right of integrity, are not
|
|
||||||
licensed under this Public License, nor are publicity,
|
|
||||||
privacy, and/or other similar personality rights; however, to
|
|
||||||
the extent possible, the Licensor waives and/or agrees not to
|
|
||||||
assert any such rights held by the Licensor to the limited
|
|
||||||
extent necessary to allow You to exercise the Licensed
|
|
||||||
Rights, but not otherwise.
|
|
||||||
|
|
||||||
2. Patent and trademark rights are not licensed under this
|
|
||||||
Public License.
|
|
||||||
|
|
||||||
3. To the extent possible, the Licensor waives any right to
|
|
||||||
collect royalties from You for the exercise of the Licensed
|
|
||||||
Rights, whether directly or through a collecting society
|
|
||||||
under any voluntary or waivable statutory or compulsory
|
|
||||||
licensing scheme. In all other cases the Licensor expressly
|
|
||||||
reserves any right to collect such royalties.
|
|
||||||
|
|
||||||
|
|
||||||
Section 3 -- License Conditions.
|
|
||||||
|
|
||||||
Your exercise of the Licensed Rights is expressly made subject to the
|
|
||||||
following conditions.
|
|
||||||
|
|
||||||
a. Attribution.
|
|
||||||
|
|
||||||
1. If You Share the Licensed Material (including in modified
|
|
||||||
form), You must:
|
|
||||||
|
|
||||||
a. retain the following if it is supplied by the Licensor
|
|
||||||
with the Licensed Material:
|
|
||||||
|
|
||||||
i. identification of the creator(s) of the Licensed
|
|
||||||
Material and any others designated to receive
|
|
||||||
attribution, in any reasonable manner requested by
|
|
||||||
the Licensor (including by pseudonym if
|
|
||||||
designated);
|
|
||||||
|
|
||||||
ii. a copyright notice;
|
|
||||||
|
|
||||||
iii. a notice that refers to this Public License;
|
|
||||||
|
|
||||||
iv. a notice that refers to the disclaimer of
|
|
||||||
warranties;
|
|
||||||
|
|
||||||
v. a URI or hyperlink to the Licensed Material to the
|
|
||||||
extent reasonably practicable;
|
|
||||||
|
|
||||||
b. indicate if You modified the Licensed Material and
|
|
||||||
retain an indication of any previous modifications; and
|
|
||||||
|
|
||||||
c. indicate the Licensed Material is licensed under this
|
|
||||||
Public License, and include the text of, or the URI or
|
|
||||||
hyperlink to, this Public License.
|
|
||||||
|
|
||||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
|
||||||
reasonable manner based on the medium, means, and context in
|
|
||||||
which You Share the Licensed Material. For example, it may be
|
|
||||||
reasonable to satisfy the conditions by providing a URI or
|
|
||||||
hyperlink to a resource that includes the required
|
|
||||||
information.
|
|
||||||
|
|
||||||
3. If requested by the Licensor, You must remove any of the
|
|
||||||
information required by Section 3(a)(1)(A) to the extent
|
|
||||||
reasonably practicable.
|
|
||||||
|
|
||||||
b. ShareAlike.
|
|
||||||
|
|
||||||
In addition to the conditions in Section 3(a), if You Share
|
|
||||||
Adapted Material You produce, the following conditions also apply.
|
|
||||||
|
|
||||||
1. The Adapter's License You apply must be a Creative Commons
|
|
||||||
license with the same License Elements, this version or
|
|
||||||
later, or a BY-SA Compatible License.
|
|
||||||
|
|
||||||
2. You must include the text of, or the URI or hyperlink to, the
|
|
||||||
Adapter's License You apply. You may satisfy this condition
|
|
||||||
in any reasonable manner based on the medium, means, and
|
|
||||||
context in which You Share Adapted Material.
|
|
||||||
|
|
||||||
3. You may not offer or impose any additional or different terms
|
|
||||||
or conditions on, or apply any Effective Technological
|
|
||||||
Measures to, Adapted Material that restrict exercise of the
|
|
||||||
rights granted under the Adapter's License You apply.
|
|
||||||
|
|
||||||
|
|
||||||
Section 4 -- Sui Generis Database Rights.
|
|
||||||
|
|
||||||
Where the Licensed Rights include Sui Generis Database Rights that
|
|
||||||
apply to Your use of the Licensed Material:
|
|
||||||
|
|
||||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
|
||||||
to extract, reuse, reproduce, and Share all or a substantial
|
|
||||||
portion of the contents of the database;
|
|
||||||
|
|
||||||
b. if You include all or a substantial portion of the database
|
|
||||||
contents in a database in which You have Sui Generis Database
|
|
||||||
Rights, then the database in which You have Sui Generis Database
|
|
||||||
Rights (but not its individual contents) is Adapted Material,
|
|
||||||
including for purposes of Section 3(b); and
|
|
||||||
|
|
||||||
c. You must comply with the conditions in Section 3(a) if You Share
|
|
||||||
all or a substantial portion of the contents of the database.
|
|
||||||
|
|
||||||
For the avoidance of doubt, this Section 4 supplements and does not
|
|
||||||
replace Your obligations under this Public License where the Licensed
|
|
||||||
Rights include other Copyright and Similar Rights.
|
|
||||||
|
|
||||||
|
|
||||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
|
||||||
|
|
||||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
|
||||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
|
||||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
|
||||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
|
||||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
|
||||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
|
||||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
|
||||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
|
||||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
|
||||||
|
|
||||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
|
||||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
|
||||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
|
||||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
|
||||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
|
||||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
|
||||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
|
||||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
|
||||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
|
||||||
|
|
||||||
c. The disclaimer of warranties and limitation of liability provided
|
|
||||||
above shall be interpreted in a manner that, to the extent
|
|
||||||
possible, most closely approximates an absolute disclaimer and
|
|
||||||
waiver of all liability.
|
|
||||||
|
|
||||||
|
|
||||||
Section 6 -- Term and Termination.
|
|
||||||
|
|
||||||
a. This Public License applies for the term of the Copyright and
|
|
||||||
Similar Rights licensed here. However, if You fail to comply with
|
|
||||||
this Public License, then Your rights under this Public License
|
|
||||||
terminate automatically.
|
|
||||||
|
|
||||||
b. Where Your right to use the Licensed Material has terminated under
|
|
||||||
Section 6(a), it reinstates:
|
|
||||||
|
|
||||||
1. automatically as of the date the violation is cured, provided
|
|
||||||
it is cured within 30 days of Your discovery of the
|
|
||||||
violation; or
|
|
||||||
|
|
||||||
2. upon express reinstatement by the Licensor.
|
|
||||||
|
|
||||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
|
||||||
right the Licensor may have to seek remedies for Your violations
|
|
||||||
of this Public License.
|
|
||||||
|
|
||||||
c. For the avoidance of doubt, the Licensor may also offer the
|
|
||||||
Licensed Material under separate terms or conditions or stop
|
|
||||||
distributing the Licensed Material at any time; however, doing so
|
|
||||||
will not terminate this Public License.
|
|
||||||
|
|
||||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
|
||||||
License.
|
|
||||||
|
|
||||||
|
|
||||||
Section 7 -- Other Terms and Conditions.
|
|
||||||
|
|
||||||
a. The Licensor shall not be bound by any additional or different
|
|
||||||
terms or conditions communicated by You unless expressly agreed.
|
|
||||||
|
|
||||||
b. Any arrangements, understandings, or agreements regarding the
|
|
||||||
Licensed Material not stated herein are separate from and
|
|
||||||
independent of the terms and conditions of this Public License.
|
|
||||||
|
|
||||||
|
|
||||||
Section 8 -- Interpretation.
|
|
||||||
|
|
||||||
a. For the avoidance of doubt, this Public License does not, and
|
|
||||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
|
||||||
conditions on any use of the Licensed Material that could lawfully
|
|
||||||
be made without permission under this Public License.
|
|
||||||
|
|
||||||
b. To the extent possible, if any provision of this Public License is
|
|
||||||
deemed unenforceable, it shall be automatically reformed to the
|
|
||||||
minimum extent necessary to make it enforceable. If the provision
|
|
||||||
cannot be reformed, it shall be severed from this Public License
|
|
||||||
without affecting the enforceability of the remaining terms and
|
|
||||||
conditions.
|
|
||||||
|
|
||||||
c. No term or condition of this Public License will be waived and no
|
|
||||||
failure to comply consented to unless expressly agreed to by the
|
|
||||||
Licensor.
|
|
||||||
|
|
||||||
d. Nothing in this Public License constitutes or may be interpreted
|
|
||||||
as a limitation upon, or waiver of, any privileges and immunities
|
|
||||||
that apply to the Licensor or You, including from the legal
|
|
||||||
processes of any jurisdiction or authority.
|
|
||||||
|
|
||||||
|
|
||||||
=======================================================================
|
|
||||||
|
|
||||||
Creative Commons is not a party to its public
|
|
||||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
|
||||||
its public licenses to material it publishes and in those instances
|
|
||||||
will be considered the “Licensor.” The text of the Creative Commons
|
|
||||||
public licenses is dedicated to the public domain under the CC0 Public
|
|
||||||
Domain Dedication. Except for the limited purpose of indicating that
|
|
||||||
material is shared under a Creative Commons public license or as
|
|
||||||
otherwise permitted by the Creative Commons policies published at
|
|
||||||
creativecommons.org/policies, Creative Commons does not authorize the
|
|
||||||
use of the trademark "Creative Commons" or any other trademark or logo
|
|
||||||
of Creative Commons without its prior written consent including,
|
|
||||||
without limitation, in connection with any unauthorized modifications
|
|
||||||
to any of its public licenses or any other arrangements,
|
|
||||||
understandings, or agreements concerning use of licensed material. For
|
|
||||||
the avoidance of doubt, this paragraph does not form part of the
|
|
||||||
public licenses.
|
|
||||||
|
|
||||||
Creative Commons may be contacted at creativecommons.org.
|
|
||||||
|
|
||||||
|
23
README.md
23
README.md
@ -6,8 +6,6 @@ This mod can record your movements and play them back.
|
|||||||
|
|
||||||
## Controls
|
## Controls
|
||||||
|
|
||||||
Default Repeating Mod keys
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Menu | J
|
Menu | J
|
||||||
Toggle recording | not specified
|
Toggle recording | not specified
|
||||||
@ -16,23 +14,4 @@ Toggle replay | not specified
|
|||||||
|
|
||||||
## Menu
|
## Menu
|
||||||
|
|
||||||
How menu looks like
|

|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Todo
|
|
||||||
Releases dont have striked lines
|
|
||||||
|
|
||||||
- record gui mouse clicks and key pressing (in dev)
|
|
||||||
- create new preview.gif
|
|
||||||
- practice mode like in geometry dash for parkours
|
|
||||||
|
|
||||||
## How to build
|
|
||||||
|
|
||||||
How to build mod from source
|
|
||||||
|
|
||||||
```
|
|
||||||
gradlew build
|
|
||||||
```
|
|
||||||
|
|
||||||
Compiled .jar file you can find in `build/libs`
|
|
||||||
|
39
build.gradle
39
build.gradle
@ -1,31 +1,22 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'fabric-loom' version '1.6-SNAPSHOT'
|
id 'fabric-loom' version '1.1-SNAPSHOT'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
}
|
}
|
||||||
|
|
||||||
version = project.mod_version
|
version = project.mod_version
|
||||||
group = project.maven_group
|
group = project.maven_group
|
||||||
|
|
||||||
base {
|
|
||||||
archivesName = project.archives_base_name
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
// Add repositories to retrieve artifacts from in here.
|
// Add repositories to retrieve artifacts from in here.
|
||||||
// You should only use this when depending on other mods because
|
// You should only use this when depending on other mods because
|
||||||
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||||
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||||
// for more information about repositories.
|
// for more information about repositories.
|
||||||
|
maven { url 'https://maven.wispforest.io' }
|
||||||
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly 'org.projectlombok:lombok:1.18.24'
|
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.18.24'
|
|
||||||
|
|
||||||
//add joml
|
|
||||||
modImplementation 'org.joml:joml:1.10.4'
|
|
||||||
include 'org.joml:joml:1.10.4'
|
|
||||||
|
|
||||||
// To change the versions see the gradle.properties file
|
// To change the versions see the gradle.properties file
|
||||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||||
@ -34,6 +25,22 @@ dependencies {
|
|||||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
|
|
||||||
|
// Uncomment the following line to enable the deprecated Fabric API modules.
|
||||||
|
// These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time.
|
||||||
|
|
||||||
|
// modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
|
||||||
|
|
||||||
|
modImplementation "io.wispforest:owo-lib:${project.owo_version}"
|
||||||
|
// only if you plan to use owo-config
|
||||||
|
annotationProcessor "io.wispforest:owo-lib:${project.owo_version}"
|
||||||
|
|
||||||
|
// include this if you don't want force your users to install owo
|
||||||
|
// sentinel will warn them and give the option to download it automatically
|
||||||
|
include "io.wispforest:owo-sentinel:${project.owo_version}"
|
||||||
|
}
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = project.archives_base_name
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
@ -45,6 +52,7 @@ processResources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
// Minecraft 1.18 (1.18-pre2) upwards uses Java 17.
|
||||||
it.options.release = 17
|
it.options.release = 17
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,15 +68,14 @@ java {
|
|||||||
|
|
||||||
jar {
|
jar {
|
||||||
from("LICENSE") {
|
from("LICENSE") {
|
||||||
rename { "${it}_${project.base.archivesName.get()}"}
|
rename { "${it}_${base.archivesName.get()}"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure the maven publication
|
// configure the maven publication
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
create("mavenJava", MavenPublication) {
|
mavenJava(MavenPublication) {
|
||||||
artifactId = project.archives_base_name
|
|
||||||
from components.java
|
from components.java
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,4 +87,4 @@ publishing {
|
|||||||
// The repositories here will be used for publishing your artifact, not for
|
// The repositories here will be used for publishing your artifact, not for
|
||||||
// retrieving dependencies.
|
// retrieving dependencies.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
# Done to increase the memory available to gradle.
|
# Done to increase the memory available to gradle.
|
||||||
org.gradle.jvmargs=-Xmx1G
|
org.gradle.jvmargs=-Xmx1G
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|
||||||
# Fabric Properties
|
# Fabric Properties
|
||||||
# check these on https://fabricmc.net/develop
|
# check these on https://fabricmc.net/develop
|
||||||
minecraft_version=1.20.1
|
minecraft_version=1.19.3
|
||||||
yarn_mappings=1.20.1+build.3
|
yarn_mappings=1.19.3+build.1
|
||||||
loader_version=0.15.10
|
loader_version=0.14.17
|
||||||
|
|
||||||
#Fabric api
|
# Mod Properties
|
||||||
fabric_version=0.97.0+1.20.4
|
mod_version = 1.0.4
|
||||||
|
maven_group = themixray.repeating.mod
|
||||||
# Mod Properties
|
archives_base_name = repeating-mod
|
||||||
mod_version = 1.1.2+1.20.1
|
|
||||||
maven_group = themixray.repeating.mod
|
# Dependencies
|
||||||
archives_base_name = repeating-mod
|
fabric_version=0.76.1+1.19.3
|
||||||
|
|
||||||
|
owo_version=0.10.3+1.19.3
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,7 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
29
gradlew
vendored
Normal file → Executable file
29
gradlew
vendored
Normal file → Executable file
@ -83,8 +83,10 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@ -131,13 +133,10 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
if ! command -v java >/dev/null 2>&1
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
then
|
|
||||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
@ -145,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@ -153,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@ -198,15 +197,11 @@ if "$cygwin" || "$msys" ; then
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
# Collect all arguments for the java command:
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
|
||||||
# and any embedded shellness will be escaped.
|
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
|
||||||
# treated as '${Hostname}' itself on the command line.
|
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
20
gradlew.bat
vendored
20
gradlew.bat
vendored
@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
name = 'Fabric'
|
name = 'Fabric'
|
||||||
url = 'https://maven.fabricmc.net/'
|
url = 'https://maven.fabricmc.net/'
|
||||||
}
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,103 +1,103 @@
|
|||||||
package themixray.repeating.mod;
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public class EasyConfig {
|
public class EasyConfig {
|
||||||
public final Path path;
|
public final Path path;
|
||||||
public final File file;
|
public final File file;
|
||||||
public Map<String,String> data;
|
public Map<String,String> data;
|
||||||
|
|
||||||
public EasyConfig(File f, Map<String,String> def) {
|
public EasyConfig(File f, Map<String,String> def) {
|
||||||
this.path = f.toPath();
|
this.path = f.toPath();
|
||||||
this.file = f;
|
this.file = f;
|
||||||
this.data = new HashMap<>();
|
this.data = new HashMap<>();
|
||||||
|
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
try {
|
try {
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
write(def);
|
write(def);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reload();
|
reload();
|
||||||
|
|
||||||
for (Map.Entry<String,String> m:def.entrySet())
|
for (Map.Entry<String,String> m:def.entrySet())
|
||||||
if (!data.containsKey(m.getKey()))
|
if (!data.containsKey(m.getKey()))
|
||||||
data.put(m.getKey(),m.getValue());
|
data.put(m.getKey(),m.getValue());
|
||||||
|
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
public EasyConfig(Path f, Map<String,String> def) {
|
public EasyConfig(Path f, Map<String,String> def) {
|
||||||
this(f.toFile(),def);
|
this(f.toFile(),def);
|
||||||
}
|
}
|
||||||
public EasyConfig(String parent,String child,Map<String,String> def) {
|
public EasyConfig(String parent,String child,Map<String,String> def) {
|
||||||
this(new File(parent,child),def);
|
this(new File(parent,child),def);
|
||||||
}
|
}
|
||||||
public EasyConfig(File parent,String child,Map<String,String> def) {
|
public EasyConfig(File parent,String child,Map<String,String> def) {
|
||||||
this(new File(parent,child),def);
|
this(new File(parent,child),def);
|
||||||
}
|
}
|
||||||
public EasyConfig(Path parent,String child,Map<String,String> def) {
|
public EasyConfig(Path parent,String child,Map<String,String> def) {
|
||||||
this(new File(parent.toFile(),child),def);
|
this(new File(parent.toFile(),child),def);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EasyConfig(File f) {
|
public EasyConfig(File f) {
|
||||||
this(f,new HashMap<>());
|
this(f,new HashMap<>());
|
||||||
}
|
}
|
||||||
public EasyConfig(Path path) {
|
public EasyConfig(Path path) {
|
||||||
this(path.toFile(),new HashMap<>());
|
this(path.toFile(),new HashMap<>());
|
||||||
}
|
}
|
||||||
public EasyConfig(String parent,String child) {
|
public EasyConfig(String parent,String child) {
|
||||||
this(new File(parent,child),new HashMap<>());
|
this(new File(parent,child),new HashMap<>());
|
||||||
}
|
}
|
||||||
public EasyConfig(File parent,String child) {
|
public EasyConfig(File parent,String child) {
|
||||||
this(new File(parent,child),new HashMap<>());
|
this(new File(parent,child),new HashMap<>());
|
||||||
}
|
}
|
||||||
public EasyConfig(Path parent,String child) {
|
public EasyConfig(Path parent,String child) {
|
||||||
this(new File(parent.toFile(),child),new HashMap<>());
|
this(new File(parent.toFile(),child),new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reload() {
|
public void reload() {
|
||||||
data = read();
|
data = read();
|
||||||
}
|
}
|
||||||
public void save() {
|
public void save() {
|
||||||
write(data);
|
write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String toText(Map<String,String> p) {
|
private String toText(Map<String,String> p) {
|
||||||
StringBuilder t = new StringBuilder();
|
String t = "";
|
||||||
for (Map.Entry<String,String> e:p.entrySet())
|
for (Map.Entry<String,String> e:p.entrySet())
|
||||||
t.append(e.getKey()).append("=").append(e.getValue()).append("\n");
|
t += e.getKey() + "=" + e.getValue() + "\n";
|
||||||
return t.toString();
|
return t;
|
||||||
}
|
}
|
||||||
private Map<String,String> toMap(String j) {
|
private Map<String,String> toMap(String j) {
|
||||||
Map<String,String> m = new HashMap<>();
|
Map<String,String> m = new HashMap<>();
|
||||||
for (String l:j.split("\n")) {
|
for (String l:j.split("\n")) {
|
||||||
String s[] = l.split("=");
|
String s[] = l.split("=");
|
||||||
m.put(s[0],s[1]);
|
m.put(s[0],s[1]);
|
||||||
}
|
}
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String,String> read() {
|
private Map<String,String> read() {
|
||||||
try {
|
try {
|
||||||
return toMap(Files.readString(path));
|
return toMap(Files.readString(path));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
private void write(Map<String,String> p) {
|
private void write(Map<String,String> p) {
|
||||||
try {
|
try {
|
||||||
Files.write(path, toText(p).getBytes());
|
Files.write(path, toText(p).getBytes());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,341 +0,0 @@
|
|||||||
package themixray.repeating.mod;
|
|
||||||
|
|
||||||
import net.fabricmc.api.ClientModInitializer;
|
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
|
||||||
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.option.KeyBinding;
|
|
||||||
import net.minecraft.client.util.InputUtil;
|
|
||||||
import net.minecraft.text.MutableText;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.util.Formatting;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import themixray.repeating.mod.event.events.DelayEvent;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
import themixray.repeating.mod.event.events.InputEvent;
|
|
||||||
import themixray.repeating.mod.event.events.MoveEvent;
|
|
||||||
import themixray.repeating.mod.render.RenderHelper;
|
|
||||||
import themixray.repeating.mod.render.RenderSystem;
|
|
||||||
import themixray.repeating.mod.render.buffer.WorldBuffer;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Main implements ClientModInitializer {
|
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger("repeating-mod");
|
|
||||||
public static final MinecraftClient client = MinecraftClient.getInstance();
|
|
||||||
public static final FabricLoader loader = FabricLoader.getInstance();
|
|
||||||
public static Main me;
|
|
||||||
|
|
||||||
public RecordList record_list;
|
|
||||||
public RecordState now_record;
|
|
||||||
|
|
||||||
public boolean is_recording = false;
|
|
||||||
public long last_record = -1;
|
|
||||||
public TickTask move_tick = null;
|
|
||||||
|
|
||||||
public TickTask replay_tick = null;
|
|
||||||
public boolean is_replaying = false;
|
|
||||||
public boolean loop_replay = false;
|
|
||||||
public static InputEvent input_replay = null;
|
|
||||||
|
|
||||||
public long living_ticks = 0;
|
|
||||||
|
|
||||||
public static RepeatingScreen menu;
|
|
||||||
private static KeyBinding menu_key;
|
|
||||||
private static KeyBinding toggle_replay_key;
|
|
||||||
private static KeyBinding toggle_record_key;
|
|
||||||
|
|
||||||
public long record_pos_delay = 20;
|
|
||||||
|
|
||||||
public static Random rand = new Random();
|
|
||||||
|
|
||||||
public EasyConfig conf;
|
|
||||||
public File records_folder;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onInitializeClient() {
|
|
||||||
LOGGER.info("Repeating mod initialized");
|
|
||||||
me = this;
|
|
||||||
|
|
||||||
now_record = null;
|
|
||||||
|
|
||||||
records_folder = new File(FabricLoader.getInstance().getGameDir().toFile(),"repeating_mod_records");
|
|
||||||
if (!records_folder.exists()) records_folder.mkdir();
|
|
||||||
|
|
||||||
record_list = new RecordList(records_folder);
|
|
||||||
record_list.loadRecords();
|
|
||||||
|
|
||||||
RenderSystem.init();
|
|
||||||
WorldRenderEvents.LAST.register(context -> {
|
|
||||||
WorldBuffer buffer = RenderHelper.startTri(context);
|
|
||||||
if (now_record != null) {
|
|
||||||
Vec3d start_pos = now_record.getStartRecordPos();
|
|
||||||
Vec3d finish_pos = now_record.getFinishRecordPos();
|
|
||||||
|
|
||||||
if (start_pos != null) drawRecordPos(buffer, start_pos, new Color(70, 230, 70, 128));
|
|
||||||
if (finish_pos != null) drawRecordPos(buffer, finish_pos, new Color(230, 70, 70, 128));
|
|
||||||
}
|
|
||||||
RenderHelper.endTri(buffer);
|
|
||||||
});
|
|
||||||
|
|
||||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
|
||||||
TickTask.tickTasks(TickTask.TickAt.CLIENT_EVENT);
|
|
||||||
});
|
|
||||||
|
|
||||||
Map<String,String> def = new HashMap<>();
|
|
||||||
def.put("record_pos_delay", String.valueOf(record_pos_delay));
|
|
||||||
|
|
||||||
conf = new EasyConfig(loader.getConfigDir(),"repeating-mod",def);
|
|
||||||
|
|
||||||
record_pos_delay = Long.parseLong(conf.data.get("record_pos_delay"));
|
|
||||||
|
|
||||||
menu_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
|
||||||
"key.repeating-mod.menu",InputUtil.Type.KEYSYM,
|
|
||||||
GLFW.GLFW_KEY_J,"text.repeating-mod.name"));
|
|
||||||
toggle_replay_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
|
||||||
"key.repeating-mod.toggle_replay",InputUtil.Type.KEYSYM,
|
|
||||||
-1,"text.repeating-mod.name"));
|
|
||||||
toggle_record_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
|
||||||
"key.repeating-mod.toggle_record",InputUtil.Type.KEYSYM,
|
|
||||||
-1,"text.repeating-mod.name"));
|
|
||||||
|
|
||||||
menu = new RepeatingScreen();
|
|
||||||
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
|
||||||
if (menu_key.wasPressed())
|
|
||||||
client.setScreen(menu);
|
|
||||||
if (toggle_replay_key.wasPressed()) {
|
|
||||||
if (now_record != null) {
|
|
||||||
if (!is_recording) {
|
|
||||||
if (is_replaying)
|
|
||||||
stopReplay();
|
|
||||||
else startReplay();
|
|
||||||
menu.updateButtons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (toggle_record_key.wasPressed()) {
|
|
||||||
if (!is_replaying) {
|
|
||||||
if (is_recording)
|
|
||||||
stopRecording();
|
|
||||||
else startRecording();
|
|
||||||
menu.updateButtons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new TickTask(0,0) {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
living_ticks++;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
System.setProperty("java.awt.headless", "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNowRecord(RecordState record) {
|
|
||||||
now_record = record;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawRecordPos(WorldBuffer buffer, Vec3d pos, Color color) {
|
|
||||||
RenderHelper.drawRectFromTri(buffer,
|
|
||||||
(float) pos.getX() - 0.25F,
|
|
||||||
(float) pos.getY() + 0.01F,
|
|
||||||
(float) pos.getZ() - 0.25F,
|
|
||||||
|
|
||||||
(float) pos.getX() + 0.25F,
|
|
||||||
(float) pos.getY() + 0.01F,
|
|
||||||
(float) pos.getZ() - 0.25F,
|
|
||||||
|
|
||||||
(float) pos.getX() + 0.25F,
|
|
||||||
(float) pos.getY() + 0.01F,
|
|
||||||
(float) pos.getZ() + 0.25F,
|
|
||||||
|
|
||||||
(float) pos.getX() - 0.25F,
|
|
||||||
(float) pos.getY() + 0.01F,
|
|
||||||
(float) pos.getZ() + 0.25F,
|
|
||||||
color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startRecording() {
|
|
||||||
is_recording = true;
|
|
||||||
menu.updateButtons();
|
|
||||||
|
|
||||||
now_record = record_list.newRecord();
|
|
||||||
|
|
||||||
Vec3d start_pos = client.player.getPos();
|
|
||||||
now_record.addEvent(new MoveEvent(start_pos,client.player.getHeadYaw(),client.player.getPitch()));
|
|
||||||
now_record.setStartRecordPos(start_pos);
|
|
||||||
|
|
||||||
if (record_pos_delay > 0) {
|
|
||||||
move_tick = new TickTask(
|
|
||||||
record_pos_delay,
|
|
||||||
record_pos_delay) {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
now_record.addEvent(new MoveEvent(client.player.getPos(),
|
|
||||||
client.player.getHeadYaw(), client.player.getPitch()));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(Text.translatable("message.repeating-mod.record_start"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordTick(RecordEvent e) {
|
|
||||||
if (is_recording) {
|
|
||||||
long now = living_ticks;
|
|
||||||
if (last_record != -1) {
|
|
||||||
long diff = now - last_record - 2;
|
|
||||||
if (diff > 0) now_record.addEvent(new DelayEvent(diff));
|
|
||||||
}
|
|
||||||
now_record.addEvent(e);
|
|
||||||
last_record = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void recordAllInput() {
|
|
||||||
if (client.player == null) {
|
|
||||||
stopRecording();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
InputEvent l = ((InputEvent) now_record.getLastEvent("input"));
|
|
||||||
if (l == null) {
|
|
||||||
InputEvent e = new InputEvent(
|
|
||||||
client.player.input.sneaking,
|
|
||||||
client.player.input.jumping,
|
|
||||||
client.player.input.movementSideways,
|
|
||||||
client.player.input.movementForward,
|
|
||||||
client.player.input.pressingForward,
|
|
||||||
client.player.input.pressingBack,
|
|
||||||
client.player.input.pressingLeft,
|
|
||||||
client.player.input.pressingRight,
|
|
||||||
client.player.getHeadYaw(),
|
|
||||||
client.player.getBodyYaw(),
|
|
||||||
client.player.getPitch(),
|
|
||||||
client.player.isSprinting(),
|
|
||||||
client.player.getYaw(),
|
|
||||||
client.player.getMovementSpeed());
|
|
||||||
recordTick(e);
|
|
||||||
} else {
|
|
||||||
InputEvent e = new InputEvent(
|
|
||||||
((Boolean) client.player.input.sneaking == l.sneaking) ? null : client.player.input.sneaking,
|
|
||||||
((Boolean) client.player.input.jumping == l.jumping) ? null : client.player.input.jumping,
|
|
||||||
(((Float) client.player.input.movementSideways).equals(l.movementSideways)) ? null : client.player.input.movementSideways,
|
|
||||||
(((Float) client.player.input.movementForward).equals(l.movementForward)) ? null : client.player.input.movementForward,
|
|
||||||
((Boolean) client.player.input.pressingForward == l.pressingForward) ? null : client.player.input.pressingForward,
|
|
||||||
((Boolean) client.player.input.pressingBack == l.pressingBack) ? null : client.player.input.pressingBack,
|
|
||||||
((Boolean) client.player.input.pressingLeft == l.pressingLeft) ? null : client.player.input.pressingLeft,
|
|
||||||
((Boolean) client.player.input.pressingRight == l.pressingRight) ? null : client.player.input.pressingRight,
|
|
||||||
client.player.getHeadYaw(), Main.client.player.getBodyYaw(),client.player.getPitch(),
|
|
||||||
((Boolean) client.player.isSprinting() == l.sprinting) ? null : client.player.isSprinting(),
|
|
||||||
client.player.getYaw(),client.player.getMovementSpeed());
|
|
||||||
|
|
||||||
if (!(e.isEmpty() &&
|
|
||||||
e.yaw == l.yaw &&
|
|
||||||
e.head_yaw == l.head_yaw &&
|
|
||||||
e.pitch == l.pitch &&
|
|
||||||
e.body_yaw == l.body_yaw)) {
|
|
||||||
e.fillEmpty(l);
|
|
||||||
recordTick(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopRecording() {
|
|
||||||
is_recording = false;
|
|
||||||
now_record.setFinishRecordPos(client.player.getPos());
|
|
||||||
try {
|
|
||||||
now_record.save();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
if (move_tick != null) {
|
|
||||||
move_tick.cancel();
|
|
||||||
move_tick = null;
|
|
||||||
}
|
|
||||||
menu.updateButtons();
|
|
||||||
last_record = -1;
|
|
||||||
sendMessage(Text.translatable("message.repeating-mod.record_stop"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void startReplay() {
|
|
||||||
is_recording = false;
|
|
||||||
is_replaying = true;
|
|
||||||
menu.updateButtons();
|
|
||||||
|
|
||||||
List<RecordEvent> events = now_record.getEvents();
|
|
||||||
|
|
||||||
replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_EVENT) {
|
|
||||||
public int replay_index = 0;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!is_replaying) {
|
|
||||||
cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordEvent e = events.get(replay_index);
|
|
||||||
if (e != null) {
|
|
||||||
if (e instanceof DelayEvent) {
|
|
||||||
setDelay(((DelayEvent) e).delay);
|
|
||||||
} else {
|
|
||||||
e.replay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
replay_index++;
|
|
||||||
if (!loop_replay) {
|
|
||||||
if (replay_index >= events.size()) {
|
|
||||||
stopReplay();
|
|
||||||
cancel();
|
|
||||||
}
|
|
||||||
} else if (replay_index >= events.size()) {
|
|
||||||
replay_index = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
sendMessage(Text.translatable("message.repeating-mod.replay_start"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopReplay() {
|
|
||||||
is_recording = false;
|
|
||||||
is_replaying = false;
|
|
||||||
if (replay_tick != null) {
|
|
||||||
replay_tick.cancel();
|
|
||||||
replay_tick = null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
now_record.save();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
menu.updateButtons();
|
|
||||||
record_list.getWidget().getWidget(now_record).getChildren().get(3).setMessage(Text.translatable("text.repeating-mod.start"));
|
|
||||||
sendMessage(Text.translatable("message.repeating-mod.replay_stop"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMessage(MutableText text) {
|
|
||||||
client.player.sendMessage(Text.literal("[")
|
|
||||||
.append(Text.translatable("text.repeating-mod.name"))
|
|
||||||
.append("] ").formatted(Formatting.BOLD,Formatting.DARK_GRAY)
|
|
||||||
.append(text.formatted(Formatting.RESET).formatted(Formatting.GRAY)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendDebug(String s) {
|
|
||||||
client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s)));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
package themixray.repeating.mod;
|
|
||||||
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import themixray.repeating.mod.widget.RecordListWidget;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class RecordList {
|
|
||||||
private final File folder;
|
|
||||||
private LinkedList<RecordState> records;
|
|
||||||
private RecordListWidget widget;
|
|
||||||
|
|
||||||
public RecordList(File folder) {
|
|
||||||
this.folder = folder;
|
|
||||||
this.records = new LinkedList<>();
|
|
||||||
this.widget = new RecordListWidget(0, 0, 180, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RecordState> getRecords() {
|
|
||||||
return records;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getFolder() {
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordListWidget getWidget() {
|
|
||||||
return widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadRecords() {
|
|
||||||
LinkedList<File> files = new LinkedList<>(List.of(folder.listFiles()));
|
|
||||||
|
|
||||||
files.sort(Comparator.comparingLong((f) -> f.lastModified()));
|
|
||||||
|
|
||||||
for (File file : files) {
|
|
||||||
try {
|
|
||||||
addRecord(file);
|
|
||||||
} catch (Exception e) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordState addRecord(File file) throws Exception {
|
|
||||||
RecordState st = RecordState.load(file);
|
|
||||||
addRecord(st);
|
|
||||||
return st;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRecord(RecordState record) {
|
|
||||||
if (record == null) return;
|
|
||||||
records.add(record);
|
|
||||||
widget.addWidget(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeRecord(RecordState record) {
|
|
||||||
records.remove(record);
|
|
||||||
widget.removeWidget(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordState newRecord() {
|
|
||||||
Date date = new Date();
|
|
||||||
String name = "Unnamed";
|
|
||||||
String author = Main.client.player.getName().getString();
|
|
||||||
|
|
||||||
File file = new File(Main.me.records_folder,
|
|
||||||
"record_" + RecordState.FILE_DATE_FORMAT.format(date) +
|
|
||||||
"_" + Main.rand.nextInt(10) + ".rrm");
|
|
||||||
|
|
||||||
RecordState state = new RecordState(
|
|
||||||
file, name, date, author,
|
|
||||||
new ArrayList<>(),
|
|
||||||
null,
|
|
||||||
null);
|
|
||||||
|
|
||||||
addRecord(state);
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordState cloneRecord(File file) throws Exception {
|
|
||||||
File out = new File(Main.me.records_folder, file.getName());
|
|
||||||
Files.copy(file.toPath(), out.toPath());
|
|
||||||
RecordState state = RecordState.load(out);
|
|
||||||
addRecord(state);
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,178 +0,0 @@
|
|||||||
package themixray.repeating.mod;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class RecordState {
|
|
||||||
public static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss");
|
|
||||||
public static SimpleDateFormat FILE_DATE_FORMAT = new SimpleDateFormat("MM-dd-yyyy_HH-mm-ss");
|
|
||||||
|
|
||||||
private final File file;
|
|
||||||
private String name;
|
|
||||||
private Date date;
|
|
||||||
private String author;
|
|
||||||
|
|
||||||
private List<RecordEvent> events;
|
|
||||||
private Vec3d start_record_pos;
|
|
||||||
private Vec3d finish_record_pos;
|
|
||||||
|
|
||||||
public RecordState(File file,
|
|
||||||
String name,
|
|
||||||
Date date,
|
|
||||||
String author,
|
|
||||||
List<RecordEvent> events,
|
|
||||||
Vec3d start_record_pos,
|
|
||||||
Vec3d finish_record_pos) {
|
|
||||||
this.file = file;
|
|
||||||
this.name = name;
|
|
||||||
this.date = date;
|
|
||||||
this.author = author;
|
|
||||||
|
|
||||||
this.events = events;
|
|
||||||
this.start_record_pos = start_record_pos;
|
|
||||||
this.finish_record_pos = finish_record_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getFile() {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAuthor() {
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getDate() {
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RecordEvent> getEvents() {
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3d getFinishRecordPos() {
|
|
||||||
return finish_record_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3d getStartRecordPos() {
|
|
||||||
return start_record_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthor(String author) {
|
|
||||||
this.author = author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDate(Date date) {
|
|
||||||
this.date = date;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEvents(List<RecordEvent> events) {
|
|
||||||
this.events = events;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFinishRecordPos(Vec3d finish_record_pos) {
|
|
||||||
this.finish_record_pos = finish_record_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStartRecordPos(Vec3d start_record_pos) {
|
|
||||||
this.start_record_pos = start_record_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addEvent(RecordEvent event) {
|
|
||||||
if (event == null) return;
|
|
||||||
events.add(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordEvent getLastEvent(String type) {
|
|
||||||
for (RecordEvent r: Lists.reverse(new ArrayList<>(events))) {
|
|
||||||
if (r.getType() != null && r.getType().getName().equals(type)) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save() throws IOException {
|
|
||||||
if (start_record_pos == null || finish_record_pos == null) return;
|
|
||||||
|
|
||||||
StringBuilder text = new StringBuilder();
|
|
||||||
|
|
||||||
text.append(name).append("\n")
|
|
||||||
.append(DATE_FORMAT.format(date)).append("\n")
|
|
||||||
.append(author).append("\n");
|
|
||||||
|
|
||||||
text.append(start_record_pos.getX()).append("n")
|
|
||||||
.append(start_record_pos.getY()).append("n")
|
|
||||||
.append(start_record_pos.getZ()).append("x")
|
|
||||||
.append(finish_record_pos.getX()).append("n")
|
|
||||||
.append(finish_record_pos.getY()).append("n")
|
|
||||||
.append(finish_record_pos.getZ());
|
|
||||||
|
|
||||||
for (RecordEvent event : events) {
|
|
||||||
if (event == null) continue;
|
|
||||||
text.append("\n");
|
|
||||||
text.append(event.serialize());
|
|
||||||
}
|
|
||||||
|
|
||||||
Files.write(file.toPath(), text.toString().getBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RecordState load(File file) throws Exception {
|
|
||||||
String text = Files.readString(file.toPath());
|
|
||||||
List<String> lines = List.of(text.split("\n"));
|
|
||||||
|
|
||||||
List<String> signature = lines.subList(0,4);
|
|
||||||
|
|
||||||
String name = signature.get(0);
|
|
||||||
Date date = DATE_FORMAT.parse(signature.get(1));
|
|
||||||
String author = signature.get(2);
|
|
||||||
|
|
||||||
String record_pos = signature.get(3);
|
|
||||||
|
|
||||||
String[] lss0 = record_pos.split("x");
|
|
||||||
String[] lss1 = lss0[0].split("n");
|
|
||||||
String[] lss2 = lss0[1].split("n");
|
|
||||||
|
|
||||||
Vec3d start_record_pos = new Vec3d(
|
|
||||||
Float.parseFloat(lss1[0]),
|
|
||||||
Float.parseFloat(lss1[1]),
|
|
||||||
Float.parseFloat(lss1[2]));
|
|
||||||
Vec3d finish_record_pos = new Vec3d(
|
|
||||||
Float.parseFloat(lss2[0]),
|
|
||||||
Float.parseFloat(lss2[1]),
|
|
||||||
Float.parseFloat(lss2[2]));
|
|
||||||
|
|
||||||
List<String> event_lines = lines.subList(4,lines.size());
|
|
||||||
List<RecordEvent> events = event_lines.stream().map(RecordEvent::deserialize).toList();
|
|
||||||
|
|
||||||
return new RecordState(file, name, date, author, events, start_record_pos, finish_record_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
Main.me.record_list.removeRecord(this);
|
|
||||||
Main.me.record_list.getWidget().removeWidget(this);
|
|
||||||
if (Main.me.is_recording && this.equals(Main.me.now_record)) {
|
|
||||||
Main.me.stopRecording();
|
|
||||||
Main.me.now_record = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
package themixray.repeating.mod;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
|
||||||
|
|
||||||
public interface RenderListener {
|
|
||||||
default boolean beforeRender() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void render(DrawContext context, int mouseX, int mouseY, float delta);
|
|
||||||
}
|
|
565
src/main/java/themixray/repeating/mod/RepeatingMod.java
Normal file
565
src/main/java/themixray/repeating/mod/RepeatingMod.java
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.option.KeyBinding;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class RepeatingMod implements ClientModInitializer {
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger("repeating-mod");
|
||||||
|
public static final MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
public static final FabricLoader loader = FabricLoader.getInstance();
|
||||||
|
public static RepeatingMod me;
|
||||||
|
|
||||||
|
public Thread move_tick = null;
|
||||||
|
public List<RecordEvent> record = new ArrayList<>();
|
||||||
|
public boolean is_recording = false;
|
||||||
|
public Date last_record = null;
|
||||||
|
|
||||||
|
public Thread replay = null;
|
||||||
|
public boolean is_replaying = false;
|
||||||
|
public boolean loop_replay = false;
|
||||||
|
public static RecordInputEvent input_replay = null;
|
||||||
|
|
||||||
|
public static RepeatingScreen menu;
|
||||||
|
private static KeyBinding menu_key;
|
||||||
|
private static KeyBinding toggle_replay_key;
|
||||||
|
private static KeyBinding toggle_record_key;
|
||||||
|
|
||||||
|
public long record_pos_delay = 1000;
|
||||||
|
|
||||||
|
public EasyConfig conf;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeClient() {
|
||||||
|
LOGGER.info("Repeating mod initialized");
|
||||||
|
me = this;
|
||||||
|
|
||||||
|
Map<String,String> def = new HashMap<>();
|
||||||
|
def.put("record_pos_delay", String.valueOf(record_pos_delay));
|
||||||
|
|
||||||
|
conf = new EasyConfig(loader.getConfigDir(),"repeating-mod",def);
|
||||||
|
|
||||||
|
record_pos_delay = Long.parseLong(conf.data.get("record_pos_delay"));
|
||||||
|
|
||||||
|
menu_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.menu",InputUtil.Type.KEYSYM,
|
||||||
|
GLFW.GLFW_KEY_J,"text.repeating-mod.name"));
|
||||||
|
toggle_replay_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.toggle_replay",InputUtil.Type.KEYSYM,
|
||||||
|
-1,"text.repeating-mod.name"));
|
||||||
|
toggle_record_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.toggle_record",InputUtil.Type.KEYSYM,
|
||||||
|
-1,"text.repeating-mod.name"));
|
||||||
|
|
||||||
|
menu = new RepeatingScreen();
|
||||||
|
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||||
|
if (menu_key.wasPressed())
|
||||||
|
client.setScreen(menu);
|
||||||
|
if (toggle_replay_key.wasPressed()) {
|
||||||
|
if (!is_recording) {
|
||||||
|
if (is_replaying)
|
||||||
|
stopReplay();
|
||||||
|
else startReplay();
|
||||||
|
menu.update_btns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toggle_record_key.wasPressed()) {
|
||||||
|
if (!is_replaying) {
|
||||||
|
if (is_recording)
|
||||||
|
stopRecording();
|
||||||
|
else startRecording();
|
||||||
|
menu.update_btns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordEvent getLastRecord(String t) {
|
||||||
|
for (RecordEvent r:Lists.reverse(new ArrayList<>(record))) {
|
||||||
|
if (r.getType().equals(t)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void startRecording() {
|
||||||
|
is_recording = true;
|
||||||
|
menu.update_btns();
|
||||||
|
record.clear();
|
||||||
|
|
||||||
|
record.add(new RecordMoveEvent(client.player.getPos(),
|
||||||
|
client.player.getHeadYaw(), client.player.getPitch()));
|
||||||
|
|
||||||
|
if (record_pos_delay > 0) {
|
||||||
|
move_tick = new Thread(() -> {
|
||||||
|
while (is_recording) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(record_pos_delay);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
record.add(new RecordMoveEvent(client.player.getPos(),
|
||||||
|
client.player.getHeadYaw(), client.player.getPitch()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
move_tick.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.record_start"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordTick(RecordEvent e) {
|
||||||
|
Date now = new Date();
|
||||||
|
if (last_record != null) {
|
||||||
|
long diff = now.getTime() - last_record.getTime();
|
||||||
|
if (diff >= 0) record.add(new RecordDelayEvent(diff));
|
||||||
|
}
|
||||||
|
record.add(e);
|
||||||
|
last_record = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordAllInput() {
|
||||||
|
RecordInputEvent l = ((RecordInputEvent)getLastRecord("input"));
|
||||||
|
if (l == null) {
|
||||||
|
RecordInputEvent e = new RecordInputEvent(
|
||||||
|
client.player.input.sneaking,
|
||||||
|
client.player.input.jumping,
|
||||||
|
client.player.input.movementSideways,
|
||||||
|
client.player.input.movementForward,
|
||||||
|
client.player.input.pressingForward,
|
||||||
|
client.player.input.pressingBack,
|
||||||
|
client.player.input.pressingLeft,
|
||||||
|
client.player.input.pressingRight,
|
||||||
|
client.player.getHeadYaw(),
|
||||||
|
client.player.getBodyYaw(),
|
||||||
|
client.player.getPitch(),
|
||||||
|
client.player.isSprinting(),
|
||||||
|
client.player.getYaw(),
|
||||||
|
client.player.getMovementSpeed());
|
||||||
|
recordTick(e);
|
||||||
|
} else {
|
||||||
|
RecordInputEvent e = new RecordInputEvent(
|
||||||
|
((Boolean) client.player.input.sneaking == l.sneaking) ? null : client.player.input.sneaking,
|
||||||
|
((Boolean) client.player.input.jumping == l.jumping) ? null : client.player.input.jumping,
|
||||||
|
(((Float) client.player.input.movementSideways).equals(l.movementSideways)) ? null : client.player.input.movementSideways,
|
||||||
|
(((Float) client.player.input.movementForward).equals(l.movementForward)) ? null : client.player.input.movementForward,
|
||||||
|
((Boolean) client.player.input.pressingForward == l.pressingForward) ? null : client.player.input.pressingForward,
|
||||||
|
((Boolean) client.player.input.pressingBack == l.pressingBack) ? null : client.player.input.pressingBack,
|
||||||
|
((Boolean) client.player.input.pressingLeft == l.pressingLeft) ? null : client.player.input.pressingLeft,
|
||||||
|
((Boolean) client.player.input.pressingRight == l.pressingRight) ? null : client.player.input.pressingRight,
|
||||||
|
client.player.getHeadYaw(),RepeatingMod.client.player.getBodyYaw(),client.player.getPitch(),
|
||||||
|
((Boolean) client.player.isSprinting() == l.sprinting) ? null : client.player.isSprinting(),
|
||||||
|
client.player.getYaw(),client.player.getMovementSpeed());
|
||||||
|
|
||||||
|
if (!(e.isEmpty() &&
|
||||||
|
e.yaw == l.yaw &&
|
||||||
|
e.head_yaw == l.head_yaw &&
|
||||||
|
e.pitch == l.pitch &&
|
||||||
|
e.body_yaw == l.body_yaw)) {
|
||||||
|
e.fillEmpty(l);
|
||||||
|
recordTick(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordCameraInput() {
|
||||||
|
RecordInputEvent l = ((RecordInputEvent)getLastRecord("input"));
|
||||||
|
if (l == null) {
|
||||||
|
RecordInputEvent e = new RecordInputEvent(
|
||||||
|
client.player.input.sneaking,
|
||||||
|
client.player.input.jumping,
|
||||||
|
client.player.input.movementSideways,
|
||||||
|
client.player.input.movementForward,
|
||||||
|
client.player.input.pressingForward,
|
||||||
|
client.player.input.pressingBack,
|
||||||
|
client.player.input.pressingLeft,
|
||||||
|
client.player.input.pressingRight,
|
||||||
|
client.player.getHeadYaw(),
|
||||||
|
client.player.getBodyYaw(),
|
||||||
|
client.player.getPitch(),
|
||||||
|
client.player.isSprinting(),
|
||||||
|
client.player.getYaw(),
|
||||||
|
client.player.getMovementSpeed());
|
||||||
|
recordTick(e);
|
||||||
|
} else {
|
||||||
|
RecordInputEvent e = new RecordInputEvent(null,null,null,
|
||||||
|
null,null,null,null,null,
|
||||||
|
client.player.getHeadYaw(),RepeatingMod.client.player.getBodyYaw(),client.player.getPitch(),
|
||||||
|
null,client.player.getYaw(),client.player.getMovementSpeed());
|
||||||
|
|
||||||
|
if (!(e.yaw == l.yaw &&
|
||||||
|
e.head_yaw == l.head_yaw &&
|
||||||
|
e.pitch == l.pitch &&
|
||||||
|
e.body_yaw == l.body_yaw)) {
|
||||||
|
e.fillEmpty(l);
|
||||||
|
recordTick(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopRecording() {
|
||||||
|
is_recording = false;
|
||||||
|
move_tick = null;
|
||||||
|
menu.update_btns();
|
||||||
|
last_record = null;
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.record_stop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void startReplay() {
|
||||||
|
is_recording = false;
|
||||||
|
is_replaying = true;
|
||||||
|
menu.update_btns();
|
||||||
|
replay = new Thread(() -> {
|
||||||
|
while (true) {
|
||||||
|
for (RecordEvent e : record) {
|
||||||
|
if (is_replaying) {
|
||||||
|
e.callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!loop_replay || !is_replaying) break;
|
||||||
|
}
|
||||||
|
stopReplay();
|
||||||
|
});
|
||||||
|
replay.start();
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.replay_start"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopReplay() {
|
||||||
|
is_recording = false;
|
||||||
|
is_replaying = false;
|
||||||
|
replay = null;
|
||||||
|
menu.update_btns();
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.replay_stop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double round(double value, int places) {
|
||||||
|
if (places < 0) throw new IllegalArgumentException();
|
||||||
|
long factor = (long) Math.pow(10, places);
|
||||||
|
return (double) Math.round(value * factor) / factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendMessage(Text text) {
|
||||||
|
client.player.sendMessage(Text.literal("[")
|
||||||
|
.append(Text.translatable("text.repeating-mod.name"))
|
||||||
|
.append("] ").append(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class RecordEvent {
|
||||||
|
abstract void callback();
|
||||||
|
abstract String toText();
|
||||||
|
abstract String getType();
|
||||||
|
|
||||||
|
public static RecordEvent fromText(String t) {
|
||||||
|
try {
|
||||||
|
String type = String.valueOf(t.charAt(0));
|
||||||
|
String[] args = t.substring(2).split("&");
|
||||||
|
if (type.equals("d")) {
|
||||||
|
return RecordDelayEvent.fromArgs(args);
|
||||||
|
} else if (type.equals("m")) {
|
||||||
|
return RecordMoveEvent.fromArgs(args);
|
||||||
|
} else if (type.equals("p")) {
|
||||||
|
return RecordInputEvent.fromArgs(args);
|
||||||
|
} else if (type.equals("b")) {
|
||||||
|
return RecordBlockBreakEvent.fromArgs(args);
|
||||||
|
} else if (type.equals("i")) {
|
||||||
|
return RecordBlockInteractEvent.fromArgs(args);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordDelayEvent extends RecordEvent {
|
||||||
|
public long delay;
|
||||||
|
|
||||||
|
public static RecordDelayEvent fromArgs(String[] a) {
|
||||||
|
return new RecordDelayEvent(Long.parseLong(a[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordDelayEvent(long delay) {
|
||||||
|
this.delay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "d="+delay;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "delay";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordMoveEvent extends RecordEvent {
|
||||||
|
public Vec3d vec;
|
||||||
|
public float yaw;
|
||||||
|
public float pitch;
|
||||||
|
|
||||||
|
public static RecordMoveEvent fromArgs(String[] a) {
|
||||||
|
return new RecordMoveEvent(new Vec3d(
|
||||||
|
Double.parseDouble(a[0]),
|
||||||
|
Double.parseDouble(a[1]),
|
||||||
|
Double.parseDouble(a[2])),
|
||||||
|
Float.parseFloat(a[3]),
|
||||||
|
Float.parseFloat(a[4]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordMoveEvent(Vec3d vec,float yaw,float pitch) {
|
||||||
|
this.vec = vec;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
Vec3d p = client.player.getPos();
|
||||||
|
Vec3d v = new Vec3d(vec.getX()-p.getX(),vec.getY()-p.getY(),vec.getZ()-p.getZ());
|
||||||
|
client.player.move(MovementType.SELF,v);
|
||||||
|
client.player.setYaw(yaw);
|
||||||
|
client.player.setPitch(pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "m="+vec.getX()+"&"+vec.getY()+"&"+vec.getZ()+"&"+yaw+"&"+pitch;
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "move";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordInputEvent extends RecordEvent {
|
||||||
|
public Boolean sneaking;
|
||||||
|
public Boolean jumping;
|
||||||
|
public Boolean pressingForward;
|
||||||
|
public Boolean pressingBack;
|
||||||
|
public Boolean pressingLeft;
|
||||||
|
public Boolean pressingRight;
|
||||||
|
public Boolean sprinting;
|
||||||
|
|
||||||
|
public Float movementSideways;
|
||||||
|
public Float movementForward;
|
||||||
|
|
||||||
|
public float yaw;
|
||||||
|
public float head_yaw;
|
||||||
|
public float body_yaw;
|
||||||
|
public float pitch;
|
||||||
|
public float speed;
|
||||||
|
|
||||||
|
public static RecordInputEvent fromArgs(String[] a) {
|
||||||
|
return new RecordInputEvent(
|
||||||
|
(a[0].equals("n")?null:a[0].equals("1")),
|
||||||
|
(a[1].equals("n")?null:a[1].equals("1")),
|
||||||
|
(a[2].equals("n")?null:Float.parseFloat(a[2])),
|
||||||
|
(a[3].equals("n")?null:Float.parseFloat(a[3])),
|
||||||
|
(a[4].equals("n")?null:a[4].equals("1")),
|
||||||
|
(a[5].equals("n")?null:a[5].equals("1")),
|
||||||
|
(a[6].equals("n")?null:a[6].equals("1")),
|
||||||
|
(a[7].equals("n")?null:a[7].equals("1")),
|
||||||
|
Float.parseFloat(a[8]),Float.parseFloat(a[9]),
|
||||||
|
Float.parseFloat(a[10]),
|
||||||
|
(a[11].equals("n")?null:a[11].equals("1")),
|
||||||
|
Float.parseFloat(a[12]),
|
||||||
|
Float.parseFloat(a[13]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordInputEvent(Boolean sneaking,
|
||||||
|
Boolean jumping,
|
||||||
|
Float movementSideways,
|
||||||
|
Float movementForward,
|
||||||
|
Boolean pressingForward,
|
||||||
|
Boolean pressingBack,
|
||||||
|
Boolean pressingLeft,
|
||||||
|
Boolean pressingRight,
|
||||||
|
float head_yaw,
|
||||||
|
float body_yaw,
|
||||||
|
float head_pitch,
|
||||||
|
Boolean sprinting,
|
||||||
|
float yaw,
|
||||||
|
float speed) {
|
||||||
|
this.sneaking = sneaking;
|
||||||
|
this.jumping = jumping;
|
||||||
|
this.movementSideways = movementSideways;
|
||||||
|
this.movementForward = movementForward;
|
||||||
|
this.pressingForward = pressingForward;
|
||||||
|
this.pressingBack = pressingBack;
|
||||||
|
this.pressingLeft = pressingLeft;
|
||||||
|
this.pressingRight = pressingRight;
|
||||||
|
this.head_yaw = head_yaw;
|
||||||
|
this.body_yaw = body_yaw;
|
||||||
|
this.pitch = head_pitch;
|
||||||
|
this.sprinting = sprinting;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillEmpty(RecordInputEvent e) {
|
||||||
|
if (sneaking == null) sneaking = e.sneaking;
|
||||||
|
if (jumping == null) jumping = e.jumping;
|
||||||
|
if (movementSideways == null) movementSideways = e.movementSideways;
|
||||||
|
if (movementForward == null) movementForward = e.movementForward;
|
||||||
|
if (pressingForward == null) pressingForward = e.pressingForward;
|
||||||
|
if (pressingBack == null) pressingBack = e.pressingBack;
|
||||||
|
if (pressingLeft == null) pressingLeft = e.pressingLeft;
|
||||||
|
if (pressingRight == null) pressingRight = e.pressingRight;
|
||||||
|
if (sprinting == null) sprinting = e.sprinting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return sneaking == null &&
|
||||||
|
jumping == null &&
|
||||||
|
movementSideways == null &&
|
||||||
|
movementForward == null &&
|
||||||
|
pressingForward == null &&
|
||||||
|
pressingBack == null &&
|
||||||
|
pressingLeft == null &&
|
||||||
|
pressingRight == null &&
|
||||||
|
sprinting == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
input_replay = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputCallback() {
|
||||||
|
if (sprinting != null && client.player.isSprinting() != sprinting)
|
||||||
|
client.player.setSprinting(sprinting);
|
||||||
|
if (client.player.getYaw() != yaw)
|
||||||
|
client.player.setYaw(yaw);
|
||||||
|
if (client.player.getHeadYaw() != head_yaw)
|
||||||
|
client.player.setHeadYaw(head_yaw);
|
||||||
|
if (client.player.getBodyYaw() != body_yaw)
|
||||||
|
client.player.setBodyYaw(body_yaw);
|
||||||
|
if (client.player.getPitch() != pitch)
|
||||||
|
client.player.setPitch(pitch);
|
||||||
|
if (client.player.getMovementSpeed() != speed)
|
||||||
|
client.player.setMovementSpeed(speed);
|
||||||
|
if (sneaking != null && client.player.input.sneaking != sneaking)
|
||||||
|
client.player.input.sneaking = sneaking;
|
||||||
|
if (jumping != null && client.player.input.jumping != jumping)
|
||||||
|
client.player.input.jumping = jumping;
|
||||||
|
if (movementSideways != null && client.player.input.movementSideways != movementSideways)
|
||||||
|
client.player.input.movementSideways = movementSideways;
|
||||||
|
if (movementForward != null && client.player.input.movementForward != movementForward)
|
||||||
|
client.player.input.movementForward = movementForward;
|
||||||
|
if (pressingForward != null && client.player.input.pressingForward != pressingForward)
|
||||||
|
client.player.input.pressingForward = pressingForward;
|
||||||
|
if (pressingBack != null && client.player.input.pressingBack != pressingBack)
|
||||||
|
client.player.input.pressingBack = pressingBack;
|
||||||
|
if (pressingLeft != null && client.player.input.pressingLeft != pressingLeft)
|
||||||
|
client.player.input.pressingLeft = pressingLeft;
|
||||||
|
if (pressingRight != null && client.player.input.pressingRight != pressingRight)
|
||||||
|
client.player.input.pressingRight = pressingRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "p="+
|
||||||
|
((sneaking==null)?"n":(sneaking?"1":"0"))+"&"+
|
||||||
|
((jumping==null)?"n":(jumping?"1":"0"))+"&"+
|
||||||
|
((movementSideways==null)?"n":movementSideways)+"&"+
|
||||||
|
((movementForward==null)?"n":movementForward)+"&"+
|
||||||
|
((pressingForward==null)?"n":(pressingForward?"1":"0"))+"&"+
|
||||||
|
((pressingBack==null)?"n":(pressingBack?"1":"0"))+"&"+
|
||||||
|
((pressingLeft==null)?"n":(pressingLeft?"1":"0"))+"&"+
|
||||||
|
((pressingRight==null)?"n":(pressingRight?"1":"0"))+"&"+
|
||||||
|
head_yaw+"&"+body_yaw+"&"+ pitch +"&"+
|
||||||
|
((sprinting==null)?"n":(sprinting?"1":"0")+
|
||||||
|
"&"+yaw+"&"+speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return "input";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordBlockBreakEvent extends RecordEvent {
|
||||||
|
public BlockPos pos;
|
||||||
|
|
||||||
|
public static RecordBlockBreakEvent fromArgs(String[] a) {
|
||||||
|
return new RecordBlockBreakEvent(new BlockPos(
|
||||||
|
Integer.parseInt(a[0]),
|
||||||
|
Integer.parseInt(a[1]),
|
||||||
|
Integer.parseInt(a[2])));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordBlockBreakEvent(
|
||||||
|
BlockPos pos) {
|
||||||
|
this.pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
client.interactionManager.breakBlock(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "b="+pos.getX()+"&"+pos.getY()+"&"+pos.getZ();
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "block_break";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RecordBlockInteractEvent extends RecordEvent {
|
||||||
|
public Hand hand;
|
||||||
|
public BlockHitResult hitResult;
|
||||||
|
|
||||||
|
public static RecordBlockInteractEvent fromArgs(String[] a) {
|
||||||
|
return new RecordBlockInteractEvent(
|
||||||
|
Hand.valueOf(a[5]),
|
||||||
|
new BlockHitResult(new Vec3d(
|
||||||
|
Double.parseDouble(a[0]),
|
||||||
|
Double.parseDouble(a[1]),
|
||||||
|
Double.parseDouble(a[2])),
|
||||||
|
Direction.byId(Integer.parseInt(a[4])),
|
||||||
|
new BlockPos(
|
||||||
|
Integer.parseInt(a[0]),
|
||||||
|
Integer.parseInt(a[1]),
|
||||||
|
Integer.parseInt(a[2])),
|
||||||
|
a[3].equals("1")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordBlockInteractEvent(Hand hand, BlockHitResult hitResult) {
|
||||||
|
this.hand = hand;
|
||||||
|
this.hitResult = hitResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callback() {
|
||||||
|
client.interactionManager.interactBlock(client.player,hand,hitResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toText() {
|
||||||
|
return "i="+hitResult.getBlockPos().getX()+"&"+hitResult.getBlockPos().getY()+"&"+hitResult.getBlockPos().getZ()+
|
||||||
|
"&"+(hitResult.isInsideBlock()?"1":"0")+"&"+hitResult.getSide().getId()+"&"+hand.name();
|
||||||
|
}
|
||||||
|
public String getType() {
|
||||||
|
return "block_interact";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,187 +1,192 @@
|
|||||||
package themixray.repeating.mod;
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
import net.fabricmc.api.EnvType;
|
import io.wispforest.owo.ui.base.*;
|
||||||
import net.fabricmc.api.Environment;
|
import io.wispforest.owo.ui.component.*;
|
||||||
import net.minecraft.client.gui.DrawContext;
|
import io.wispforest.owo.ui.container.*;
|
||||||
import net.minecraft.client.gui.Drawable;
|
import io.wispforest.owo.ui.container.FlowLayout;
|
||||||
import net.minecraft.client.gui.Element;
|
import io.wispforest.owo.ui.core.*;
|
||||||
import net.minecraft.client.gui.Selectable;
|
import io.wispforest.owo.ui.core.Insets;
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.client.gui.tooltip.Tooltip;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import net.minecraft.client.gui.widget.SliderWidget;
|
|
||||||
import net.minecraft.text.Text;
|
import java.io.*;
|
||||||
import themixray.repeating.mod.widget.RecordListWidget;
|
import java.nio.file.Files;
|
||||||
|
|
||||||
import java.awt.*;
|
public class RepeatingScreen extends BaseOwoScreen<FlowLayout> {
|
||||||
import java.io.File;
|
public RepeatingMod mod;
|
||||||
import java.util.ArrayList;
|
public ButtonComponent replay_btn;
|
||||||
import java.util.List;
|
public ButtonComponent record_btn;
|
||||||
|
public ButtonComponent loop_btn;
|
||||||
@Environment(EnvType.CLIENT)
|
public boolean was_build = false;
|
||||||
public class RepeatingScreen extends Screen {
|
|
||||||
private static List<RenderListener> render_listeners = new ArrayList<>();
|
public RepeatingScreen() {
|
||||||
|
this.mod = RepeatingMod.me;
|
||||||
public ButtonWidget record_btn;
|
}
|
||||||
public ButtonWidget loop_btn;
|
|
||||||
public ButtonWidget import_btn;
|
@Override
|
||||||
|
protected @NotNull OwoUIAdapter<FlowLayout> createAdapter() {
|
||||||
public SliderWidget pos_delay_slider;
|
return OwoUIAdapter.create(this, Containers::horizontalFlow);
|
||||||
|
}
|
||||||
public boolean was_build = false;
|
|
||||||
|
public void update_btns() {
|
||||||
protected RepeatingScreen() {
|
if (was_build) {
|
||||||
super(Text.empty());
|
replay_btn.setMessage(Text.translatable("text.repeating-mod." +
|
||||||
}
|
((mod.is_replaying) ? "stop" : "start")).append(" ")
|
||||||
|
.append(Text.translatable("text.repeating-mod.replay")));
|
||||||
public static void addRenderListener(RenderListener render) {
|
record_btn.setMessage(Text.translatable("text.repeating-mod." +
|
||||||
render_listeners.add(render);
|
((mod.is_recording) ? "stop" : "start")).append(" ")
|
||||||
}
|
.append(Text.translatable("text.repeating-mod.record")));
|
||||||
|
loop_btn.setMessage(Text.of(((mod.loop_replay) ? "\uefff " : "\ueffe ")));
|
||||||
public static void removeRenderListener(RenderListener render) {
|
}
|
||||||
render_listeners.remove(render);
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
public void updateButtons() {
|
protected void build(FlowLayout rootComponent) {
|
||||||
if (was_build) {
|
rootComponent
|
||||||
record_btn.setMessage(Text.translatable("text.repeating-mod." + ((Main.me.is_recording) ? "stop_record" : "start_record")));
|
.surface(Surface.VANILLA_TRANSLUCENT)
|
||||||
loop_btn.setMessage(Text.translatable("text.repeating-mod." + ((Main.me.loop_replay) ? "off_loop" : "on_loop")));
|
.horizontalAlignment(HorizontalAlignment.CENTER)
|
||||||
}
|
.verticalAlignment(VerticalAlignment.CENTER);
|
||||||
}
|
|
||||||
|
replay_btn = (ButtonComponent) Components.button(Text.of("replay"),
|
||||||
@Override
|
(ButtonComponent btn) -> {
|
||||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
if (!mod.is_recording) {
|
||||||
renderBackground(context);
|
if (mod.is_replaying)
|
||||||
|
mod.stopReplay();
|
||||||
for (RenderListener l : render_listeners) {
|
else mod.startReplay();
|
||||||
if (l.beforeRender()) {
|
update_btns();
|
||||||
l.render(context, mouseX, mouseY, delta);
|
}
|
||||||
}
|
}).margins(Insets.of(1)).sizing(
|
||||||
}
|
Sizing.fixed(98),Sizing.fixed(20));
|
||||||
|
|
||||||
super.render(context, mouseX, mouseY, delta);
|
loop_btn = (ButtonComponent) Components.button(Text.of(""),
|
||||||
|
(ButtonComponent btn) -> {
|
||||||
for (RenderListener l : render_listeners) {
|
mod.loop_replay = !mod.loop_replay;
|
||||||
if (!l.beforeRender()) {
|
update_btns();
|
||||||
l.render(context, mouseX, mouseY, delta);
|
}).margins(Insets.of(1))
|
||||||
}
|
.sizing(Sizing.fixed(20),Sizing.fixed(20));
|
||||||
}
|
|
||||||
}
|
record_btn = (ButtonComponent) Components.button(Text.of("record"),
|
||||||
|
(ButtonComponent btn) -> {
|
||||||
@Override
|
if (!mod.is_replaying) {
|
||||||
protected void init() {
|
if (mod.is_recording)
|
||||||
RecordListWidget list_widget = Main.me.record_list.getWidget();
|
mod.stopRecording();
|
||||||
|
else mod.startRecording();
|
||||||
list_widget.setX(width / 2 + 2);
|
update_btns();
|
||||||
list_widget.setY(height / 2 - list_widget.getHeight() / 2);
|
}
|
||||||
list_widget.init(this);
|
}).margins(Insets.of(1)).sizing(
|
||||||
|
Sizing.fixed(120),Sizing.fixed(20));
|
||||||
|
was_build = true;
|
||||||
record_btn = ButtonWidget.builder(
|
|
||||||
Text.translatable("text.repeating-mod.start_record"), button -> {
|
rootComponent.child(
|
||||||
if (!Main.me.is_replaying) {
|
Containers.horizontalFlow(Sizing.content(), Sizing.content()).child(
|
||||||
if (Main.me.is_recording)
|
Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
Main.me.stopRecording();
|
.child(Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
else Main.me.startRecording();
|
.child(Components.label(Text.translatable("text.repeating-mod.basic")).margins(Insets.of(1)))
|
||||||
updateButtons();
|
.padding(Insets.of(5))
|
||||||
}
|
.surface(Surface.DARK_PANEL)
|
||||||
})
|
.verticalAlignment(VerticalAlignment.CENTER)
|
||||||
.dimensions(width / 2 - 120, height / 2 - 32, 120, 20)
|
.horizontalAlignment(HorizontalAlignment.CENTER)
|
||||||
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.record_tooltip")))
|
.margins(Insets.of(1)))
|
||||||
.build();
|
.child(Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
|
.child(Containers.horizontalFlow(Sizing.content(), Sizing.content())
|
||||||
loop_btn = ButtonWidget.builder(Text.empty(), button -> {
|
.child(replay_btn).child(loop_btn))
|
||||||
Main.me.loop_replay = !Main.me.loop_replay;
|
.child(record_btn)
|
||||||
updateButtons();
|
.child(Components.button(Text.translatable(
|
||||||
})
|
"text.repeating-mod.export"),
|
||||||
.dimensions(width / 2 - 120, height / 2 - 10, 120, 20)
|
(ButtonComponent btn) -> {
|
||||||
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.loop_tooltip")))
|
String t = "";
|
||||||
.build();
|
for (int i = 0; i < mod.record.size(); i++) {
|
||||||
|
t += mod.record.get(i).toText();
|
||||||
pos_delay_slider = new SliderWidget(
|
if (i != mod.record.size()-1)
|
||||||
width / 2 - 120, height / 2 + 12, 120, 20,
|
t += "\n";
|
||||||
(Main.me.record_pos_delay < 0) ? Text.translatable("text.repeating-mod.nan_pos_delay") :
|
}
|
||||||
Text.translatable("text.repeating-mod.pos_delay", String.valueOf(Main.me.record_pos_delay)),
|
|
||||||
(Main.me.record_pos_delay+1d)/101d) {
|
File p = new File(FabricLoader.getInstance().getGameDir().toFile(),"repeating");
|
||||||
|
if (!p.exists()) p.mkdir();
|
||||||
@Override
|
File file = new File(p,"export.txt");
|
||||||
protected void updateMessage() {
|
|
||||||
double v = value*101d-1d;
|
try {
|
||||||
if (v <= 1) setMessage(Text.translatable("text.repeating-mod.nan_pos_delay"));
|
if (!file.exists()) file.createNewFile();
|
||||||
else setMessage(Text.translatable("text.repeating-mod.pos_delay", String.valueOf((long) v)));
|
Files.write(file.toPath(), t.getBytes());
|
||||||
}
|
Runtime.getRuntime().exec("explorer /select,\""+file.getAbsolutePath()+"\"");
|
||||||
|
} catch (Exception e) {
|
||||||
@Override
|
e.printStackTrace();
|
||||||
protected void applyValue() {
|
}
|
||||||
double v = value*101d-1d;
|
}).margins(Insets.of(10,1,1,1)).sizing(
|
||||||
if (v <= 1) setMessage(Text.translatable("text.repeating-mod.nan_pos_delay"));
|
Sizing.fixed(120),Sizing.fixed(20)))
|
||||||
else setMessage(Text.translatable("text.repeating-mod.pos_delay", String.valueOf((long) v)));
|
.child(Components.button(Text.translatable(
|
||||||
Main.me.record_pos_delay = (long) v;
|
"text.repeating-mod.import"),
|
||||||
Main.me.conf.data.put("record_pos_delay",String.valueOf(Main.me.record_pos_delay));
|
(ButtonComponent btn) -> {
|
||||||
Main.me.conf.save();
|
mod.record.clear();
|
||||||
}
|
|
||||||
|
File p = new File(FabricLoader.getInstance().getGameDir().toFile(),"repeating");
|
||||||
@Override
|
if (!p.exists()) p.mkdir();
|
||||||
public void onRelease(double mouseX, double mouseY) {
|
File file = new File(p,"import.txt");
|
||||||
super.onRelease(mouseX, mouseY);
|
|
||||||
applyValue();
|
try {
|
||||||
}
|
if (!file.exists()) {
|
||||||
|
file.createNewFile();
|
||||||
@Override
|
Runtime.getRuntime().exec("explorer /select,\""+file.getAbsolutePath()+"\"");
|
||||||
protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY) {
|
return;
|
||||||
super.onDrag(mouseX, mouseY, deltaX, deltaY);
|
}
|
||||||
applyValue();
|
String t = Files.readString(file.toPath());
|
||||||
}
|
for (String s:t.split("\n"))
|
||||||
};
|
mod.record.add(RepeatingMod.RecordEvent.fromText(s));
|
||||||
pos_delay_slider.setTooltip(Tooltip.of(Text.translatable("text.repeating-mod.pos_delay_tooltip")));
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
import_btn = ButtonWidget.builder(Text.translatable("text.repeating-mod.import"), button -> {
|
}
|
||||||
new Thread(() -> {
|
}).margins(Insets.of(1)).sizing(
|
||||||
FileDialog fd = new FileDialog((java.awt.Frame) null);
|
Sizing.fixed(120),Sizing.fixed(20)))
|
||||||
fd.setMultipleMode(true);
|
.padding(Insets.of(10))
|
||||||
fd.setName("Choose record files");
|
.surface(Surface.DARK_PANEL)
|
||||||
fd.setTitle("Choose record files");
|
.verticalAlignment(VerticalAlignment.CENTER)
|
||||||
fd.setFilenameFilter((dir, name) -> name.endsWith(".rrm"));
|
.horizontalAlignment(HorizontalAlignment.CENTER)
|
||||||
fd.setVisible(true);
|
.margins(Insets.of(1)))
|
||||||
|
/*).child(
|
||||||
File[] files = fd.getFiles();
|
Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
if (files != null) {
|
.child(Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
for (File file : files) {
|
.child(Components.label(Text.translatable("text.repeating-mod.parkour")).margins(Insets.of(1)))
|
||||||
try {
|
.padding(Insets.of(5))
|
||||||
Main.me.setNowRecord(Main.me.record_list.cloneRecord(file));
|
.surface(Surface.DARK_PANEL)
|
||||||
} catch (Exception e) {
|
.verticalAlignment(VerticalAlignment.CENTER)
|
||||||
throw new RuntimeException(e);
|
.horizontalAlignment(HorizontalAlignment.CENTER)
|
||||||
}
|
.margins(Insets.of(1)))
|
||||||
}
|
.child(Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
}}).start();
|
.child(Components.label(Text.translatable("text.repeating-mod.dev")).margins(Insets.of(1)))
|
||||||
})
|
.padding(Insets.of(10))
|
||||||
.dimensions(width / 2 + 2, height / 2 - list_widget.getHeight() / 2 - 22, 180, 20)
|
.surface(Surface.DARK_PANEL)
|
||||||
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.import_tooltip")))
|
.verticalAlignment(VerticalAlignment.CENTER)
|
||||||
.build();
|
.horizontalAlignment(HorizontalAlignment.CENTER)
|
||||||
|
.margins(Insets.of(1)))*/
|
||||||
was_build = true;
|
).child(
|
||||||
|
Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
updateButtons();
|
.child(Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
|
.child(Components.label(Text.translatable("text.repeating-mod.settings")).margins(Insets.of(1)))
|
||||||
addDrawableChild(loop_btn);
|
.padding(Insets.of(5))
|
||||||
addDrawableChild(record_btn);
|
.surface(Surface.DARK_PANEL)
|
||||||
addDrawableChild(import_btn);
|
.verticalAlignment(VerticalAlignment.CENTER)
|
||||||
addDrawableChild(pos_delay_slider);
|
.horizontalAlignment(HorizontalAlignment.CENTER)
|
||||||
}
|
.margins(Insets.of(1)))
|
||||||
|
.child(Containers.verticalFlow(Sizing.content(), Sizing.content())
|
||||||
public <T extends Element & Drawable & Selectable> T addDrawableChild(T drawableElement) {
|
.child(Components.discreteSlider(Sizing.fixed(120),-24,5000)
|
||||||
return super.addDrawableChild(drawableElement);
|
.setFromDiscreteValue(mod.record_pos_delay)
|
||||||
}
|
.message((String s)->{
|
||||||
|
mod.record_pos_delay = Long.parseLong(s);
|
||||||
public <T extends Drawable> T addDrawable(T drawable) {
|
mod.conf.data.put("record_pos_delay",String.valueOf(mod.record_pos_delay));
|
||||||
return super.addDrawable(drawable);
|
mod.conf.save();
|
||||||
}
|
if (mod.record_pos_delay > -1)
|
||||||
|
return Text.translatable("text.repeating-mod.pos_delay", s);
|
||||||
public <T extends Element & Selectable> T addSelectableChild(T child) {
|
return Text.translatable("text.repeating-mod.nan_pos_delay", s);
|
||||||
return super.addSelectableChild(child);
|
}).scrollStep(25)
|
||||||
}
|
.margins(Insets.of(1))
|
||||||
|
.tooltip(Text.translatable("text.repeating-mod.pos_delay_text")))
|
||||||
public void remove(Element child) {
|
.padding(Insets.of(10))
|
||||||
super.remove(child);
|
.surface(Surface.DARK_PANEL)
|
||||||
}
|
.verticalAlignment(VerticalAlignment.CENTER)
|
||||||
}
|
.horizontalAlignment(HorizontalAlignment.CENTER)
|
||||||
|
.margins(Insets.of(1)))
|
||||||
|
));
|
||||||
|
update_btns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
package themixray.repeating.mod;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class TickTask implements Runnable {
|
|
||||||
public static List<TickTask> tasks = new ArrayList<>();
|
|
||||||
|
|
||||||
public static void tickTasks(TickAt at) {
|
|
||||||
for (TickTask t:new ArrayList<>(tasks))
|
|
||||||
if (t.getAt() == at) t.tick();
|
|
||||||
}
|
|
||||||
|
|
||||||
private long living;
|
|
||||||
private long delay;
|
|
||||||
|
|
||||||
private boolean is_repeating;
|
|
||||||
private long period;
|
|
||||||
|
|
||||||
private boolean is_cancelled;
|
|
||||||
private TickAt at;
|
|
||||||
|
|
||||||
public enum TickAt {
|
|
||||||
CLIENT_HEAD, CLIENT_TAIL,
|
|
||||||
MOVEMENT_HEAD, MOVEMENT_TAIL,
|
|
||||||
RENDER_HEAD, RENDER_TAIL,
|
|
||||||
CLIENT_EVENT
|
|
||||||
}
|
|
||||||
|
|
||||||
public TickTask(long delay, TickAt at) {
|
|
||||||
this.is_cancelled = false;
|
|
||||||
this.is_repeating = false;
|
|
||||||
this.delay = delay;
|
|
||||||
this.living = 0;
|
|
||||||
this.period = 0;
|
|
||||||
this.at = at;
|
|
||||||
tasks.add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TickTask(long delay, long period, TickAt at) {
|
|
||||||
this.is_cancelled = false;
|
|
||||||
this.is_repeating = true;
|
|
||||||
this.delay = delay;
|
|
||||||
this.period = period;
|
|
||||||
this.living = 0;
|
|
||||||
this.at = at;
|
|
||||||
tasks.add(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TickTask(long delay) {
|
|
||||||
this(delay,TickAt.CLIENT_HEAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TickTask(long delay, long period) {
|
|
||||||
this(delay,period,TickAt.CLIENT_HEAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancel() {
|
|
||||||
if (!is_cancelled) {
|
|
||||||
is_cancelled = true;
|
|
||||||
tasks.remove(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return is_cancelled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TickAt getAt() {
|
|
||||||
return at;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDelay(long delay) {
|
|
||||||
if (is_repeating) {
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public long getDelay() {
|
|
||||||
return this.delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void tick() {
|
|
||||||
if (living >= delay) {
|
|
||||||
if (is_repeating) {
|
|
||||||
delay = period;
|
|
||||||
run();
|
|
||||||
living = -1;
|
|
||||||
} else {
|
|
||||||
run();
|
|
||||||
cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
living++;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package themixray.repeating.mod.event;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.event.events.*;
|
|
||||||
|
|
||||||
public abstract class RecordEvent {
|
|
||||||
public abstract void replay();
|
|
||||||
public RecordEventType getType() {
|
|
||||||
for (RecordEventType ev : RecordEventType.values()) {
|
|
||||||
if (ev.getEventClass().getTypeName().equals(this.getClass().getTypeName())) {
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
protected abstract String[] serializeArgs();
|
|
||||||
public String serialize() {
|
|
||||||
return getType().getChar() + "=" + String.join("&", serializeArgs());
|
|
||||||
}
|
|
||||||
public static RecordEvent deserialize(String t) {
|
|
||||||
return RecordEventType.getByChar(t.charAt(0)).deserialize(t.substring(2).split("&"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
package themixray.repeating.mod.event;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.event.events.*;
|
|
||||||
|
|
||||||
public enum RecordEventType {
|
|
||||||
BLOCK_BREAK('b',"block_break",BlockBreakEvent.class),
|
|
||||||
BLOCK_INTERACT('i',"block_interact",BlockInteractEvent.class),
|
|
||||||
DELAY('d',"delay",DelayEvent.class),
|
|
||||||
INPUT('p',"input",InputEvent.class),
|
|
||||||
MOVE('m',"move",MoveEvent.class);
|
|
||||||
// GUI_KEY_PRESS('r',"key_press", GuiKeyPressEvent.class),
|
|
||||||
// GUI_KEY_RELEASE('s',"key_release",GuiKeyReleaseEvent.class),
|
|
||||||
// GUI_CHAR_TYPE('h',"char_type",GuiCharTypeEvent.class),
|
|
||||||
// GUI_MOUSE_CLICK('c',"mouse_click",GuiMouseClickEvent.class),
|
|
||||||
// GUI_MOUSE_RELEASE('l',"mouse_release",GuiMouseReleaseEvent.class),
|
|
||||||
// GUI_MOUSE_DRAG('g',"mouse_drag",GuiMouseDragEvent.class),
|
|
||||||
// GUI_MOUSE_MOVE('v',"mouse_move",GuiMouseMoveEvent.class),
|
|
||||||
// GUI_MOUSE_SCROLL('o',"mouse_scroll",GuiMouseScrollEvent.class),
|
|
||||||
// GUI_CLOSE('e',"close",GuiCloseEvent.class);
|
|
||||||
|
|
||||||
private Class<? extends RecordEvent> ev;
|
|
||||||
private char ch;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
RecordEventType(char ch, String name, Class<? extends RecordEvent> ev) {
|
|
||||||
this.ev = ev;
|
|
||||||
this.ch = ch;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<? extends RecordEvent> getEventClass() {
|
|
||||||
return ev;
|
|
||||||
}
|
|
||||||
|
|
||||||
public char getChar() {
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordEvent deserialize(String[] args) {
|
|
||||||
try {
|
|
||||||
return (RecordEvent) ev
|
|
||||||
.getMethod("deserialize", String[].class)
|
|
||||||
.invoke(null, (Object) args);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String serialize(RecordEvent event) {
|
|
||||||
return event.serialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RecordEventType getByChar(String type) {
|
|
||||||
return getByChar(type.charAt(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RecordEventType getByChar(char ch) {
|
|
||||||
for (RecordEventType t : values()) {
|
|
||||||
if (t.getChar() == ch) {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class BlockBreakEvent extends RecordEvent {
|
|
||||||
public BlockPos pos;
|
|
||||||
|
|
||||||
public BlockBreakEvent(
|
|
||||||
BlockPos pos) {
|
|
||||||
this.pos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlockBreakEvent deserialize(String[] a) {
|
|
||||||
return new BlockBreakEvent(new BlockPos(
|
|
||||||
Integer.parseInt(a[0]),
|
|
||||||
Integer.parseInt(a[1]),
|
|
||||||
Integer.parseInt(a[2])));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[]{
|
|
||||||
String.valueOf(pos.getX()),
|
|
||||||
String.valueOf(pos.getY()),
|
|
||||||
String.valueOf(pos.getZ())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.interactionManager != null) {
|
|
||||||
Main.client.interactionManager.breakBlock(pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import net.minecraft.util.Hand;
|
|
||||||
import net.minecraft.util.hit.BlockHitResult;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Direction;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class BlockInteractEvent extends RecordEvent {
|
|
||||||
public Hand hand;
|
|
||||||
public BlockHitResult hitResult;
|
|
||||||
|
|
||||||
public static BlockInteractEvent deserialize(String[] a) {
|
|
||||||
return new BlockInteractEvent(
|
|
||||||
Hand.valueOf(a[5]),
|
|
||||||
new BlockHitResult(new Vec3d(
|
|
||||||
Double.parseDouble(a[0]),
|
|
||||||
Double.parseDouble(a[1]),
|
|
||||||
Double.parseDouble(a[2])),
|
|
||||||
Direction.byId(Integer.parseInt(a[4])),
|
|
||||||
new BlockPos(
|
|
||||||
Integer.parseInt(a[0]),
|
|
||||||
Integer.parseInt(a[1]),
|
|
||||||
Integer.parseInt(a[2])),
|
|
||||||
a[3].equals("1")));
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockInteractEvent(Hand hand, BlockHitResult hitResult) {
|
|
||||||
this.hand = hand;
|
|
||||||
this.hitResult = hitResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.interactionManager != null) {
|
|
||||||
Main.client.interactionManager.interactBlock(Main.client.player, hand, hitResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[]{
|
|
||||||
String.valueOf(hitResult.getBlockPos().getX()),
|
|
||||||
String.valueOf(hitResult.getBlockPos().getY()),
|
|
||||||
String.valueOf(hitResult.getBlockPos().getZ()),
|
|
||||||
(hitResult.isInsideBlock() ? "1" : "0"),
|
|
||||||
String.valueOf(hitResult.getSide().getId()),
|
|
||||||
hand.name()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class DelayEvent extends RecordEvent {
|
|
||||||
public long delay;
|
|
||||||
|
|
||||||
public static DelayEvent deserialize(String[] a) {
|
|
||||||
return new DelayEvent(Long.parseLong(a[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public DelayEvent(long delay) {
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
try {
|
|
||||||
Thread.sleep(delay / 20 * 1000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[]{
|
|
||||||
String.valueOf(delay)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiCharTypeEvent extends RecordEvent {
|
|
||||||
private char chr;
|
|
||||||
private int modifiers;
|
|
||||||
|
|
||||||
public GuiCharTypeEvent(char chr, int modifiers) {
|
|
||||||
this.chr = chr;
|
|
||||||
this.modifiers = modifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
Main.client.currentScreen.charTyped(chr, modifiers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
String.valueOf((int) chr),
|
|
||||||
String.valueOf(modifiers)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiCharTypeEvent deserialize(String[] args) {
|
|
||||||
return new GuiCharTypeEvent(
|
|
||||||
(char) Integer.parseInt(args[0]),
|
|
||||||
Integer.parseInt(args[1])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiCloseEvent extends RecordEvent {
|
|
||||||
public GuiCloseEvent() {}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
Main.client.setScreen(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiCloseEvent deserialize(String[] args) {
|
|
||||||
return new GuiCloseEvent();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiKeyPressEvent extends RecordEvent {
|
|
||||||
private int keyCode;
|
|
||||||
private int scanCode;
|
|
||||||
private int modifiers;
|
|
||||||
|
|
||||||
public GuiKeyPressEvent(int keyCode, int scanCode, int modifiers) {
|
|
||||||
this.keyCode = keyCode;
|
|
||||||
this.scanCode = scanCode;
|
|
||||||
this.modifiers = modifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
Main.client.currentScreen.keyPressed(keyCode, scanCode, modifiers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
String.valueOf(keyCode),
|
|
||||||
String.valueOf(scanCode),
|
|
||||||
String.valueOf(modifiers)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiKeyPressEvent deserialize(String[] args) {
|
|
||||||
return new GuiKeyPressEvent(
|
|
||||||
Integer.parseInt(args[0]),
|
|
||||||
Integer.parseInt(args[1]),
|
|
||||||
Integer.parseInt(args[2])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiKeyReleaseEvent extends RecordEvent {
|
|
||||||
private int keyCode;
|
|
||||||
private int scanCode;
|
|
||||||
private int modifiers;
|
|
||||||
|
|
||||||
public GuiKeyReleaseEvent(int keyCode, int scanCode, int modifiers) {
|
|
||||||
this.keyCode = keyCode;
|
|
||||||
this.scanCode = scanCode;
|
|
||||||
this.modifiers = modifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
Main.client.currentScreen.keyReleased(keyCode, scanCode, modifiers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
String.valueOf(keyCode),
|
|
||||||
String.valueOf(scanCode),
|
|
||||||
String.valueOf(modifiers)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiKeyReleaseEvent deserialize(String[] args) {
|
|
||||||
return new GuiKeyReleaseEvent(
|
|
||||||
Integer.parseInt(args[0]),
|
|
||||||
Integer.parseInt(args[1]),
|
|
||||||
Integer.parseInt(args[2])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiMouseClickEvent extends RecordEvent {
|
|
||||||
private double mouseX;
|
|
||||||
private double mouseY;
|
|
||||||
private int button;
|
|
||||||
|
|
||||||
public GuiMouseClickEvent(double mouseX, double mouseY, int button) {
|
|
||||||
this.mouseX = mouseX;
|
|
||||||
this.mouseY = mouseY;
|
|
||||||
this.button = button;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
Main.client.currentScreen.mouseClicked(mouseX, mouseY, button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
String.valueOf(mouseX),
|
|
||||||
String.valueOf(mouseY),
|
|
||||||
String.valueOf(button)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiMouseClickEvent deserialize(String[] args) {
|
|
||||||
return new GuiMouseClickEvent(
|
|
||||||
Double.parseDouble(args[0]),
|
|
||||||
Double.parseDouble(args[1]),
|
|
||||||
Integer.parseInt(args[2])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiMouseDragEvent extends RecordEvent {
|
|
||||||
private double mouseX;
|
|
||||||
private double mouseY;
|
|
||||||
private double deltaX;
|
|
||||||
private double deltaY;
|
|
||||||
private int button;
|
|
||||||
|
|
||||||
public GuiMouseDragEvent(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
|
|
||||||
this.mouseX = mouseX;
|
|
||||||
this.mouseY = mouseY;
|
|
||||||
this.deltaX = deltaX;
|
|
||||||
this.deltaY = deltaY;
|
|
||||||
this.button = button;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
Main.client.currentScreen.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
String.valueOf(mouseX),
|
|
||||||
String.valueOf(mouseY),
|
|
||||||
String.valueOf(button),
|
|
||||||
String.valueOf(deltaX),
|
|
||||||
String.valueOf(deltaY)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiMouseDragEvent deserialize(String[] args) {
|
|
||||||
return new GuiMouseDragEvent(
|
|
||||||
Double.parseDouble(args[0]),
|
|
||||||
Double.parseDouble(args[1]),
|
|
||||||
Integer.parseInt(args[2]),
|
|
||||||
Double.parseDouble(args[3]),
|
|
||||||
Double.parseDouble(args[4])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiMouseMoveEvent extends RecordEvent {
|
|
||||||
private double mouseX;
|
|
||||||
private double mouseY;
|
|
||||||
|
|
||||||
public GuiMouseMoveEvent(double mouseX, double mouseY) {
|
|
||||||
this.mouseX = mouseX;
|
|
||||||
this.mouseY = mouseY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
Main.client.currentScreen.mouseMoved(mouseX, mouseY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
String.valueOf(mouseX),
|
|
||||||
String.valueOf(mouseY)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiMouseMoveEvent deserialize(String[] args) {
|
|
||||||
return new GuiMouseMoveEvent(
|
|
||||||
Double.parseDouble(args[0]),
|
|
||||||
Double.parseDouble(args[1])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiMouseReleaseEvent extends RecordEvent {
|
|
||||||
private double mouseX;
|
|
||||||
private double mouseY;
|
|
||||||
private int button;
|
|
||||||
|
|
||||||
public GuiMouseReleaseEvent(double mouseX, double mouseY, int button) {
|
|
||||||
this.mouseX = mouseX;
|
|
||||||
this.mouseY = mouseY;
|
|
||||||
this.button = button;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
Main.client.currentScreen.mouseReleased(mouseX, mouseY, button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
String.valueOf(mouseX),
|
|
||||||
String.valueOf(mouseY),
|
|
||||||
String.valueOf(button)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiMouseReleaseEvent deserialize(String[] args) {
|
|
||||||
return new GuiMouseReleaseEvent(
|
|
||||||
Double.parseDouble(args[0]),
|
|
||||||
Double.parseDouble(args[1]),
|
|
||||||
Integer.parseInt(args[2])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class GuiMouseScrollEvent extends RecordEvent {
|
|
||||||
private double mouseX;
|
|
||||||
private double mouseY;
|
|
||||||
private double amount;
|
|
||||||
|
|
||||||
public GuiMouseScrollEvent(double mouseX, double mouseY, double amount) {
|
|
||||||
this.mouseX = mouseX;
|
|
||||||
this.mouseY = mouseY;
|
|
||||||
this.amount = amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.currentScreen != null) {
|
|
||||||
// Main.client.currentScreen.mouseScrolled(mouseX, mouseY, amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
String.valueOf(mouseX),
|
|
||||||
String.valueOf(mouseY),
|
|
||||||
String.valueOf(amount)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GuiMouseScrollEvent deserialize(String[] args) {
|
|
||||||
return new GuiMouseScrollEvent(
|
|
||||||
Double.parseDouble(args[0]),
|
|
||||||
Double.parseDouble(args[1]),
|
|
||||||
Double.parseDouble(args[2])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class InputEvent extends RecordEvent {
|
|
||||||
public Boolean sneaking;
|
|
||||||
public Boolean jumping;
|
|
||||||
public Boolean pressingForward;
|
|
||||||
public Boolean pressingBack;
|
|
||||||
public Boolean pressingLeft;
|
|
||||||
public Boolean pressingRight;
|
|
||||||
public Boolean sprinting;
|
|
||||||
|
|
||||||
public Float movementSideways;
|
|
||||||
public Float movementForward;
|
|
||||||
|
|
||||||
public float yaw;
|
|
||||||
public float head_yaw;
|
|
||||||
public float body_yaw;
|
|
||||||
public float pitch;
|
|
||||||
public float speed;
|
|
||||||
|
|
||||||
public InputEvent(Boolean sneaking,
|
|
||||||
Boolean jumping,
|
|
||||||
Float movementSideways,
|
|
||||||
Float movementForward,
|
|
||||||
Boolean pressingForward,
|
|
||||||
Boolean pressingBack,
|
|
||||||
Boolean pressingLeft,
|
|
||||||
Boolean pressingRight,
|
|
||||||
float head_yaw,
|
|
||||||
float body_yaw,
|
|
||||||
float head_pitch,
|
|
||||||
Boolean sprinting,
|
|
||||||
float yaw,
|
|
||||||
float speed) {
|
|
||||||
this.sneaking = sneaking;
|
|
||||||
this.jumping = jumping;
|
|
||||||
this.movementSideways = movementSideways;
|
|
||||||
this.movementForward = movementForward;
|
|
||||||
this.pressingForward = pressingForward;
|
|
||||||
this.pressingBack = pressingBack;
|
|
||||||
this.pressingLeft = pressingLeft;
|
|
||||||
this.pressingRight = pressingRight;
|
|
||||||
this.head_yaw = head_yaw;
|
|
||||||
this.body_yaw = body_yaw;
|
|
||||||
this.pitch = head_pitch;
|
|
||||||
this.sprinting = sprinting;
|
|
||||||
this.yaw = yaw;
|
|
||||||
this.speed = speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputEvent deserialize(String[] a) {
|
|
||||||
return new InputEvent(
|
|
||||||
(a[0].equals("n") ? null : a[0].equals("1")),
|
|
||||||
(a[1].equals("n") ? null : a[1].equals("1")),
|
|
||||||
(a[2].equals("n") ? null : Float.parseFloat(a[2])),
|
|
||||||
(a[3].equals("n") ? null : Float.parseFloat(a[3])),
|
|
||||||
(a[4].equals("n") ? null : a[4].equals("1")),
|
|
||||||
(a[5].equals("n") ? null : a[5].equals("1")),
|
|
||||||
(a[6].equals("n") ? null : a[6].equals("1")),
|
|
||||||
(a[7].equals("n") ? null : a[7].equals("1")),
|
|
||||||
Float.parseFloat(a[8]), Float.parseFloat(a[9]),
|
|
||||||
Float.parseFloat(a[10]),
|
|
||||||
(a[11].equals("n") ? null : a[11].equals("1")),
|
|
||||||
Float.parseFloat(a[12]),
|
|
||||||
Float.parseFloat(a[13]));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[] {
|
|
||||||
((sneaking == null) ? "n" : (sneaking ? "1" : "0")), // sneaking
|
|
||||||
((jumping == null) ? "n" : (jumping ? "1" : "0")), // jumping
|
|
||||||
((movementSideways == null) ? "n" : String.valueOf(movementSideways)), // movement sideways
|
|
||||||
((movementForward == null) ? "n" : String.valueOf(movementForward)), // movement forward
|
|
||||||
((pressingForward == null) ? "n" : (pressingForward ? "1" : "0")), // pressing forward
|
|
||||||
((pressingBack == null) ? "n" : (pressingBack ? "1" : "0")), // pressing back
|
|
||||||
((pressingLeft == null) ? "n" : (pressingLeft ? "1" : "0")), // pressing left
|
|
||||||
((pressingRight == null) ? "n" : (pressingRight ? "1" : "0")), // pressing right
|
|
||||||
String.valueOf(head_yaw), // head yaw
|
|
||||||
String.valueOf(body_yaw), // body yaw
|
|
||||||
String.valueOf(pitch), // pitch
|
|
||||||
((sprinting == null) ? "n" : (sprinting ? "1" : "0")), // sprinting
|
|
||||||
String.valueOf(yaw), // yaw
|
|
||||||
String.valueOf(speed) // speed
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fillEmpty(InputEvent e) {
|
|
||||||
if (sneaking == null) sneaking = e.sneaking;
|
|
||||||
if (jumping == null) jumping = e.jumping;
|
|
||||||
if (movementSideways == null) movementSideways = e.movementSideways;
|
|
||||||
if (movementForward == null) movementForward = e.movementForward;
|
|
||||||
if (pressingForward == null) pressingForward = e.pressingForward;
|
|
||||||
if (pressingBack == null) pressingBack = e.pressingBack;
|
|
||||||
if (pressingLeft == null) pressingLeft = e.pressingLeft;
|
|
||||||
if (pressingRight == null) pressingRight = e.pressingRight;
|
|
||||||
if (sprinting == null) sprinting = e.sprinting;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return sneaking == null &&
|
|
||||||
jumping == null &&
|
|
||||||
movementSideways == null &&
|
|
||||||
movementForward == null &&
|
|
||||||
pressingForward == null &&
|
|
||||||
pressingBack == null &&
|
|
||||||
pressingLeft == null &&
|
|
||||||
pressingRight == null &&
|
|
||||||
sprinting == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
Main.input_replay = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void inputCallback() {
|
|
||||||
if (Main.client.player != null) {
|
|
||||||
if (sprinting != null && Main.client.player.isSprinting() != sprinting)
|
|
||||||
Main.client.player.setSprinting(sprinting);
|
|
||||||
if (Main.client.player.getYaw() != yaw)
|
|
||||||
Main.client.player.setYaw(yaw);
|
|
||||||
if (Main.client.player.getHeadYaw() != head_yaw)
|
|
||||||
Main.client.player.setHeadYaw(head_yaw);
|
|
||||||
if (Main.client.player.getBodyYaw() != body_yaw)
|
|
||||||
Main.client.player.setBodyYaw(body_yaw);
|
|
||||||
if (Main.client.player.getPitch() != pitch)
|
|
||||||
Main.client.player.setPitch(pitch);
|
|
||||||
if (Main.client.player.getMovementSpeed() != speed)
|
|
||||||
Main.client.player.setMovementSpeed(speed);
|
|
||||||
if (sneaking != null && Main.client.player.input.sneaking != sneaking)
|
|
||||||
Main.client.player.input.sneaking = sneaking;
|
|
||||||
if (jumping != null && Main.client.player.input.jumping != jumping)
|
|
||||||
Main.client.player.input.jumping = jumping;
|
|
||||||
if (movementSideways != null && Main.client.player.input.movementSideways != movementSideways)
|
|
||||||
Main.client.player.input.movementSideways = movementSideways;
|
|
||||||
if (movementForward != null && Main.client.player.input.movementForward != movementForward)
|
|
||||||
Main.client.player.input.movementForward = movementForward;
|
|
||||||
if (pressingForward != null && Main.client.player.input.pressingForward != pressingForward)
|
|
||||||
Main.client.player.input.pressingForward = pressingForward;
|
|
||||||
if (pressingBack != null && Main.client.player.input.pressingBack != pressingBack)
|
|
||||||
Main.client.player.input.pressingBack = pressingBack;
|
|
||||||
if (pressingLeft != null && Main.client.player.input.pressingLeft != pressingLeft)
|
|
||||||
Main.client.player.input.pressingLeft = pressingLeft;
|
|
||||||
if (pressingRight != null && Main.client.player.input.pressingRight != pressingRight)
|
|
||||||
Main.client.player.input.pressingRight = pressingRight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package themixray.repeating.mod.event.events;
|
|
||||||
|
|
||||||
import net.minecraft.entity.MovementType;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.event.RecordEvent;
|
|
||||||
|
|
||||||
public class MoveEvent extends RecordEvent {
|
|
||||||
public Vec3d vec;
|
|
||||||
public float yaw;
|
|
||||||
public float pitch;
|
|
||||||
|
|
||||||
public static MoveEvent deserialize(String[] a) {
|
|
||||||
return new MoveEvent(new Vec3d(
|
|
||||||
Double.parseDouble(a[0]),
|
|
||||||
Double.parseDouble(a[1]),
|
|
||||||
Double.parseDouble(a[2])),
|
|
||||||
Float.parseFloat(a[3]),
|
|
||||||
Float.parseFloat(a[4]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public MoveEvent(Vec3d vec, float yaw, float pitch) {
|
|
||||||
this.vec = vec;
|
|
||||||
this.yaw = yaw;
|
|
||||||
this.pitch = pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void replay() {
|
|
||||||
if (Main.client.player != null) {
|
|
||||||
Vec3d p = Main.client.player.getPos();
|
|
||||||
Vec3d v = new Vec3d(vec.getX() - p.getX(), vec.getY() - p.getY(), vec.getZ() - p.getZ());
|
|
||||||
Main.client.player.move(MovementType.SELF, v);
|
|
||||||
Main.client.player.setYaw(yaw);
|
|
||||||
Main.client.player.setPitch(pitch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String[] serializeArgs() {
|
|
||||||
return new String[]{
|
|
||||||
String.valueOf(vec.getX()),
|
|
||||||
String.valueOf(vec.getZ()),
|
|
||||||
String.valueOf(yaw),
|
|
||||||
String.valueOf(pitch)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
package themixray.repeating.mod.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.TickTask;
|
|
||||||
|
|
||||||
@Mixin(MinecraftClient.class)
|
|
||||||
public abstract class ClientMixin {
|
|
||||||
@Inject(at = @At(value = "HEAD"), method = "tick")
|
|
||||||
private void onTickHead(CallbackInfo ci) {
|
|
||||||
if (Main.me.is_recording)
|
|
||||||
Main.me.recordAllInput();
|
|
||||||
TickTask.tickTasks(TickTask.TickAt.CLIENT_HEAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(at = @At(value = "TAIL"), method = "tick")
|
|
||||||
private void onTickTail(CallbackInfo ci) {
|
|
||||||
TickTask.tickTasks(TickTask.TickAt.CLIENT_TAIL);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package themixray.repeating.mod.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Mixin(Entity.class)
|
|
||||||
public abstract class EntityMixin {
|
|
||||||
@Shadow public abstract UUID getUuid();
|
|
||||||
|
|
||||||
@Inject(at = @At(value = "HEAD"), method = "setSprinting", cancellable = true)
|
|
||||||
private void onSprint(boolean sprinting,CallbackInfo ci) {
|
|
||||||
if (Main.client.player != null) {
|
|
||||||
if (getUuid().equals(Main.client.player.getUuid())) {
|
|
||||||
if (Main.me.is_replaying) {
|
|
||||||
if (Main.input_replay != null &&
|
|
||||||
Main.input_replay.sprinting != null &&
|
|
||||||
Main.input_replay.sprinting != sprinting) {
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +1,20 @@
|
|||||||
package themixray.repeating.mod.mixin;
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
import net.minecraft.client.input.KeyboardInput;
|
import net.minecraft.client.input.KeyboardInput;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import themixray.repeating.mod.Main;
|
import themixray.repeating.mod.RepeatingMod;
|
||||||
|
|
||||||
@Mixin(KeyboardInput.class)
|
@Mixin(KeyboardInput.class)
|
||||||
public abstract class InputMixin {
|
public abstract class InputMixin {
|
||||||
@Inject(at = @At(value = "TAIL"), method = "tick")
|
@Inject(at = @At(value = "TAIL"), method = "tick")
|
||||||
private void onTickTail(boolean slowDown, float f, CallbackInfo ci) {
|
private void onTickTail(boolean slowDown, float f, CallbackInfo ci) {
|
||||||
if (Main.me.is_replaying) {
|
if (RepeatingMod.me.is_replaying) {
|
||||||
if (Main.input_replay != null) {
|
if (RepeatingMod.input_replay != null) {
|
||||||
Main.input_replay.inputCallback();
|
RepeatingMod.input_replay.inputCallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,44 +1,65 @@
|
|||||||
package themixray.repeating.mod.mixin;
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||||
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||||
import net.minecraft.client.network.ClientPlayerEntity;
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.hit.HitResult;
|
import net.minecraft.util.hit.HitResult;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import themixray.repeating.mod.Main;
|
import themixray.repeating.mod.RepeatingMod;
|
||||||
import themixray.repeating.mod.event.events.BlockBreakEvent;
|
import themixray.repeating.mod.TickTask;
|
||||||
import themixray.repeating.mod.event.events.BlockInteractEvent;
|
|
||||||
import themixray.repeating.mod.TickTask;
|
@Mixin(ClientPlayerEntity.class)
|
||||||
|
public abstract class MovementMixin {
|
||||||
@Mixin(ClientPlayerEntity.class)
|
|
||||||
public abstract class MovementMixin {
|
@Inject(at = @At(value = "HEAD"), method = "init")
|
||||||
|
private void init(CallbackInfo ci) {
|
||||||
@Inject(at = @At(value = "HEAD"), method = "init")
|
PlayerBlockBreakEvents.AFTER.register((world, player, pos, blockState, blockEntity) -> {
|
||||||
private void init(CallbackInfo ci) {
|
if (RepeatingMod.me.is_recording)
|
||||||
PlayerBlockBreakEvents.AFTER.register((world, player, pos, blockState, blockEntity) -> {
|
RepeatingMod.me.recordTick(new RepeatingMod.RecordBlockBreakEvent(pos));
|
||||||
if (Main.me.is_recording)
|
});
|
||||||
Main.me.recordTick(new BlockBreakEvent(pos));
|
|
||||||
});
|
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
|
||||||
|
if (hitResult.getType().equals(HitResult.Type.BLOCK))
|
||||||
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
|
if (RepeatingMod.me.is_recording)
|
||||||
if (hitResult.getType().equals(HitResult.Type.BLOCK))
|
RepeatingMod.me.recordTick(new RepeatingMod.RecordBlockInteractEvent(hand,hitResult));
|
||||||
if (Main.me.is_recording)
|
return ActionResult.PASS;
|
||||||
Main.me.recordTick(new BlockInteractEvent(hand,hitResult));
|
});
|
||||||
return ActionResult.PASS;
|
}
|
||||||
});
|
|
||||||
}
|
@Inject(at = @At(value = "HEAD"), method = "tick")
|
||||||
|
private void onTickHead(CallbackInfo ci) {
|
||||||
@Inject(at = @At(value = "HEAD"), method = "tickMovement")
|
for (TickTask t:TickTask.ticks)
|
||||||
private void onMoveHead(CallbackInfo ci) {
|
if (t.getAt() == TickTask.TickAt.HEAD)
|
||||||
TickTask.tickTasks(TickTask.TickAt.MOVEMENT_HEAD);
|
t.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject(at = @At(value = "TAIL"), method = "tick")
|
@Inject(at = @At(value = "TAIL"), method = "tick")
|
||||||
private void onMoveTail(CallbackInfo ci) {
|
private void onTickTail(CallbackInfo ci) {
|
||||||
TickTask.tickTasks(TickTask.TickAt.MOVEMENT_TAIL);
|
for (TickTask t:TickTask.ticks)
|
||||||
}
|
if (t.getAt() == TickTask.TickAt.TAIL)
|
||||||
}
|
t.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "tickMovement")
|
||||||
|
private void onMove(CallbackInfo ci) {
|
||||||
|
if (RepeatingMod.me.is_recording) {
|
||||||
|
RepeatingMod.me.recordAllInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "setSprinting", cancellable = true)
|
||||||
|
private void onSprint(boolean sprinting,CallbackInfo ci) {
|
||||||
|
if (RepeatingMod.me.is_replaying) {
|
||||||
|
if (RepeatingMod.input_replay != null &&
|
||||||
|
RepeatingMod.input_replay.sprinting != null &&
|
||||||
|
RepeatingMod.input_replay.sprinting != sprinting) {
|
||||||
|
ci.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package themixray.repeating.mod.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
|
||||||
import net.minecraft.network.listener.ServerPlayPacketListener;
|
|
||||||
import net.minecraft.network.packet.Packet;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.function.BooleanSupplier;
|
|
||||||
|
|
||||||
@Mixin(ClientPlayNetworkHandler.class)
|
|
||||||
public abstract class NetworkMixin {
|
|
||||||
// @Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V")
|
|
||||||
// private void onSendPacket1Head(Packet<?> packet,
|
|
||||||
// CallbackInfo ci) {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V")
|
|
||||||
// private void onSendPacket2Head(Packet<ServerPlayPacketListener> packet,
|
|
||||||
// BooleanSupplier sendCondition,
|
|
||||||
// Duration expirationTime,
|
|
||||||
// CallbackInfo ci) {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package themixray.repeating.mod.mixin;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents;
|
|
||||||
import net.minecraft.client.network.ClientPlayerEntity;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.network.ClientConnection;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Mixin(ClientConnection.class)
|
|
||||||
public abstract class PlayerMixin {
|
|
||||||
@Inject(at = @At(value = "HEAD"), method = "disconnect")
|
|
||||||
private void disconnect(Text disconnectReason, CallbackInfo ci) {
|
|
||||||
if (Main.me.is_replaying) {
|
|
||||||
Main.me.stopReplay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +1,21 @@
|
|||||||
package themixray.repeating.mod.mixin;
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
import net.minecraft.client.render.*;
|
import net.minecraft.client.input.KeyboardInput;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import net.minecraft.client.render.GameRenderer;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import themixray.repeating.mod.TickTask;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import themixray.repeating.mod.RepeatingMod;
|
||||||
@Mixin(GameRenderer.class)
|
|
||||||
public abstract class RendererMixin {
|
@Mixin(GameRenderer.class)
|
||||||
@Inject(at = @At(value = "HEAD"), method = "tick")
|
public abstract class RendererMixin {
|
||||||
private void onTickHead(CallbackInfo ci) {
|
@Inject(at = @At(value = "TAIL"), method = "tick")
|
||||||
TickTask.tickTasks(TickTask.TickAt.RENDER_HEAD);
|
private void onTickTail(CallbackInfo ci) {
|
||||||
}
|
if (RepeatingMod.me.is_replaying) {
|
||||||
|
if (RepeatingMod.input_replay != null) {
|
||||||
@Inject(at = @At(value = "TAIL"), method = "tick")
|
RepeatingMod.me.recordCameraInput();
|
||||||
private void onTickTail(CallbackInfo ci) {
|
}
|
||||||
TickTask.tickTasks(TickTask.TickAt.RENDER_TAIL);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
package themixray.repeating.mod.mixin;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.AbstractParentElement;
|
|
||||||
import net.minecraft.client.gui.Drawable;
|
|
||||||
import net.minecraft.client.gui.Element;
|
|
||||||
import net.minecraft.client.gui.ParentElement;
|
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
|
||||||
import net.minecraft.client.render.GameRenderer;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.TickTask;
|
|
||||||
import themixray.repeating.mod.event.events.*;
|
|
||||||
|
|
||||||
@Mixin(Screen.class)
|
|
||||||
public abstract class ScreenMixin extends AbstractParentElement implements Drawable {
|
|
||||||
@Inject(at = @At(value = "HEAD"), method = "close")
|
|
||||||
private void close(CallbackInfo ci) {
|
|
||||||
if (Main.me.is_recording) {
|
|
||||||
// Main.me.now_record.addEvent(new GuiCloseEvent());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(at = @At(value = "HEAD"), method = "keyPressed")
|
|
||||||
private void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
|
|
||||||
if (Main.me.is_recording) {
|
|
||||||
// Main.me.now_record.addEvent(new GuiKeyPressEvent(keyCode, scanCode, modifiers));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean charTyped(char chr, int modifiers) {
|
|
||||||
if (Main.me.is_recording) {
|
|
||||||
// Main.me.now_record.addEvent(new GuiCharTypeEvent(chr, modifiers));
|
|
||||||
}
|
|
||||||
return super.charTyped(chr, modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
|
||||||
if (Main.me.is_recording) {
|
|
||||||
// Main.me.now_record.addEvent(new GuiKeyReleaseEvent(keyCode, scanCode, modifiers));
|
|
||||||
}
|
|
||||||
return super.keyReleased(keyCode, scanCode, modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
|
||||||
if (Main.me.is_recording) {
|
|
||||||
// Main.me.now_record.addEvent(new GuiMouseClickEvent(mouseX, mouseY, button));
|
|
||||||
}
|
|
||||||
return super.mouseClicked(mouseX, mouseY, button);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseMoved(double mouseX, double mouseY) {
|
|
||||||
if (Main.me.is_recording) {
|
|
||||||
// Main.me.now_record.addEvent(new GuiMouseMoveEvent(mouseX, mouseY));
|
|
||||||
}
|
|
||||||
super.mouseMoved(mouseX, mouseY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
|
|
||||||
if (Main.me.is_recording) {
|
|
||||||
// Main.me.now_record.addEvent(new GuiMouseDragEvent(mouseX, mouseY, button, deltaX, deltaY));
|
|
||||||
}
|
|
||||||
return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
|
||||||
if (Main.me.is_recording) {
|
|
||||||
// Main.me.now_record.addEvent(new GuiMouseReleaseEvent(mouseX, mouseY, button));
|
|
||||||
}
|
|
||||||
return super.mouseReleased(mouseX, mouseY, button);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
|
|
||||||
// if (Main.me.is_recording) {
|
|
||||||
//// Main.me.now_record.addEvent(new GuiMouseScrollEvent(mouseX, mouseY, amount));
|
|
||||||
// }
|
|
||||||
// return super.mouseScrolled(mouseX, mouseY, amount);
|
|
||||||
// }
|
|
||||||
}
|
|
@ -1,200 +0,0 @@
|
|||||||
package themixray.repeating.mod.render;
|
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import themixray.repeating.mod.render.buffer.WorldBuffer;
|
|
||||||
import themixray.repeating.mod.render.shader.ShaderManager;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL33.*;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class RenderHelper {
|
|
||||||
public WorldBuffer startLines(WorldRenderContext context) {
|
|
||||||
glEnable(GL_LINE_SMOOTH);
|
|
||||||
return new WorldBuffer(GL_LINES, ShaderManager.getPositionColorShader(), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void endLines(WorldBuffer buffer) {
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glDepthMask(false);
|
|
||||||
buffer.draw();
|
|
||||||
glDepthMask(true);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawLine(WorldBuffer buffer, float x1, float y1, float z1, float x2, float y2, float z2, Color color) {
|
|
||||||
buffer.vert(x1, y1, z1, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
|
||||||
buffer.vert(x2, y2, z2, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static WorldBuffer startTri(WorldRenderContext context) {
|
|
||||||
return new WorldBuffer(GL_TRIANGLES, ShaderManager.getPositionColorShader(), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void endTri(WorldBuffer buffer) {
|
|
||||||
//glDepthRange(0, 0.7);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
glDepthMask(false);
|
|
||||||
buffer.draw();
|
|
||||||
glDepthMask(true);
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glDepthRange(0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawTri(WorldBuffer buffer, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, Color color) {
|
|
||||||
buffer.vert(x1, y1, z1, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
|
||||||
buffer.vert(x2, y2, z2, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
|
||||||
buffer.vert(x3, y3, z3, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawRectFromTri(WorldBuffer buffer,
|
|
||||||
float x1, float y1, float z1,
|
|
||||||
float x2, float y2, float z2,
|
|
||||||
float x3, float y3, float z3,
|
|
||||||
float x4, float y4, float z4,
|
|
||||||
Color color) {
|
|
||||||
drawTri(buffer,
|
|
||||||
x1, y1, z1,
|
|
||||||
x2, y2, z2,
|
|
||||||
x3, y3, z3,
|
|
||||||
color);
|
|
||||||
drawTri(buffer,
|
|
||||||
x3, y3, z3,
|
|
||||||
x4, y4, z4,
|
|
||||||
x1, y1, z1,
|
|
||||||
color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawRectFromLines(WorldBuffer buffer,
|
|
||||||
float x1, float y1, float z1,
|
|
||||||
float x2, float y2, float z2,
|
|
||||||
float x3, float y3, float z3,
|
|
||||||
float x4, float y4, float z4,
|
|
||||||
Color color) {
|
|
||||||
drawLine(buffer,
|
|
||||||
x1, y1, z1,
|
|
||||||
x2, y2, z2,
|
|
||||||
color);
|
|
||||||
drawLine(buffer,
|
|
||||||
x2, y2, z2,
|
|
||||||
x3, y3, z3,
|
|
||||||
color);
|
|
||||||
drawLine(buffer,
|
|
||||||
x3, y3, z3,
|
|
||||||
x4, y4, z4,
|
|
||||||
color);
|
|
||||||
drawLine(buffer,
|
|
||||||
x4, y4, z4,
|
|
||||||
x1, y1, z1,
|
|
||||||
color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawBoxFromTri(WorldBuffer buffer,
|
|
||||||
float x1, float y1, float z1,
|
|
||||||
float x2, float y2, float z2,
|
|
||||||
Color color) {
|
|
||||||
float[][] v = new float[][]{
|
|
||||||
new float[]{Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2)},
|
|
||||||
new float[]{Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2)}};
|
|
||||||
|
|
||||||
drawRectFromTri(buffer,
|
|
||||||
v[0][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[1][1], v[0][2],
|
|
||||||
v[0][0], v[1][1], v[0][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromTri(buffer,
|
|
||||||
v[0][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[0][1], v[1][2],
|
|
||||||
v[0][0], v[0][1], v[1][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromTri(buffer,
|
|
||||||
v[0][0], v[0][1], v[0][2],
|
|
||||||
v[0][0], v[0][1], v[1][2],
|
|
||||||
v[0][0], v[1][1], v[1][2],
|
|
||||||
v[0][0], v[1][1], v[0][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromTri(buffer,
|
|
||||||
v[0][0], v[0][1], v[1][2],
|
|
||||||
v[1][0], v[0][1], v[1][2],
|
|
||||||
v[1][0], v[1][1], v[1][2],
|
|
||||||
v[0][0], v[1][1], v[1][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromTri(buffer,
|
|
||||||
v[0][0], v[1][1], v[0][2],
|
|
||||||
v[1][0], v[1][1], v[0][2],
|
|
||||||
v[1][0], v[1][1], v[1][2],
|
|
||||||
v[0][0], v[1][1], v[1][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromTri(buffer,
|
|
||||||
v[1][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[0][1], v[1][2],
|
|
||||||
v[1][0], v[1][1], v[1][2],
|
|
||||||
v[1][0], v[1][1], v[0][2],
|
|
||||||
color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawBoxFromLines(WorldBuffer buffer,
|
|
||||||
float x1, float y1, float z1,
|
|
||||||
float x2, float y2, float z2,
|
|
||||||
Color color) {
|
|
||||||
float[][] v = new float[][]{
|
|
||||||
new float[]{Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2)},
|
|
||||||
new float[]{Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2)}};
|
|
||||||
|
|
||||||
drawRectFromLines(buffer,
|
|
||||||
v[0][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[1][1], v[0][2],
|
|
||||||
v[0][0], v[1][1], v[0][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromLines(buffer,
|
|
||||||
v[0][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[0][1], v[1][2],
|
|
||||||
v[0][0], v[0][1], v[1][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromLines(buffer,
|
|
||||||
v[0][0], v[0][1], v[0][2],
|
|
||||||
v[0][0], v[0][1], v[1][2],
|
|
||||||
v[0][0], v[1][1], v[1][2],
|
|
||||||
v[0][0], v[1][1], v[0][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromLines(buffer,
|
|
||||||
v[0][0], v[0][1], v[1][2],
|
|
||||||
v[1][0], v[0][1], v[1][2],
|
|
||||||
v[1][0], v[1][1], v[1][2],
|
|
||||||
v[0][0], v[1][1], v[1][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromLines(buffer,
|
|
||||||
v[0][0], v[1][1], v[0][2],
|
|
||||||
v[1][0], v[1][1], v[0][2],
|
|
||||||
v[1][0], v[1][1], v[1][2],
|
|
||||||
v[0][0], v[1][1], v[1][2],
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawRectFromLines(buffer,
|
|
||||||
v[1][0], v[0][1], v[0][2],
|
|
||||||
v[1][0], v[0][1], v[1][2],
|
|
||||||
v[1][0], v[1][1], v[1][2],
|
|
||||||
v[1][0], v[1][1], v[0][2],
|
|
||||||
color);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
package themixray.repeating.mod.render;
|
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import themixray.repeating.mod.render.buffer.BufferManager;
|
|
||||||
import themixray.repeating.mod.render.shader.ShaderManager;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class RenderSystem {
|
|
||||||
public static void init() {
|
|
||||||
BufferManager.init();
|
|
||||||
ShaderManager.init();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package themixray.repeating.mod.render.buffer;
|
|
||||||
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL33.*;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class BufferManager {
|
|
||||||
private int vao;
|
|
||||||
private int vbo;
|
|
||||||
|
|
||||||
private int prevVao;
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
ClientLifecycleEvents.CLIENT_STARTED.register(client -> {
|
|
||||||
vao = glGenVertexArrays();
|
|
||||||
vbo = glGenBuffers();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bindBuffer() {
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void unbindBuffer() {
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeBuffer(FloatBuffer buffer) {
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void draw(int drawMode, int verts) {
|
|
||||||
glDrawArrays(drawMode, 0, verts);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void bind() {
|
|
||||||
prevVao = glGetInteger(GL_VERTEX_ARRAY_BINDING);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void unbind() {
|
|
||||||
glBindVertexArray(prevVao);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package themixray.repeating.mod.render.buffer;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
public class Vertex {
|
|
||||||
@Getter
|
|
||||||
private float x;
|
|
||||||
@Getter
|
|
||||||
private float y;
|
|
||||||
@Getter
|
|
||||||
private float z;
|
|
||||||
@Getter
|
|
||||||
private float r;
|
|
||||||
@Getter
|
|
||||||
private float g;
|
|
||||||
@Getter
|
|
||||||
private float b;
|
|
||||||
@Getter
|
|
||||||
private float a;
|
|
||||||
|
|
||||||
public Vertex(float x, float y, float z, float r, float g, float b, float a) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
this.r = r;
|
|
||||||
this.g = g;
|
|
||||||
this.b = b;
|
|
||||||
this.a = a;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package themixray.repeating.mod.render.buffer;
|
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
import org.lwjgl.BufferUtils;
|
|
||||||
import themixray.repeating.mod.render.shader.Shader;
|
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL33.*;
|
|
||||||
|
|
||||||
public class WorldBuffer {
|
|
||||||
private final List<Vertex> vertices = new ArrayList<>();
|
|
||||||
private final int drawMode;
|
|
||||||
private final Shader shader;
|
|
||||||
private FloatBuffer projectionMatrix;
|
|
||||||
private final Vec3d cameraPos;
|
|
||||||
|
|
||||||
public WorldBuffer(int drawMode, Shader shader, WorldRenderContext worldRenderContext) {
|
|
||||||
this.drawMode = drawMode;
|
|
||||||
this.shader = shader;
|
|
||||||
this.cameraPos = worldRenderContext.camera().getPos();
|
|
||||||
makeProjectionMatrix(worldRenderContext.projectionMatrix(), worldRenderContext.matrixStack().peek().getPositionMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void vert(float x, float y, float z, float r, float g, float b, float a) {
|
|
||||||
vertices.add(new Vertex(x - (float) cameraPos.x, y - (float) cameraPos.y, z - (float) cameraPos.z, r, g, b, a));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void draw() {
|
|
||||||
BufferManager.bind();
|
|
||||||
BufferManager.bindBuffer();
|
|
||||||
|
|
||||||
BufferManager.writeBuffer(getBuffer());
|
|
||||||
applyProjectionMatrix();
|
|
||||||
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, vertices.size() * 3 * 4L);
|
|
||||||
glEnableVertexAttribArray(1);
|
|
||||||
|
|
||||||
BufferManager.unbindBuffer();
|
|
||||||
|
|
||||||
shader.bind();
|
|
||||||
BufferManager.draw(drawMode, this.vertices.size());
|
|
||||||
shader.unbind();
|
|
||||||
|
|
||||||
BufferManager.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
private FloatBuffer getBuffer() {
|
|
||||||
FloatBuffer floatBuffer = BufferUtils.createFloatBuffer(vertices.size() * 7);
|
|
||||||
ArrayList<Float> floats = new ArrayList<>();
|
|
||||||
for (Vertex vertex : vertices) {
|
|
||||||
floats.add(vertex.getX());
|
|
||||||
floats.add(vertex.getY());
|
|
||||||
floats.add(vertex.getZ());
|
|
||||||
}
|
|
||||||
for (Vertex vertex : vertices) {
|
|
||||||
floats.add(vertex.getR());
|
|
||||||
floats.add(vertex.getG());
|
|
||||||
floats.add(vertex.getB());
|
|
||||||
floats.add(vertex.getA());
|
|
||||||
}
|
|
||||||
Float[] floatArray = new Float[floats.size()];
|
|
||||||
floats.toArray(floatArray);
|
|
||||||
floatBuffer.put(ArrayUtils.toPrimitive(floatArray));
|
|
||||||
return floatBuffer.flip();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void makeProjectionMatrix(Matrix4f projectionMatrix, Matrix4f viewModelMatrix) {
|
|
||||||
this.projectionMatrix = projectionMatrix.mul(viewModelMatrix).get(BufferUtils.createFloatBuffer(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyProjectionMatrix() {
|
|
||||||
shader.uniformMatrix4f("u_projection", projectionMatrix);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
package themixray.repeating.mod.render.shader;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL33.*;
|
|
||||||
|
|
||||||
public class Shader {
|
|
||||||
@Getter
|
|
||||||
private final int id;
|
|
||||||
|
|
||||||
|
|
||||||
public Shader(String name) {
|
|
||||||
int v = ShaderManager.loadShaderProgram(name, ShaderManager.ShaderType.VERTEX);
|
|
||||||
int f = ShaderManager.loadShaderProgram(name, ShaderManager.ShaderType.FRAGMENT);
|
|
||||||
this.id = glCreateProgram();
|
|
||||||
glAttachShader(id, v);
|
|
||||||
glAttachShader(id, f);
|
|
||||||
glLinkProgram(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bind() {
|
|
||||||
glUseProgram(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unbind() {
|
|
||||||
glUseProgram(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void uniformMatrix4f(String name, FloatBuffer matrix) {
|
|
||||||
bind();
|
|
||||||
glUniformMatrix4fv(glGetUniformLocation(id, name), false, matrix);
|
|
||||||
unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void uniformValue2f(String name, float value1, float value2) {
|
|
||||||
bind();
|
|
||||||
glUniform2f(glGetUniformLocation(id, name), value1, value2);
|
|
||||||
unbind();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
package themixray.repeating.mod.render.shader;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
|
||||||
import com.mojang.blaze3d.platform.TextureUtil;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import net.minecraft.client.gl.GlImportProcessor;
|
|
||||||
import net.minecraft.resource.Resource;
|
|
||||||
import net.minecraft.resource.ResourceFactory;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.lwjgl.system.MemoryUtil;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL33.*;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class ShaderManager {
|
|
||||||
@Getter
|
|
||||||
private Shader positionColorShader;
|
|
||||||
|
|
||||||
public void init() {
|
|
||||||
ClientLifecycleEvents.CLIENT_STARTED.register(client -> loadShaders());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadShaders() {
|
|
||||||
positionColorShader = new Shader("position_color");
|
|
||||||
}
|
|
||||||
|
|
||||||
public int loadShaderProgram(String name, ShaderType type) {
|
|
||||||
try {
|
|
||||||
boolean file_present = true;
|
|
||||||
ResourceFactory resourceFactory = MinecraftClient.getInstance().getResourceManager();
|
|
||||||
Optional<Resource> resource = resourceFactory.getResource(new Identifier("renderer", "shader/" + name + type.fileExtension));
|
|
||||||
int i = glCreateShader(type.glType);
|
|
||||||
if (resource.isPresent()) {
|
|
||||||
GlStateManager.glShaderSource(i, new GlImportProcessor() {
|
|
||||||
@SneakyThrows
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public String loadImport(boolean inline, String name) {
|
|
||||||
return IOUtils.toString(resource.get().getInputStream(), StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
}.readSource(readResourceAsString(resource.get().getInputStream())));
|
|
||||||
} else file_present = false;
|
|
||||||
glCompileShader(i);
|
|
||||||
if (glGetShaderi(i, GL_COMPILE_STATUS) == 0 || !file_present) {
|
|
||||||
String shaderInfo = StringUtils.trim(glGetShaderInfoLog(i, 32768));
|
|
||||||
throw new IOException("Couldn't compile " + type.name + " program (" + name + ") : " + shaderInfo);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String readResourceAsString(InputStream inputStream) {
|
|
||||||
ByteBuffer byteBuffer = null;
|
|
||||||
try {
|
|
||||||
byteBuffer = TextureUtil.readResource(inputStream);
|
|
||||||
int i = byteBuffer.position();
|
|
||||||
byteBuffer.rewind();
|
|
||||||
return MemoryUtil.memASCII(byteBuffer, i);
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
} finally {
|
|
||||||
if (byteBuffer != null) {
|
|
||||||
MemoryUtil.memFree(byteBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ShaderType {
|
|
||||||
VERTEX("vertex", ".vsh", GL_VERTEX_SHADER),
|
|
||||||
FRAGMENT("fragment", ".fsh", GL_FRAGMENT_SHADER);
|
|
||||||
private final String name;
|
|
||||||
private final String fileExtension;
|
|
||||||
private final int glType;
|
|
||||||
|
|
||||||
ShaderType(String name, String fileExtension, int glType) {
|
|
||||||
this.name = name;
|
|
||||||
this.fileExtension = fileExtension;
|
|
||||||
this.glType = glType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,153 +0,0 @@
|
|||||||
package themixray.repeating.mod.widget;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
|
||||||
import net.minecraft.client.gui.Drawable;
|
|
||||||
import net.minecraft.client.gui.Element;
|
|
||||||
import net.minecraft.client.gui.Selectable;
|
|
||||||
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
|
||||||
import net.minecraft.client.gui.tooltip.Tooltip;
|
|
||||||
import net.minecraft.client.gui.widget.*;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.RecordState;
|
|
||||||
import themixray.repeating.mod.RepeatingScreen;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class RecordListWidget extends ScrollableWidget {
|
|
||||||
private LinkedList<RecordWidget> widgets = new LinkedList<>();
|
|
||||||
private boolean focused = false;
|
|
||||||
|
|
||||||
public RecordListWidget(int x, int y, int width, int height) {
|
|
||||||
super(x,y,width,height,Text.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
|
|
||||||
focused = true;
|
|
||||||
boolean res = super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
|
|
||||||
focused = false;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected double getDeltaYPerScroll() {
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void renderContents(DrawContext ctx, int mouseX, int mouseY, float delta) {
|
|
||||||
int y = 0;
|
|
||||||
for (RecordWidget wid: widgets) {
|
|
||||||
wid.setY(y);
|
|
||||||
wid.render(ctx, mouseX, (int) (mouseY + this.getScrollY()), delta);
|
|
||||||
|
|
||||||
y += wid.getHeight();
|
|
||||||
y += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addWidget(RecordState record) {
|
|
||||||
RecordWidget widget = new RecordWidget(0, 0, width, 55, record, this);
|
|
||||||
widget.init(null);
|
|
||||||
widgets.add(0, widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeWidget(RecordState record) {
|
|
||||||
widgets.removeIf(i -> i.getRecord().equals(record));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFocused(boolean focused) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFocused() {
|
|
||||||
return focused;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getContentsHeight() {
|
|
||||||
return !widgets.isEmpty() ? widgets.size() * 55 + (widgets.size() - 1) * 2 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(RepeatingScreen screen) {
|
|
||||||
for (RecordWidget widget : widgets) {
|
|
||||||
widget.init(screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
screen.addDrawableChild(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void appendClickableNarrations(NarrationMessageBuilder builder) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordWidget getWidget(RecordState record) {
|
|
||||||
for (RecordWidget widget : widgets) {
|
|
||||||
if (widget.getRecord().equals(record)) {
|
|
||||||
return widget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface transport {
|
|
||||||
boolean check(ClickableWidget ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkTransport(transport tr) {
|
|
||||||
for (RecordWidget wid : widgets) {
|
|
||||||
for (ClickableWidget child : wid.getChildren()) {
|
|
||||||
if (child.isFocused() && tr.check(child)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkTransportNF(double mouseX, double mouseY, int button) {
|
|
||||||
for (RecordWidget wid : widgets) {
|
|
||||||
if (wid.contains((int) mouseX, (int) mouseY)) {
|
|
||||||
Main.me.setNowRecord(wid.getRecord());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ClickableWidget child : wid.getChildren()) {
|
|
||||||
if (child.mouseClicked(mouseX, mouseY, button)) {
|
|
||||||
child.setFocused(true);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
child.setFocused(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
|
||||||
return checkTransportNF(mouseX, mouseY + getScrollY(), button) || super.mouseClicked(mouseX, mouseY, button);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean charTyped(char chr, int modifiers) {
|
|
||||||
return checkTransport((c) -> c.charTyped(chr, modifiers)) || super.charTyped(chr, modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
|
||||||
return checkTransport((c) -> c.keyPressed(keyCode, scanCode, modifiers)) || super.keyPressed(keyCode, scanCode, modifiers);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
|
||||||
return checkTransport((c) -> c.keyReleased(keyCode, scanCode, modifiers)) || super.keyReleased(keyCode, scanCode, modifiers);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,218 +0,0 @@
|
|||||||
package themixray.repeating.mod.widget;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.DrawContext;
|
|
||||||
import net.minecraft.client.gui.Drawable;
|
|
||||||
import net.minecraft.client.gui.tooltip.Tooltip;
|
|
||||||
import net.minecraft.client.gui.widget.*;
|
|
||||||
import net.minecraft.text.Style;
|
|
||||||
import net.minecraft.text.Text;
|
|
||||||
import net.minecraft.text.TextColor;
|
|
||||||
import net.minecraft.util.Formatting;
|
|
||||||
import themixray.repeating.mod.Main;
|
|
||||||
import themixray.repeating.mod.RecordState;
|
|
||||||
import themixray.repeating.mod.RenderListener;
|
|
||||||
import themixray.repeating.mod.RepeatingScreen;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class RecordWidget implements Drawable, Widget {
|
|
||||||
private RecordState record;
|
|
||||||
|
|
||||||
private List<ClickableWidget> children;
|
|
||||||
|
|
||||||
private RecordListWidget parent;
|
|
||||||
|
|
||||||
private int x;
|
|
||||||
private int y;
|
|
||||||
private int width;
|
|
||||||
private int height;
|
|
||||||
|
|
||||||
public RecordWidget(int x, int y, int width, int height, RecordState record, RecordListWidget parent) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.record = record;
|
|
||||||
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
|
|
||||||
this.children = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean contains(int x, int y) {
|
|
||||||
return parent.getX() + getX() <= x &&
|
|
||||||
parent.getY() + getY() <= y &&
|
|
||||||
x <= parent.getX() + getX() + getWidth() &&
|
|
||||||
y <= parent.getY() + getY() + getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setX(int x) {
|
|
||||||
this.x = x;
|
|
||||||
}
|
|
||||||
public void setY(int y) {
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
public int getX() {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
public int getY() {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
public int getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
public int getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ClickableWidget> getChildren() {
|
|
||||||
return children;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void forEachChild(Consumer<ClickableWidget> consumer) {
|
|
||||||
children.forEach(consumer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(RepeatingScreen screen) {
|
|
||||||
this.children = new ArrayList<>();
|
|
||||||
|
|
||||||
TextFieldWidget name_widget = new TextFieldWidget(
|
|
||||||
Main.client.textRenderer,
|
|
||||||
parent.getX() + getX() + 5,
|
|
||||||
parent.getY() + getY() + 5,
|
|
||||||
102,
|
|
||||||
10,
|
|
||||||
Text.empty());
|
|
||||||
|
|
||||||
name_widget.setText(record.getName());
|
|
||||||
|
|
||||||
name_widget.setChangedListener((s) -> {
|
|
||||||
record.setName(s);
|
|
||||||
try {
|
|
||||||
record.save();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
children.add(name_widget);
|
|
||||||
|
|
||||||
ButtonWidget delete_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.delete"), (i) -> {
|
|
||||||
record.remove();
|
|
||||||
}).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4, 65, 13).build();
|
|
||||||
|
|
||||||
children.add(delete_button);
|
|
||||||
|
|
||||||
ButtonWidget export_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.export"), (i) -> {
|
|
||||||
try {
|
|
||||||
record.save();
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
if (Desktop.isDesktopSupported()) {
|
|
||||||
Desktop desk = Desktop.getDesktop();
|
|
||||||
try {
|
|
||||||
desk.browseFileDirectory(record.getFile());
|
|
||||||
} catch (Exception e) {
|
|
||||||
try {
|
|
||||||
desk.browse(record.getFile().toURI());
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Main.sendMessage(Text.literal("Record file is ").append(
|
|
||||||
Text.literal("["+record.getFile().getAbsolutePath()+"]").styled((s) -> s.withColor(Formatting.GRAY))));
|
|
||||||
}
|
|
||||||
}).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 14, 65, 13).build();
|
|
||||||
|
|
||||||
children.add(export_button);
|
|
||||||
|
|
||||||
ButtonWidget replay_button = ButtonWidget.builder(Text.translatable("text.repeating-mod." +
|
|
||||||
(getRecord().equals(Main.me.now_record) && Main.me.is_replaying ? "stop" : "start")), (i) -> {
|
|
||||||
if (Main.me.is_replaying) {
|
|
||||||
Main.me.stopReplay();
|
|
||||||
if (getRecord().equals(Main.me.now_record)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i.setMessage(Text.translatable("text.repeating-mod.stop"));
|
|
||||||
Main.me.now_record = getRecord();
|
|
||||||
Main.me.startReplay();
|
|
||||||
Main.client.setScreen(null);
|
|
||||||
}).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 28, 65, 13)
|
|
||||||
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.replay_tooltip"))).build();
|
|
||||||
|
|
||||||
children.add(replay_button);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecordState getRecord() {
|
|
||||||
return record;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void drawText(int x, int y, DrawContext ctx, List<Text> lines, float size, int line_height, boolean shadow) {
|
|
||||||
ctx.getMatrices().push();
|
|
||||||
ctx.getMatrices().scale(size, size, size);
|
|
||||||
|
|
||||||
int now_y = y;
|
|
||||||
|
|
||||||
for (Text line : lines) {
|
|
||||||
ctx.drawText(Main.client.textRenderer, line, (int) (x / size), (int) (now_y / size), line.getStyle().getColor().getRgb(), shadow);
|
|
||||||
now_y += line_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.getMatrices().pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(DrawContext ctx, int mouseX, int mouseY, float delta) {
|
|
||||||
int color = record.equals(Main.me.now_record) ? 0xFF555555 : 0xFF333333;
|
|
||||||
|
|
||||||
ctx.fill(parent.getX() + getX(),
|
|
||||||
parent.getY() + getY(),
|
|
||||||
parent.getX() + getX() + getWidth(),
|
|
||||||
parent.getY() + getY() + getHeight(),
|
|
||||||
color);
|
|
||||||
|
|
||||||
drawText(
|
|
||||||
parent.getX() + getX() + 5,
|
|
||||||
parent.getY() + getY() + 5 + 12,
|
|
||||||
ctx, List.of(
|
|
||||||
Text.translatable("text.repeating-mod.recorded_at")
|
|
||||||
.append(": ")
|
|
||||||
.styled((s) -> s.withColor(0xbbbbbb)),
|
|
||||||
Text.literal(RecordState.DATE_FORMAT.format(record.getDate())).styled((s) -> s.withColor(0xffffff)),
|
|
||||||
Text.translatable("text.repeating-mod.author")
|
|
||||||
.append(": ")
|
|
||||||
.styled((s) -> s.withColor(0xbbbbbb)),
|
|
||||||
Text.literal(record.getAuthor()).styled((s) -> s.withColor(0xffffff))
|
|
||||||
), 1,
|
|
||||||
9,
|
|
||||||
false);
|
|
||||||
|
|
||||||
if (!children.isEmpty()) {
|
|
||||||
ClickableWidget name_widget = children.get(0);
|
|
||||||
name_widget.setPosition(parent.getX() + getX() + 5, parent.getY() + getY() + 5);
|
|
||||||
|
|
||||||
ClickableWidget delete_button = children.get(1);
|
|
||||||
delete_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4);
|
|
||||||
|
|
||||||
ClickableWidget export_button = children.get(2);
|
|
||||||
export_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 14);
|
|
||||||
|
|
||||||
ClickableWidget replay_button = children.get(3);
|
|
||||||
replay_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 28);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ClickableWidget child : children) {
|
|
||||||
child.render(ctx, mouseX, mouseY, delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"providers": [
|
"providers": [
|
||||||
{
|
{
|
||||||
"file":"repeating-mod:ui/no-loop.png",
|
"file":"repeating-mod:ui/no-loop.png",
|
||||||
"chars":["\ueffe"],
|
"chars":["\ueffe"],
|
||||||
"height":16,
|
"height":16,
|
||||||
"ascent":12,
|
"ascent":12,
|
||||||
"type":"bitmap"
|
"type":"bitmap"
|
||||||
},{
|
},{
|
||||||
"file":"repeating-mod:ui/loop.png",
|
"file":"repeating-mod:ui/loop.png",
|
||||||
"chars":["\uefff"],
|
"chars":["\uefff"],
|
||||||
"height":16,
|
"height":16,
|
||||||
"ascent":12,
|
"ascent":12,
|
||||||
"type":"bitmap"
|
"type":"bitmap"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -1,12 +0,0 @@
|
|||||||
#version 330
|
|
||||||
|
|
||||||
in vec4 vertexColor;
|
|
||||||
|
|
||||||
out vec4 fragmentColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
if (vertexColor.a == 0.0f) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
fragmentColor = vertexColor;
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
#version 330
|
|
||||||
|
|
||||||
layout (location = 0) in vec3 i_pos;
|
|
||||||
layout (location = 1) in vec4 i_color;
|
|
||||||
|
|
||||||
uniform mat4 u_projection;
|
|
||||||
|
|
||||||
out vec4 vertexColor;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
gl_Position = u_projection * vec4(i_pos, 1.0f);
|
|
||||||
vertexColor = i_color;
|
|
||||||
}
|
|
@ -1,36 +1,25 @@
|
|||||||
{
|
{
|
||||||
"key.repeating-mod.menu": "Repeating menu",
|
"key.repeating-mod.menu": "Repeating menu",
|
||||||
"key.repeating-mod.toggle_replay": "Toggle replay",
|
"key.repeating-mod.toggle_replay": "Toggle replay",
|
||||||
"key.repeating-mod.toggle_record": "Toggle recording",
|
"key.repeating-mod.toggle_record": "Toggle recording",
|
||||||
|
|
||||||
"text.repeating-mod.name": "Repeating Mod",
|
"text.repeating-mod.name": "Repeating Mod",
|
||||||
"text.repeating-mod.start_record": "Start record",
|
"text.repeating-mod.record": "record",
|
||||||
"text.repeating-mod.stop_record": "Stop record",
|
"text.repeating-mod.replay": "replay",
|
||||||
"text.repeating-mod.start_replay": "Start replay",
|
"text.repeating-mod.start": "Start",
|
||||||
"text.repeating-mod.stop_replay": "Stop replay",
|
"text.repeating-mod.stop": "Stop",
|
||||||
"text.repeating-mod.record_tooltip": "Start/stop recording all activities",
|
"text.repeating-mod.export": "Export record",
|
||||||
"text.repeating-mod.replay_tooltip": "Start/stop repeating recorded actions",
|
"text.repeating-mod.import": "Import record",
|
||||||
"text.repeating-mod.loop_tooltip": "Enable/disable repeating of recorded actions replay",
|
"text.repeating-mod.basic": "Basic mode",
|
||||||
"text.repeating-mod.export_record": "Export record",
|
"text.repeating-mod.parkour": "Parkour mode",
|
||||||
"text.repeating-mod.import": "Import record",
|
"text.repeating-mod.settings": "Settings",
|
||||||
"text.repeating-mod.export_tooltip": "Exporting a recording to a file",
|
"text.repeating-mod.dev": "In development...",
|
||||||
"text.repeating-mod.import_tooltip": "Importing a recording from a file",
|
"text.repeating-mod.nan_pos_delay": "No pos delay",
|
||||||
"text.repeating-mod.dev": "In development...",
|
"text.repeating-mod.pos_delay": "Pos delay: %s ms",
|
||||||
"text.repeating-mod.nan_pos_delay": "No pos timer",
|
"text.repeating-mod.pos_delay_text": "Delay after which the pos event is added",
|
||||||
"text.repeating-mod.pos_delay": "Pos timer: %s ticks",
|
|
||||||
"text.repeating-mod.pos_delay_tooltip": "Timer after which the pos\nevent is added (20 ticks = 1 sec)",
|
"message.repeating-mod.replay_start": "Replay started",
|
||||||
"text.repeating-mod.unnamed": "Unnamed Record",
|
"message.repeating-mod.replay_stop": "Replay finished",
|
||||||
"text.repeating-mod.on_loop": "Enable repeat",
|
"message.repeating-mod.record_start": "Record started",
|
||||||
"text.repeating-mod.off_loop": "Disable repeat",
|
"message.repeating-mod.record_stop": "Record finished"
|
||||||
"text.repeating-mod.recorded_at": "Recorded at",
|
|
||||||
"text.repeating-mod.author": "Author",
|
|
||||||
"text.repeating-mod.delete": "Delete",
|
|
||||||
"text.repeating-mod.start": "Start",
|
|
||||||
"text.repeating-mod.stop": "Stop",
|
|
||||||
"text.repeating-mod.export": "Export",
|
|
||||||
|
|
||||||
"message.repeating-mod.replay_start": "Replay started",
|
|
||||||
"message.repeating-mod.replay_stop": "Replay finished",
|
|
||||||
"message.repeating-mod.record_start": "Record started",
|
|
||||||
"message.repeating-mod.record_stop": "Record finished"
|
|
||||||
}
|
}
|
@ -1,38 +1,26 @@
|
|||||||
{
|
{
|
||||||
"key.repeating-mod.menu": "Меню репитинга",
|
"key.repeating-mod.menu": "Меню репитинга",
|
||||||
"key.repeating-mod.toggle_replay": "Вкл/выкл повтор",
|
"key.repeating-mod.toggle_replay": "Вкл/выкл повтор",
|
||||||
"key.repeating-mod.toggle_record": "Вкл/выкл запись",
|
"key.repeating-mod.toggle_record": "Вкл/выкл запись",
|
||||||
|
|
||||||
"text.repeating-mod.name": "Репитинг Мод",
|
"text.repeating-mod.name": "Репитинг Мод",
|
||||||
"text.repeating-mod.start_record": "Начать запись",
|
"text.repeating-mod.record": "запись",
|
||||||
"text.repeating-mod.stop_record": "Остановить запись",
|
"text.repeating-mod.replay": "повтор",
|
||||||
"text.repeating-mod.start_replay": "Начать повтор",
|
"text.repeating-mod.start": "Начать",
|
||||||
"text.repeating-mod.stop_replay": "Остановить повтор",
|
"text.repeating-mod.stop": "Остановить",
|
||||||
"text.repeating-mod.record_tooltip": "Начать/остановить запись всех действий",
|
"text.repeating-mod.export": "Экспорт записи",
|
||||||
"text.repeating-mod.replay_tooltip": "Начать/остановить повтор записанных действий",
|
"text.repeating-mod.import": "Импорт записи",
|
||||||
"text.repeating-mod.loop_tooltip": "Вкл/выкл повтор записи",
|
"text.repeating-mod.basic": "Обычный режим",
|
||||||
"text.repeating-mod.import": "Импорт записи",
|
"text.repeating-mod.parkour": "Режим паркура",
|
||||||
"text.repeating-mod.export_tooltip": "Экспорт записи в файл",
|
"text.repeating-mod.settings": "Настройки",
|
||||||
"text.repeating-mod.import_tooltip": "Импорт записи из файла",
|
"text.repeating-mod.dev": "В разработке...",
|
||||||
"text.repeating-mod.dev": "В разработке...",
|
"text.repeating-mod.nan_pos_delay": "Задержки позиции нету",
|
||||||
"text.repeating-mod.nan_pos_delay": "Таймера позиции нету",
|
"text.repeating-mod.pos_delay": "Задержка позиции: %s мс",
|
||||||
"text.repeating-mod.pos_delay": "Таймер позиции: %s тиков",
|
"text.repeating-mod.pos_delay_text": "Задержка, после которой добавляется ивент позиции",
|
||||||
"text.repeating-mod.pos_delay_tooltip": "Таймер, после которой добавляется\nивент позиции (20 тиков = 1 сек)",
|
|
||||||
"text.repeating-mod.unnamed": "Безымянная Запись",
|
"message.repeating-mod.replay_start": "Повтор начат",
|
||||||
"text.repeating-mod.on_loop": "Включить повторение",
|
"message.repeating-mod.replay_stop": "Повтор закончен",
|
||||||
"text.repeating-mod.off_loop": "Выключить повторение",
|
"message.repeating-mod.record_start": "Запись начата",
|
||||||
"text.repeating-mod.recorded_at": "Записано в",
|
"message.repeating-mod.record_stop": "Запись закончена"
|
||||||
"text.repeating-mod.author": "Автор",
|
}
|
||||||
|
|
||||||
"message.repeating-mod.replay_start": "Повтор начат",
|
|
||||||
"message.repeating-mod.replay_stop": "Повтор закончен",
|
|
||||||
"message.repeating-mod.record_start": "Запись начата",
|
|
||||||
"message.repeating-mod.record_stop": "Запись закончена",
|
|
||||||
|
|
||||||
"text.repeating-mod.export_record": "Экпорт записи",
|
|
||||||
"text.repeating-mod.export": "Экспорт",
|
|
||||||
"text.repeating-mod.delete": "Удалить",
|
|
||||||
"text.repeating-mod.start": "Старт",
|
|
||||||
"text.repeating-mod.stop": "Стоп"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,38 +1,38 @@
|
|||||||
{
|
{
|
||||||
"schemaVersion": 1,
|
"schemaVersion": 1,
|
||||||
"id": "repeating-mod",
|
"id": "repeating-mod",
|
||||||
"version": "${version}",
|
"version": "${version}",
|
||||||
|
|
||||||
"name": "Repeating Mod",
|
"name": "Repeating Mod",
|
||||||
"description": "Mod that repeats your recorded actions. ",
|
"description": "Mod that repeats your recorded actions. ",
|
||||||
"authors": [
|
"authors": [
|
||||||
"TheMixRay"
|
"TheMixRay"
|
||||||
],
|
],
|
||||||
"contact": {
|
"contact": {
|
||||||
"homepage": "https://modrinth.com/mod/repeating-mod",
|
"homepage": "https://modrinth.com/mod/repeating-mod",
|
||||||
"sources": "https://github.com/MeexReay/repeating-mod"
|
"sources": "https://github.com/MeexReay/repeating-mod"
|
||||||
},
|
},
|
||||||
|
|
||||||
"license": "CC0-1.0",
|
"license": "CC0-1.0",
|
||||||
"icon": "icon.png",
|
"icon": "icon.png",
|
||||||
|
|
||||||
"environment": "client",
|
"environment": "client",
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"client": [
|
"client": [
|
||||||
"themixray.repeating.mod.Main"
|
"themixray.repeating.mod.RepeatingMod"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"repeating-mod.mixins.json"
|
"repeating-mod.mixins.json"
|
||||||
],
|
],
|
||||||
|
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.14.14",
|
"fabricloader": ">=0.14.14",
|
||||||
"fabric-api": "*",
|
"fabric-api": "*",
|
||||||
"minecraft": ">=1.20",
|
"minecraft": "~1.19.3",
|
||||||
"java": ">=17"
|
"java": ">=17"
|
||||||
},
|
},
|
||||||
"suggests": {
|
"suggests": {
|
||||||
"another-mod": "*"
|
"another-mod": "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.2 KiB |
@ -1,20 +1,15 @@
|
|||||||
{
|
{
|
||||||
"required": true,
|
"required": true,
|
||||||
"minVersion": "0.8",
|
"minVersion": "0.8",
|
||||||
"package": "themixray.repeating.mod.mixin",
|
"package": "themixray.repeating.mod.mixin",
|
||||||
"compatibilityLevel": "JAVA_17",
|
"compatibilityLevel": "JAVA_17",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"MovementMixin",
|
"MovementMixin",
|
||||||
"InputMixin",
|
"InputMixin"
|
||||||
"RendererMixin",
|
],
|
||||||
"EntityMixin",
|
"injectors": {
|
||||||
"ClientMixin",
|
"defaultRequire": 1
|
||||||
"ScreenMixin",
|
}
|
||||||
"PlayerMixin"
|
}
|
||||||
],
|
|
||||||
"injectors": {
|
|
||||||
"defaultRequire": 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user