mirror of https://github.com/LOOHP/Limbo.git
Compare commits
No commits in common. "master" and "Downloads" have entirely different histories.
|
|
@ -1,4 +0,0 @@
|
||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: [LOOHP]
|
|
||||||
custom: ['https://paypal.me/loohpjames/5USD']
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
# IntelliJ IDEA
|
|
||||||
*.iml
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
# Maven
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Mac OS
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Eclipse
|
|
||||||
.classpath
|
|
||||||
.project
|
|
||||||
.settings/
|
|
||||||
201
LICENSE
201
LICENSE
|
|
@ -1,201 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
@ -0,0 +1,674 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
49
README.md
49
README.md
|
|
@ -1,56 +1,19 @@
|
||||||
[](http://ci.loohpjames.com/job/Limbo/)
|
|
||||||
# Limbo
|
# Limbo
|
||||||
## Standalone Limbo Minecraft Server (Currently 1.21.10)
|
[](http://ci.loohpjames.com/job/Limbo/)
|
||||||
|
## Standalone Limbo Minecraft Server (Currently 1.16.2)
|
||||||
https://www.spigotmc.org/resources/82468/<br>
|
|
||||||
https://modrinth.com/mod/limbo-server
|
|
||||||
|
|
||||||
### Starting the server
|
### Starting the server
|
||||||
Use the following command lines to start the limbo server just like any other Minecraft server
|
Use the following command lines to start the limbo server just like any other minecraft server
|
||||||
```
|
```
|
||||||
java -jar Limbo.jar --nogui
|
java -jar Limbo.jar --nogui
|
||||||
```
|
```
|
||||||
|
|
||||||
Put the world scheme file in the same folder as the server jar file and configure the `server.properties` file to your needs
|
Put the world schem file in the same folder as the server jar file and configurate the `server.properties` file to your needs
|
||||||
***
|
***
|
||||||
### Demo Limbo Server
|
### Demo Limbo Server
|
||||||
```
|
```
|
||||||
IP: mc.loohpjames.com
|
IP: demo.limbo.loohpjames.com
|
||||||
```
|
```
|
||||||

|
|
||||||
***
|
***
|
||||||
### Downloads (1.17.1-1.21.10)
|
### Downloads
|
||||||
- [Jenkins](http://ci.loohpjames.com/job/Limbo/)
|
- [Jenkins](http://ci.loohpjames.com/job/Limbo/)
|
||||||
***
|
|
||||||
### Offical Plugins
|
|
||||||
- [ViaLimbo](https://github.com/LOOHP/ViaLimbo/) - Allow other Minecraft versions to join through the use of [ViaProxy](https://github.com/ViaVersion/ViaProxy)
|
|
||||||
- [Floodgate-Limbo](https://github.com/LOOHP/floodgate-limbo) - [Geyser's](https://geysermc.org/) [floodgate](https://geysermc.org/wiki/floodgate/) plugin implemented for Limbo
|
|
||||||
***
|
|
||||||
### Maven
|
|
||||||
```html
|
|
||||||
<repository>
|
|
||||||
<id>loohp-repo</id>
|
|
||||||
<url>https://repo.loohpjames.com/repository</url>
|
|
||||||
</repository>
|
|
||||||
```
|
|
||||||
```html
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.loohp</groupId>
|
|
||||||
<artifactId>Limbo</artifactId>
|
|
||||||
<version>VERSION</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
```
|
|
||||||
Replace `VERSION` with the version.
|
|
||||||
|
|
||||||
## Partnerships
|
|
||||||
|
|
||||||
### Server Hosting
|
|
||||||
**Use the link or click the banner** below to **get a 25% discount off** your first month when buying any of their gaming servers!<br>
|
|
||||||
It also **supports my development**, take it as an alternative way to donate while getting your very own Minecraft server as well!
|
|
||||||
|
|
||||||
*P.S. Using the link or clicking the banner rather than the code supports me more! (Costs you no extra!)*
|
|
||||||
|
|
||||||
**https://www.bisecthosting.com/loohp**
|
|
||||||
|
|
||||||

|
|
||||||
|
|
|
||||||
Binary file not shown.
242
pom.xml
242
pom.xml
|
|
@ -1,65 +1,19 @@
|
||||||
<!--
|
|
||||||
~ This file is part of Limbo.
|
|
||||||
~
|
|
||||||
~ Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
~ Copyright (C) 2022. Contributors
|
|
||||||
~
|
|
||||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
~ you may not use this file except in compliance with the License.
|
|
||||||
~ You may obtain a copy of the License at
|
|
||||||
~
|
|
||||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
~
|
|
||||||
~ Unless required by applicable law or agreed to in writing, software
|
|
||||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
~ See the License for the specific language governing permissions and
|
|
||||||
~ limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.loohp</groupId>
|
<groupId>Limbo</groupId>
|
||||||
<artifactId>Limbo</artifactId>
|
<artifactId>Limbo</artifactId>
|
||||||
<name>Limbo</name>
|
<version>0.3.0-ALPHA</version>
|
||||||
<version>0.7.16-ALPHA</version>
|
|
||||||
|
|
||||||
<description>Standalone Limbo Minecraft Server.</description>
|
|
||||||
<url>https://github.com/LOOHP/Limbo</url>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.build.number></project.build.number>
|
|
||||||
<project.fullVersion>${project.version}</project.fullVersion>
|
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<sourceDirectory>src/main/java</sourceDirectory>
|
<sourceDirectory>src</sourceDirectory>
|
||||||
<resources>
|
<resources>
|
||||||
<resource>
|
<resource>
|
||||||
<directory>src/main/resources</directory>
|
<directory>src</directory>
|
||||||
<filtering>true</filtering>
|
|
||||||
<excludes>
|
<excludes>
|
||||||
<exclude>**/*.java</exclude>
|
<exclude>**/*.java</exclude>
|
||||||
<exclude>**/*.ttf</exclude>
|
|
||||||
<exclude>**/*.jar</exclude>
|
|
||||||
<exclude>**/*.schem</exclude>
|
|
||||||
</excludes>
|
</excludes>
|
||||||
</resource>
|
</resource>
|
||||||
<resource>
|
|
||||||
<directory>src/main/resources</directory>
|
|
||||||
<filtering>false</filtering>
|
|
||||||
<includes>
|
|
||||||
<include>**/*.ttf</include>
|
|
||||||
<include>**/*.jar</include>
|
|
||||||
<include>**/*.schem</include>
|
|
||||||
</includes>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
</resources>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
@ -98,218 +52,48 @@
|
||||||
<encoding>ISO-8859-1</encoding>
|
<encoding>ISO-8859-1</encoding>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>3.2.0</version>
|
|
||||||
<configuration>
|
|
||||||
<failOnError>false</failOnError>
|
|
||||||
<encoding>ISO-8859-1</encoding>
|
|
||||||
<doctitle>Limbo JavaDocs</doctitle>
|
|
||||||
<windowtitle>Limbo JavaDocs</windowtitle>
|
|
||||||
<additionalOptions>
|
|
||||||
<additionalOption>-Xdoclint:none</additionalOption>
|
|
||||||
</additionalOptions>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>install</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>aggregate</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
|
||||||
<version>3.2.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-sources</id>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>jar-no-fork</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
</plugins>
|
||||||
<finalName>${project.artifactId}-${project.version}-1.21.10</finalName>
|
<finalName>${project.artifactId}-${project.version}-1.16.2</finalName>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>jenkins</id>
|
|
||||||
<activation>
|
|
||||||
<property>
|
|
||||||
<name>env.BUILD_NUMBER</name>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<properties>
|
|
||||||
<project.build.number>-b${env.BUILD_NUMBER}</project.build.number>
|
|
||||||
<!--<project.fullVersion>${project.version}${project.build.number}</project.fullVersion> -->
|
|
||||||
<project.fullVersion>${project.version}</project.fullVersion>
|
|
||||||
</properties>
|
|
||||||
</profile>
|
|
||||||
|
|
||||||
<profile>
|
|
||||||
<id>release-sign-artifacts</id>
|
|
||||||
<activation>
|
|
||||||
<property>
|
|
||||||
<name>performRelease</name>
|
|
||||||
<value>true</value>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<properties>
|
|
||||||
<project.fullVersion>${project.version}</project.fullVersion>
|
|
||||||
</properties>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
|
||||||
<version>3.2.1</version>
|
|
||||||
<configuration>
|
|
||||||
<encoding>${project.build.sourceEncoding}</encoding>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-sources</id>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
|
||||||
<version>3.2.0</version>
|
|
||||||
<configuration>
|
|
||||||
<encoding>${project.build.sourceEncoding}</encoding>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>attach-javadocs</id>
|
|
||||||
<goals>
|
|
||||||
<goal>jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>jitpack.io</id>
|
<id>jitpack.io</id>
|
||||||
<url>https://jitpack.io</url>
|
<url>https://jitpack.io</url>
|
||||||
</repository>
|
</repository>
|
||||||
<repository>
|
|
||||||
<id>sonatype-oss-snapshots1</id>
|
|
||||||
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>bungeecord-repo</id>
|
|
||||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>maven_central</id>
|
|
||||||
<name>Maven Central</name>
|
|
||||||
<url>https://repo.maven.apache.org/maven2/</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-lang3</artifactId>
|
|
||||||
<version>3.14.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.Querz</groupId>
|
<groupId>com.github.Querz</groupId>
|
||||||
<artifactId>NBT</artifactId>
|
<artifactId>NBT</artifactId>
|
||||||
<version>5.5</version>
|
<version>5.5</version>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.10.1</version>
|
<version>2.8.5</version>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.yaml</groupId>
|
<groupId>org.yaml</groupId>
|
||||||
<artifactId>snakeyaml</artifactId>
|
<artifactId>snakeyaml</artifactId>
|
||||||
<version>2.3</version>
|
<version>1.26</version>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.googlecode.json-simple</groupId>
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
<artifactId>json-simple</artifactId>
|
<artifactId>json-simple</artifactId>
|
||||||
<version>1.1.1</version>
|
<version>1.1.1</version>
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-chat</artifactId>
|
<artifactId>bungeecord-chat</artifactId>
|
||||||
<version>1.18-R0.1-SNAPSHOT</version>
|
<version>1.16-R0.3</version>
|
||||||
<type>jar</type>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.kyori</groupId>
|
|
||||||
<artifactId>adventure-text-serializer-gson</artifactId>
|
|
||||||
<version>4.25.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.kyori</groupId>
|
|
||||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
|
||||||
<version>4.25.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.kyori</groupId>
|
|
||||||
<artifactId>adventure-text-serializer-plain</artifactId>
|
|
||||||
<version>4.25.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.kyori</groupId>
|
|
||||||
<artifactId>adventure-api</artifactId>
|
|
||||||
<version>4.25.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.kyori</groupId>
|
|
||||||
<artifactId>adventure-nbt</artifactId>
|
|
||||||
<version>4.25.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.fusesource.jansi</groupId>
|
|
||||||
<artifactId>jansi</artifactId>
|
|
||||||
<version>1.18</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jline</groupId>
|
|
||||||
<artifactId>jline</artifactId>
|
|
||||||
<version>3.16.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>jline</groupId>
|
|
||||||
<artifactId>jline</artifactId>
|
|
||||||
<version>2.11</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>1.8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.8</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
BIN
spawn.schem
BIN
spawn.schem
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.loohp.limbo.Commands;
|
||||||
|
|
||||||
|
public interface CommandExecutor {
|
||||||
|
|
||||||
|
public void execute(CommandSender sender, String[] args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.loohp.limbo.Commands;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
|
||||||
|
public interface CommandSender {
|
||||||
|
|
||||||
|
public void sendMessage(BaseComponent[] component);
|
||||||
|
|
||||||
|
public void sendMessage(BaseComponent component);
|
||||||
|
|
||||||
|
public void sendMessage(String message);
|
||||||
|
|
||||||
|
public boolean hasPermission(String permission);
|
||||||
|
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.loohp.limbo.Commands;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface TabCompletor {
|
||||||
|
|
||||||
|
public List<String> tabComplete(CommandSender sender, String[] args);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,311 @@
|
||||||
|
package com.loohp.limbo;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Commands.CommandSender;
|
||||||
|
import com.loohp.limbo.GUI.ConsoleTextOutput;
|
||||||
|
import com.loohp.limbo.Utils.CustomStringUtils;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
|
||||||
|
public class Console implements CommandSender {
|
||||||
|
|
||||||
|
private InputStream in;
|
||||||
|
private PrintStream out;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private PrintStream err;
|
||||||
|
protected PrintStream logs;
|
||||||
|
|
||||||
|
private final String CONSOLE = "CONSOLE";
|
||||||
|
|
||||||
|
public Console(InputStream in, PrintStream out, PrintStream err) throws FileNotFoundException {
|
||||||
|
String fileName = new SimpleDateFormat("yyyy'-'MM'-'dd'_'HH'-'mm'-'ss'_'zzz'.log'").format(new Date());
|
||||||
|
File dir = new File("logs");
|
||||||
|
dir.mkdirs();
|
||||||
|
File logs = new File(dir, fileName);
|
||||||
|
this.logs = new PrintStream(logs);
|
||||||
|
|
||||||
|
if (in != null) {
|
||||||
|
System.setIn(in);
|
||||||
|
this.in = System.in;
|
||||||
|
} else {
|
||||||
|
this.in = null;
|
||||||
|
}
|
||||||
|
System.setOut(new ConsoleOutputStream(out == null ? new PrintStream(new PrintStream(new OutputStream() {
|
||||||
|
@Override
|
||||||
|
public void write(int b) {
|
||||||
|
//DO NOTHING
|
||||||
|
}
|
||||||
|
})) : out, this.logs));
|
||||||
|
this.out = System.out;
|
||||||
|
System.setErr(new ConsoleErrorStream(err == null ? new PrintStream(new PrintStream(new OutputStream() {
|
||||||
|
@Override
|
||||||
|
public void write(int b) {
|
||||||
|
//DO NOTHING
|
||||||
|
}
|
||||||
|
})) : err, this.logs));
|
||||||
|
this.err = System.err;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return CONSOLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(BaseComponent component) {
|
||||||
|
sendMessage(new BaseComponent[] {component});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(BaseComponent[] component) {
|
||||||
|
sendMessage(String.join("", Arrays.asList(component).stream().map(each -> each.toLegacyText()).collect(Collectors.toList())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(String permission) {
|
||||||
|
return Limbo.getInstance().getPermissionsManager().hasPermission(this, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(String message) {
|
||||||
|
out.println(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void run() {
|
||||||
|
if (in == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
String[] input = CustomStringUtils.splitStringToArgs(reader.readLine());
|
||||||
|
Limbo.getInstance().dispatchCommand(this, input);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConsoleOutputStream extends PrintStream {
|
||||||
|
|
||||||
|
private PrintStream logs;
|
||||||
|
|
||||||
|
public ConsoleOutputStream(OutputStream out, PrintStream logs) {
|
||||||
|
super(out);
|
||||||
|
this.logs = logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrintStream printf(Locale l, String format, Object... args) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText(String.format(l, "[" + date + " Info]" + format, args));
|
||||||
|
logs.printf(l, "[" + date + " Info]" + format, args);
|
||||||
|
return super.printf(l, "[" + date + " Info]" + format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrintStream printf(String format, Object... args) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText(String.format("[" + date + " Info]" + format, args));
|
||||||
|
logs.printf("[" + date + " Info]" + format, args);
|
||||||
|
return super.printf("[" + date + " Info]" + format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println() {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info]", true);
|
||||||
|
logs.println("[" + date + " Info]");
|
||||||
|
super.println("[" + date + " Info]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(boolean x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + x, true);
|
||||||
|
logs.println("[" + date + " Info]" + x);
|
||||||
|
super.println("[" + date + " Info]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(char x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + x, true);
|
||||||
|
logs.println("[" + date + " Info]" + x);
|
||||||
|
super.println("[" + date + " Info]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(char[] x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + String.valueOf(x), true);
|
||||||
|
logs.println("[" + date + " Info]" + String.valueOf(x));
|
||||||
|
super.println("[" + date + " Info]" + String.valueOf(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(double x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + x, true);
|
||||||
|
logs.println("[" + date + " Info]" + x);
|
||||||
|
super.println("[" + date + " Info]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(float x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + x, true);
|
||||||
|
logs.println("[" + date + " Info]" + x);
|
||||||
|
super.println("[" + date + " Info]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(int x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + x, true);
|
||||||
|
logs.println("[" + date + " Info]" + x);
|
||||||
|
super.println("[" + date + " Info]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(long x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + x, true);
|
||||||
|
logs.println("[" + date + " Info]" + x);
|
||||||
|
super.println("[" + date + " Info]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(Object x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + x, true);
|
||||||
|
logs.println("[" + date + " Info]" + x);
|
||||||
|
super.println("[" + date + " Info]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(String string) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Info] " + string, true);
|
||||||
|
logs.println("[" + date + " Info] " + string);
|
||||||
|
super.println("[" + date + " Info] " + string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ConsoleErrorStream extends PrintStream {
|
||||||
|
|
||||||
|
private PrintStream logs;
|
||||||
|
|
||||||
|
public ConsoleErrorStream(OutputStream out, PrintStream logs) {
|
||||||
|
super(out);
|
||||||
|
this.logs = logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrintStream printf(Locale l, String format, Object... args) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText(String.format(l, "[" + date + " Error]" + format, args));
|
||||||
|
logs.printf(l, "[" + date + " Error]" + format, args);
|
||||||
|
return super.printf(l, "[" + date + " Error]" + format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrintStream printf(String format, Object... args) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText(String.format("[" + date + " Error]" + format, args));
|
||||||
|
logs.printf("[" + date + " Error]" + format, args);
|
||||||
|
return super.printf("[" + date + " Error]" + format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println() {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error]", true);
|
||||||
|
logs.println("[" + date + " Error]");
|
||||||
|
super.println("[" + date + " Error]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(boolean x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + x, true);
|
||||||
|
logs.println("[" + date + " Error]" + x);
|
||||||
|
super.println("[" + date + " Error]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(char x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + x, true);
|
||||||
|
logs.println("[" + date + " Error]" + x);
|
||||||
|
super.println("[" + date + " Error]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(char[] x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + String.valueOf(x), true);
|
||||||
|
logs.println("[" + date + " Error]" + String.valueOf(x));
|
||||||
|
super.println("[" + date + " Error]" + String.valueOf(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(double x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + x, true);
|
||||||
|
logs.println("[" + date + " Error]" + x);
|
||||||
|
super.println("[" + date + " Error]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(float x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + x, true);
|
||||||
|
logs.println("[" + date + " Error]" + x);
|
||||||
|
super.println("[" + date + " Error]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(int x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + x, true);
|
||||||
|
logs.println("[" + date + " Error]" + x);
|
||||||
|
super.println("[" + date + " Error]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(long x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + x, true);
|
||||||
|
logs.println("[" + date + " Error]" + x);
|
||||||
|
super.println("[" + date + " Error]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(Object x) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + x, true);
|
||||||
|
logs.println("[" + date + " Error]" + x);
|
||||||
|
super.println("[" + date + " Error]" + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void println(String string) {
|
||||||
|
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
||||||
|
ConsoleTextOutput.appendText("[" + date + " Error] " + string, true);
|
||||||
|
logs.println("[" + date + " Error] " + string);
|
||||||
|
super.println("[" + date + " Error] " + string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,27 +1,4 @@
|
||||||
/*
|
package com.loohp.limbo;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.utils;
|
|
||||||
|
|
||||||
import com.loohp.limbo.Limbo;
|
|
||||||
import com.loohp.limbo.commands.CommandSender;
|
|
||||||
import com.loohp.limbo.network.protocol.packets.PacketPlayOutDeclareCommands;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
|
|
@ -29,24 +6,22 @@ import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Commands.CommandSender;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutDeclareCommands;
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
public class DeclareCommands {
|
public class DeclareCommands {
|
||||||
|
|
||||||
public static PacketPlayOutDeclareCommands getDeclareCommandsPacket(CommandSender sender) throws IOException {
|
public static PacketPlayOutDeclareCommands getDeclareCommandsPacket(CommandSender sender) throws IOException {
|
||||||
List<String> commands = Limbo.getInstance().getPluginManager().getTabOptions(sender, new String[0]);
|
List<String> commands = Limbo.getInstance().getPluginManager().getTabOptions(sender, new String[0]);
|
||||||
|
|
||||||
|
if (commands.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
DataOutputStream output = new DataOutputStream(buffer);
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
|
||||||
if (commands.isEmpty()) {
|
|
||||||
DataTypeIO.writeVarInt(output, 1);
|
|
||||||
|
|
||||||
output.writeByte(0);
|
|
||||||
DataTypeIO.writeVarInt(output, 0);
|
|
||||||
DataTypeIO.writeVarInt(output, 0);
|
|
||||||
|
|
||||||
return new PacketPlayOutDeclareCommands(buffer.toByteArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
DataTypeIO.writeVarInt(output, commands.size() * 2 + 1);
|
DataTypeIO.writeVarInt(output, commands.size() * 2 + 1);
|
||||||
|
|
||||||
output.writeByte(0);
|
output.writeByte(0);
|
||||||
|
|
@ -64,10 +39,11 @@ public class DeclareCommands {
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
output.writeByte(2 | 0x04 | 0x10);
|
output.writeByte(2 | 0x04 | 0x10);
|
||||||
DataTypeIO.writeVarInt(output, 0);
|
DataTypeIO.writeVarInt(output, 1);
|
||||||
|
DataTypeIO.writeVarInt(output, i);
|
||||||
DataTypeIO.writeString(output, "arg", StandardCharsets.UTF_8);
|
DataTypeIO.writeString(output, "arg", StandardCharsets.UTF_8);
|
||||||
DataTypeIO.writeVarInt(output, 5); //brigadier:string
|
DataTypeIO.writeString(output, "brigadier:string", StandardCharsets.UTF_8);
|
||||||
DataTypeIO.writeVarInt(output, 2);
|
DataTypeIO.writeVarInt(output, 0);
|
||||||
DataTypeIO.writeString(output, "minecraft:ask_server", StandardCharsets.UTF_8);
|
DataTypeIO.writeString(output, "minecraft:ask_server", StandardCharsets.UTF_8);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
public interface Cancellable {
|
||||||
|
|
||||||
|
public void setCancelled(boolean cancelled);
|
||||||
|
|
||||||
|
public boolean isCancelled();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
public abstract class Event {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface EventHandler {
|
||||||
|
EventPriority priority() default EventPriority.NORMAL;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
public enum EventPriority {
|
||||||
|
LOWEST(0),
|
||||||
|
LOW(1),
|
||||||
|
NORMAL(2),
|
||||||
|
HIGH(3),
|
||||||
|
HIGHEST(4),
|
||||||
|
MONITOR(5);
|
||||||
|
|
||||||
|
int order;
|
||||||
|
|
||||||
|
EventPriority(int order) {
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOrder() {
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventPriority getByOrder(int order) {
|
||||||
|
for (EventPriority each : EventPriority.values()) {
|
||||||
|
if (each.getOrder() == order) {
|
||||||
|
return each;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventPriority[] getPrioritiesInOrder() {
|
||||||
|
EventPriority[] array = new EventPriority[EventPriority.values().length];
|
||||||
|
for (int i = 0; i < array.length; i++) {
|
||||||
|
array[i] = EventPriority.getByOrder(i);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Plugins.LimboPlugin;
|
||||||
|
|
||||||
|
public class EventsManager {
|
||||||
|
|
||||||
|
private List<ListenerPair> listeners;
|
||||||
|
|
||||||
|
public EventsManager() {
|
||||||
|
listeners = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Event> T callEvent(T event) {
|
||||||
|
for (EventPriority priority : EventPriority.getPrioritiesInOrder()) {
|
||||||
|
for (ListenerPair entry : listeners) {
|
||||||
|
Listener listener = entry.listener;
|
||||||
|
for (Method method : listener.getClass().getMethods()) {
|
||||||
|
if (method.isAnnotationPresent(EventHandler.class)) {
|
||||||
|
if (method.getAnnotation(EventHandler.class).priority().equals(priority)) {
|
||||||
|
if (method.getParameterCount() == 1 && method.getParameterTypes()[0].equals(event.getClass())) {
|
||||||
|
try {
|
||||||
|
method.invoke(listener, event);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error while passing " + event.getClass().getCanonicalName() + " to the plugin \"" + entry.plugin.getName() + "\"");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerEvents(LimboPlugin plugin, Listener listener) {
|
||||||
|
listeners.add(new ListenerPair(plugin, listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregisterAllListeners(LimboPlugin plugin) {
|
||||||
|
listeners.removeIf(each -> each.plugin.equals(plugin));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class ListenerPair {
|
||||||
|
public LimboPlugin plugin;
|
||||||
|
public Listener listener;
|
||||||
|
|
||||||
|
public ListenerPair(LimboPlugin plugin, Listener listener) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Player.Player;
|
||||||
|
|
||||||
|
public class PlayerChatEvent extends PlayerEvent implements Cancellable {
|
||||||
|
|
||||||
|
private String prefix;
|
||||||
|
private String message;
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
public PlayerChatEvent(Player player, String prefix, String message, boolean cancelled) {
|
||||||
|
this.player = player;
|
||||||
|
this.prefix = prefix;
|
||||||
|
this.message = message;
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrefix(String prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancelled) {
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Player.Player;
|
||||||
|
|
||||||
|
public abstract class PlayerEvent extends Event {
|
||||||
|
|
||||||
|
protected Player player;
|
||||||
|
|
||||||
|
public abstract Player getPlayer();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Player.Player;
|
||||||
|
|
||||||
|
public class PlayerJoinEvent extends PlayerEvent {
|
||||||
|
|
||||||
|
public PlayerJoinEvent(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Server.ClientConnection;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
|
||||||
|
public class PlayerLoginEvent extends Event implements Cancellable {
|
||||||
|
|
||||||
|
private ClientConnection connection;
|
||||||
|
private boolean cancelled;
|
||||||
|
private BaseComponent[] cancelReason;
|
||||||
|
|
||||||
|
public PlayerLoginEvent(ClientConnection connection, boolean cancelled, BaseComponent... cancelReason) {
|
||||||
|
this.connection = connection;
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
this.cancelReason = cancelReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientConnection getConnection() {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseComponent[] getCancelReason() {
|
||||||
|
return cancelReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCancelReason(BaseComponent... cancelReason) {
|
||||||
|
this.cancelReason = cancelReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancelled) {
|
||||||
|
this.cancelled = cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.loohp.limbo.Events;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Player.Player;
|
||||||
|
|
||||||
|
public class PlayerQuitEvent extends PlayerEvent {
|
||||||
|
|
||||||
|
public PlayerQuitEvent(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,41 +1,22 @@
|
||||||
/*
|
package com.loohp.limbo.Events;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.events.status;
|
|
||||||
|
|
||||||
import com.loohp.limbo.events.Event;
|
|
||||||
import com.loohp.limbo.network.ClientConnection;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Server.ClientConnection;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
|
||||||
public class StatusPingEvent extends Event {
|
public class StatusPingEvent extends Event {
|
||||||
|
|
||||||
private ClientConnection connection;
|
private ClientConnection connection;
|
||||||
private String version;
|
private String version;
|
||||||
private int protocol;
|
private int protocol;
|
||||||
private Component motd;
|
private BaseComponent[] motd;
|
||||||
private int maxPlayers;
|
private int maxPlayers;
|
||||||
private int playersOnline;
|
private int playersOnline;
|
||||||
private BufferedImage favicon;
|
private BufferedImage favicon;
|
||||||
|
|
||||||
public StatusPingEvent(ClientConnection connection, String version, int protocol, Component motd, int maxPlayers, int playersOnline, BufferedImage favicon) {
|
public StatusPingEvent(ClientConnection connection, String version, int protocol, BaseComponent[] motd, int maxPlayers, int playersOnline, BufferedImage favicon) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
|
|
@ -65,11 +46,11 @@ public class StatusPingEvent extends Event {
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Component getMotd() {
|
public BaseComponent[] getMotd() {
|
||||||
return motd;
|
return motd;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMotd(Component motd) {
|
public void setMotd(BaseComponent[] motd) {
|
||||||
this.motd = motd;
|
this.motd = motd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
package com.loohp.limbo.File;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
import org.yaml.snakeyaml.representer.Representer;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.YamlOrder;
|
||||||
|
|
||||||
|
public class FileConfiguration {
|
||||||
|
|
||||||
|
Map<String, Object> mapping;
|
||||||
|
String header;
|
||||||
|
|
||||||
|
public FileConfiguration(File file) {
|
||||||
|
if (file.exists()) {
|
||||||
|
try {
|
||||||
|
reloadConfig(new FileInputStream(file));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mapping = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileConfiguration(InputStream input){
|
||||||
|
reloadConfig(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileConfiguration reloadConfig(InputStream input) {
|
||||||
|
Yaml yml = new Yaml();
|
||||||
|
mapping = yml.load(input);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeader(String header) {
|
||||||
|
this.header = header;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T get(String key, Class<T> returnType) {
|
||||||
|
try {
|
||||||
|
String[] tree = key.split("\\.");
|
||||||
|
Map<String, Object> map = mapping;
|
||||||
|
for (int i = 0; i < tree.length - 1; i++) {
|
||||||
|
map = (Map<String, Object>) map.get(tree[i]);
|
||||||
|
}
|
||||||
|
if (returnType.equals(String.class)) {
|
||||||
|
return (T) map.get(tree[tree.length - 1]).toString();
|
||||||
|
}
|
||||||
|
return returnType.cast(map.get(tree[tree.length - 1]));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> void set(String key, T value) {
|
||||||
|
String[] tree = key.split("\\.");
|
||||||
|
Map<String, Object> map = mapping;
|
||||||
|
for (int i = 0; i < tree.length - 1; i++) {
|
||||||
|
Map<String, Object> map1 = (Map<String, Object>) map.get(tree[i]);
|
||||||
|
if (map1 == null) {
|
||||||
|
map1 = new LinkedHashMap<>();
|
||||||
|
map.put(tree[i], map1);
|
||||||
|
}
|
||||||
|
map = map1;
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
map.put(tree[tree.length - 1], (T) value);
|
||||||
|
} else {
|
||||||
|
map.remove(tree[tree.length - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveConfig(File file) throws FileNotFoundException, UnsupportedEncodingException {
|
||||||
|
DumperOptions options = new DumperOptions();
|
||||||
|
options.setIndent(2);
|
||||||
|
options.setPrettyFlow(true);
|
||||||
|
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
||||||
|
Representer customRepresenter = new Representer();
|
||||||
|
YamlOrder customProperty = new YamlOrder();
|
||||||
|
customRepresenter.setPropertyUtils(customProperty);
|
||||||
|
Yaml yaml = new Yaml(customRepresenter, options);
|
||||||
|
|
||||||
|
PrintWriter pw = new PrintWriter(file, StandardCharsets.UTF_8.toString());
|
||||||
|
if (header != null) {
|
||||||
|
pw.println(header);
|
||||||
|
}
|
||||||
|
yaml.dump(mapping, pw);
|
||||||
|
pw.flush();
|
||||||
|
pw.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,165 @@
|
||||||
|
package com.loohp.limbo.File;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
import com.loohp.limbo.Location.Location;
|
||||||
|
import com.loohp.limbo.Utils.GameMode;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
import com.loohp.limbo.World.World;
|
||||||
|
|
||||||
|
public class ServerProperties {
|
||||||
|
|
||||||
|
public static final String JSON_BASE_RESPONSE = "{\"version\":{\"name\":\"%VERSION%\",\"protocol\":%PROTOCOL%},\"players\":{\"max\":%MAXPLAYERS%,\"online\":%ONLINECLIENTS%},\"description\":%MOTD%,%FAVICON%\"modinfo\":{\"type\":\"FML\",\"modList\":[]}}";
|
||||||
|
|
||||||
|
File file;
|
||||||
|
int maxPlayers;
|
||||||
|
int serverPort;
|
||||||
|
String serverIp;
|
||||||
|
NamespacedKey levelName;
|
||||||
|
String schemFileName;
|
||||||
|
NamespacedKey levelDimension;
|
||||||
|
GameMode defaultGamemode;
|
||||||
|
Location worldSpawn;
|
||||||
|
boolean reducedDebugInfo;
|
||||||
|
boolean allowFlight;
|
||||||
|
String motdJson;
|
||||||
|
String versionString;
|
||||||
|
int protocol;
|
||||||
|
boolean bungeecord;
|
||||||
|
|
||||||
|
Optional<BufferedImage> favicon;
|
||||||
|
|
||||||
|
public ServerProperties(File file) throws IOException {
|
||||||
|
this.file = file;
|
||||||
|
Properties prop = new Properties();
|
||||||
|
prop.load(new FileInputStream(file));
|
||||||
|
|
||||||
|
protocol = Limbo.getInstance().serverImplmentationProtocol;
|
||||||
|
|
||||||
|
maxPlayers = Integer.parseInt(prop.getProperty("max-players"));
|
||||||
|
serverPort = Integer.parseInt(prop.getProperty("server-port"));
|
||||||
|
serverIp = prop.getProperty("server-ip");
|
||||||
|
String[] level = prop.getProperty("level-name").split(";");
|
||||||
|
levelName = new NamespacedKey(level[0]);
|
||||||
|
schemFileName = level[1];
|
||||||
|
levelDimension = new NamespacedKey(prop.getProperty("level-dimension"));
|
||||||
|
defaultGamemode = GameMode.fromName(new NamespacedKey(prop.getProperty("default-gamemode")).getKey());
|
||||||
|
String[] locStr = prop.getProperty("world-spawn").split(";");
|
||||||
|
World world = Limbo.getInstance().getWorld(locStr[0]);
|
||||||
|
double x = Double.parseDouble(locStr[1]);
|
||||||
|
double y = Double.parseDouble(locStr[2]);
|
||||||
|
double z = Double.parseDouble(locStr[3]);
|
||||||
|
float yaw = Float.parseFloat(locStr[4]);
|
||||||
|
float pitch = Float.parseFloat(locStr[5]);
|
||||||
|
worldSpawn = new Location(world, x, y, z, yaw, pitch);
|
||||||
|
reducedDebugInfo = Boolean.parseBoolean(prop.getProperty("reduced-debug-info"));
|
||||||
|
allowFlight = Boolean.parseBoolean(prop.getProperty("allow-flight"));
|
||||||
|
motdJson = prop.getProperty("motd");
|
||||||
|
versionString = prop.getProperty("version");
|
||||||
|
bungeecord = Boolean.parseBoolean(prop.getProperty("bungeecord"));
|
||||||
|
|
||||||
|
File png = new File("server-icon.png");
|
||||||
|
if (png.exists()) {
|
||||||
|
try {
|
||||||
|
BufferedImage image = ImageIO.read(png);
|
||||||
|
if (image.getHeight() == 64 && image.getWidth() == 64) {
|
||||||
|
favicon = Optional.of(image);
|
||||||
|
} else {
|
||||||
|
System.out.println("Unable to load server-icon.png! The image is not 64 x 64 in size!");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Unable to load server-icon.png! Is it a png image?");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("No server-icon.png found");
|
||||||
|
favicon = Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Loaded server.properties");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerImplementationVersion() {
|
||||||
|
return Limbo.getInstance().serverImplementationVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBungeecord() {
|
||||||
|
return bungeecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<BufferedImage> getFavicon() {
|
||||||
|
return favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxPlayers() {
|
||||||
|
return maxPlayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getServerPort() {
|
||||||
|
return serverPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerIp() {
|
||||||
|
return serverIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getLevelName() {
|
||||||
|
return levelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchemFileName() {
|
||||||
|
return schemFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getLevelDimension() {
|
||||||
|
return levelDimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameMode getDefaultGamemode() {
|
||||||
|
return defaultGamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getWorldSpawn() {
|
||||||
|
return worldSpawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorldSpawn(Location location) {
|
||||||
|
this.worldSpawn = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReducedDebugInfo() {
|
||||||
|
return reducedDebugInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllowFlight() {
|
||||||
|
return allowFlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getJsonBaseResponse() {
|
||||||
|
return JSON_BASE_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMotdJson() {
|
||||||
|
return motdJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersionString() {
|
||||||
|
return versionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getProtocol() {
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.loohp.limbo.GUI;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
|
||||||
|
public class ConsoleTextOutput {
|
||||||
|
|
||||||
|
public static void appendText(String string) {
|
||||||
|
if (!Limbo.noGui) {
|
||||||
|
GUI.textOutput.setText(GUI.textOutput.getText() + string);
|
||||||
|
GUI.scrollPane.getVerticalScrollBar().setValue(GUI.scrollPane.getVerticalScrollBar().getMaximum());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void appendText(String string, boolean isWriteLine) {
|
||||||
|
if (isWriteLine) {
|
||||||
|
appendText(string + "\n");
|
||||||
|
} else {
|
||||||
|
appendText(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,36 +1,5 @@
|
||||||
/*
|
package com.loohp.limbo.GUI;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.consolegui;
|
|
||||||
|
|
||||||
import com.loohp.limbo.Limbo;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.JTextPane;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.UnsupportedLookAndFeelException;
|
|
||||||
import javax.swing.border.EmptyBorder;
|
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.GridBagConstraints;
|
import java.awt.GridBagConstraints;
|
||||||
import java.awt.GridBagLayout;
|
import java.awt.GridBagLayout;
|
||||||
|
|
@ -44,6 +13,17 @@ import java.awt.event.WindowEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
import javax.swing.JTextPane;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class GUI extends JFrame {
|
public class GUI extends JFrame {
|
||||||
|
|
||||||
|
|
@ -68,8 +48,7 @@ public class GUI extends JFrame {
|
||||||
/**
|
/**
|
||||||
* Launch the application.
|
* Launch the application.
|
||||||
*/
|
*/
|
||||||
public static void main() throws UnsupportedLookAndFeelException, ClassNotFoundException, InstantiationException, IllegalAccessException {
|
public static void main() {
|
||||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
|
||||||
GUI frame = new GUI();
|
GUI frame = new GUI();
|
||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
|
|
||||||
|
|
@ -92,10 +71,8 @@ public class GUI extends JFrame {
|
||||||
addWindowListener(new WindowAdapter() {
|
addWindowListener(new WindowAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void windowClosing(WindowEvent e) {
|
public void windowClosing(WindowEvent e) {
|
||||||
if (Limbo.getInstance().isRunning()) {
|
|
||||||
Limbo.getInstance().stopServer();
|
Limbo.getInstance().stopServer();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
setBounds(100, 100, 1198, 686);
|
setBounds(100, 100, 1198, 686);
|
||||||
contentPane = new JPanel();
|
contentPane = new JPanel();
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.loohp.limbo.GUI;
|
||||||
|
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
|
||||||
|
public class SystemInfo {
|
||||||
|
|
||||||
|
public static void printInfo() {
|
||||||
|
if (!Limbo.noGui) {
|
||||||
|
while (true) {
|
||||||
|
Runtime runtime = Runtime.getRuntime();
|
||||||
|
|
||||||
|
NumberFormat format = NumberFormat.getInstance();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
long maxMemory = runtime.maxMemory();
|
||||||
|
long allocatedMemory = runtime.totalMemory();
|
||||||
|
long freeMemory = runtime.freeMemory();
|
||||||
|
|
||||||
|
sb.append("Free Memory: " + format.format(freeMemory / 1024 / 1024) + " MB\n");
|
||||||
|
sb.append("Allocated Memory: " + format.format(allocatedMemory / 1024 / 1024) + " MB\n");
|
||||||
|
sb.append("Max Memory: " + format.format(maxMemory / 1024 / 1024) + " MB\n");
|
||||||
|
sb.append("Memory Usage: " + format.format((allocatedMemory - freeMemory) / 1024 / 1024) + "/" + format.format(maxMemory / 1024 / 1024) + " MB (" + Math.round((double) (allocatedMemory - freeMemory) / (double) (maxMemory) * 100) + "%)\n");
|
||||||
|
sb.append("\n");
|
||||||
|
|
||||||
|
try {
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
|
com.sun.management.OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
|
double processLoad = operatingSystemMXBean.getProcessCpuLoad();
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
|
double systemLoad = operatingSystemMXBean.getSystemCpuLoad();
|
||||||
|
int processors = runtime.availableProcessors();
|
||||||
|
|
||||||
|
sb.append("Available Processors: " + processors + "\n");
|
||||||
|
sb.append("Process CPU Load: " + Math.round(processLoad * 100) + "%\n");
|
||||||
|
sb.append("System CPU Load: " + Math.round(systemLoad * 100) + "%\n");
|
||||||
|
GUI.sysText.setText(sb.toString());
|
||||||
|
} catch (Exception ignore) {}
|
||||||
|
|
||||||
|
try {TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,495 @@
|
||||||
|
package com.loohp.limbo;
|
||||||
|
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.loohp.limbo.Commands.CommandSender;
|
||||||
|
import com.loohp.limbo.Events.EventsManager;
|
||||||
|
import com.loohp.limbo.File.ServerProperties;
|
||||||
|
import com.loohp.limbo.GUI.GUI;
|
||||||
|
import com.loohp.limbo.Location.Location;
|
||||||
|
import com.loohp.limbo.Permissions.PermissionsManager;
|
||||||
|
import com.loohp.limbo.Player.Player;
|
||||||
|
import com.loohp.limbo.Plugins.LimboPlugin;
|
||||||
|
import com.loohp.limbo.Plugins.PluginManager;
|
||||||
|
import com.loohp.limbo.Server.ServerConnection;
|
||||||
|
import com.loohp.limbo.Server.Packets.Packet;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketIn;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketOut;
|
||||||
|
import com.loohp.limbo.Utils.CustomStringUtils;
|
||||||
|
import com.loohp.limbo.Utils.ImageUtils;
|
||||||
|
import com.loohp.limbo.Utils.NetworkUtils;
|
||||||
|
import com.loohp.limbo.World.Schematic;
|
||||||
|
import com.loohp.limbo.World.World;
|
||||||
|
import com.loohp.limbo.World.World.Environment;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import net.querz.nbt.io.NBTUtil;
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
|
||||||
|
public class Limbo {
|
||||||
|
|
||||||
|
private static Limbo instance;
|
||||||
|
public static boolean noGui = false;
|
||||||
|
|
||||||
|
public static void main(String args[]) throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
|
||||||
|
for (String flag : args) {
|
||||||
|
if (flag.equals("--nogui")) {
|
||||||
|
noGui = true;
|
||||||
|
} else {
|
||||||
|
System.out.println("Accepted flags:");
|
||||||
|
System.out.println(" --nogui ");
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("Press [enter] to quit");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (GraphicsEnvironment.isHeadless()) {
|
||||||
|
noGui = true;
|
||||||
|
}
|
||||||
|
if (!noGui) {
|
||||||
|
System.out.println("Launching Server GUI.. Add \"--nogui\" in launch arguments to disable");
|
||||||
|
Thread t1 = new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
GUI.main();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t1.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
new Limbo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Limbo getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================
|
||||||
|
|
||||||
|
public final String serverImplementationVersion = "1.16.2";
|
||||||
|
public final int serverImplmentationProtocol = 751;
|
||||||
|
|
||||||
|
private ServerConnection server;
|
||||||
|
private Console console;
|
||||||
|
|
||||||
|
private List<World> worlds = new ArrayList<>();
|
||||||
|
private Map<String, Player> playersByName = new HashMap<>();
|
||||||
|
private Map<UUID, Player> playersByUUID = new HashMap<>();
|
||||||
|
|
||||||
|
private ServerProperties properties;
|
||||||
|
|
||||||
|
private PluginManager pluginManager;
|
||||||
|
private EventsManager eventsManager;
|
||||||
|
private PermissionsManager permissionManager;
|
||||||
|
private File pluginFolder;
|
||||||
|
|
||||||
|
private File internalDataFolder;
|
||||||
|
|
||||||
|
public AtomicInteger entityIdCount = new AtomicInteger();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
if (!noGui) {
|
||||||
|
while (!GUI.loadFinish) {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(500);
|
||||||
|
}
|
||||||
|
console = new Console(null, System.out, System.err);
|
||||||
|
} else {
|
||||||
|
console = new Console(System.in, System.out, System.err);
|
||||||
|
}
|
||||||
|
|
||||||
|
String spName = "server.properties";
|
||||||
|
File sp = new File(spName);
|
||||||
|
if (!sp.exists()) {
|
||||||
|
try (InputStream in = getClass().getClassLoader().getResourceAsStream(spName)) {
|
||||||
|
Files.copy(in, sp.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties = new ServerProperties(sp);
|
||||||
|
|
||||||
|
if (!properties.isBungeecord()) {
|
||||||
|
console.sendMessage("If you are using bungeecord, consider turning that on in the settings!");
|
||||||
|
} else {
|
||||||
|
console.sendMessage("Starting Limbo server in bungeecord mode!");
|
||||||
|
}
|
||||||
|
|
||||||
|
internalDataFolder = new File("internal_data");
|
||||||
|
if (!internalDataFolder.exists()) {
|
||||||
|
internalDataFolder.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
String mappingName = "mapping.json";
|
||||||
|
File mappingFile = new File(internalDataFolder, mappingName);
|
||||||
|
if (!mappingFile.exists()) {
|
||||||
|
try (InputStream in = getClass().getClassLoader().getResourceAsStream(mappingName)) {
|
||||||
|
Files.copy(in, mappingFile.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.sendMessage("Loading packet id mappings from mapping.json ...");
|
||||||
|
|
||||||
|
JSONObject json = (JSONObject) new JSONParser().parse(new FileReader(mappingFile));
|
||||||
|
|
||||||
|
String classPrefix = Packet.class.getName().substring(0, Packet.class.getName().lastIndexOf(".") + 1);
|
||||||
|
int mappingsCount = 0;
|
||||||
|
|
||||||
|
Map<Integer, Class<? extends PacketIn>> HandshakeIn = new HashMap<>();
|
||||||
|
for (Object key : ((JSONObject) json.get("HandshakeIn")).keySet()) {
|
||||||
|
int packetId = Integer.decode((String) key);
|
||||||
|
HandshakeIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + (String) ((JSONObject) json.get("HandshakeIn")).get(key)));
|
||||||
|
}
|
||||||
|
Packet.setHandshakeIn(HandshakeIn);
|
||||||
|
mappingsCount += HandshakeIn.size();
|
||||||
|
|
||||||
|
Map<Integer, Class<? extends PacketIn>> StatusIn = new HashMap<>();
|
||||||
|
for (Object key : ((JSONObject) json.get("StatusIn")).keySet()) {
|
||||||
|
int packetId = Integer.decode((String) key);
|
||||||
|
StatusIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + (String) ((JSONObject) json.get("StatusIn")).get(key)));
|
||||||
|
}
|
||||||
|
Packet.setStatusIn(StatusIn);
|
||||||
|
mappingsCount += StatusIn.size();
|
||||||
|
|
||||||
|
Map<Class<? extends PacketOut>, Integer> StatusOut = new HashMap<>();
|
||||||
|
for (Object key : ((JSONObject) json.get("StatusOut")).keySet()) {
|
||||||
|
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + (String) key);
|
||||||
|
StatusOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("StatusOut")).get(key)));
|
||||||
|
}
|
||||||
|
Packet.setStatusOut(StatusOut);
|
||||||
|
mappingsCount += StatusOut.size();
|
||||||
|
|
||||||
|
Map<Integer, Class<? extends PacketIn>> LoginIn = new HashMap<>();
|
||||||
|
for (Object key : ((JSONObject) json.get("LoginIn")).keySet()) {
|
||||||
|
int packetId = Integer.decode((String) key);
|
||||||
|
LoginIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + (String) ((JSONObject) json.get("LoginIn")).get(key)));
|
||||||
|
}
|
||||||
|
Packet.setLoginIn(LoginIn);
|
||||||
|
mappingsCount += LoginIn.size();
|
||||||
|
|
||||||
|
Map<Class<? extends PacketOut>, Integer> LoginOut = new HashMap<>();
|
||||||
|
for (Object key : ((JSONObject) json.get("LoginOut")).keySet()) {
|
||||||
|
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + (String) key);
|
||||||
|
LoginOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("LoginOut")).get(key)));
|
||||||
|
}
|
||||||
|
Packet.setLoginOut(LoginOut);
|
||||||
|
mappingsCount += LoginOut.size();
|
||||||
|
|
||||||
|
Map<Integer, Class<? extends PacketIn>> PlayIn = new HashMap<>();
|
||||||
|
for (Object key : ((JSONObject) json.get("PlayIn")).keySet()) {
|
||||||
|
int packetId = Integer.decode((String) key);
|
||||||
|
PlayIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + (String) ((JSONObject) json.get("PlayIn")).get(key)));
|
||||||
|
}
|
||||||
|
Packet.setPlayIn(PlayIn);
|
||||||
|
mappingsCount += PlayIn.size();
|
||||||
|
|
||||||
|
Map<Class<? extends PacketOut>, Integer> PlayOut = new HashMap<>();
|
||||||
|
for (Object key : ((JSONObject) json.get("PlayOut")).keySet()) {
|
||||||
|
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + (String) key);
|
||||||
|
PlayOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("PlayOut")).get(key)));
|
||||||
|
}
|
||||||
|
Packet.setPlayOut(PlayOut);
|
||||||
|
mappingsCount += PlayOut.size();
|
||||||
|
|
||||||
|
console.sendMessage("Loaded all " + mappingsCount + " packet id mappings!");
|
||||||
|
|
||||||
|
worlds.add(loadDefaultWorld());
|
||||||
|
Location spawn = properties.getWorldSpawn();
|
||||||
|
properties.setWorldSpawn(new Location(getWorld(properties.getLevelName().getKey()), spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getYaw(), spawn.getPitch()));
|
||||||
|
|
||||||
|
if (!NetworkUtils.available(properties.getServerPort())) {
|
||||||
|
console.sendMessage("");
|
||||||
|
console.sendMessage("*****FAILED TO BIND PORT [" + properties.getServerPort() + "]*****");
|
||||||
|
console.sendMessage("*****PORT ALREADY IN USE*****");
|
||||||
|
console.sendMessage("*****PERHAPS ANOTHER INSTANCE OF THE SERVER IS ALREADY RUNNING?*****");
|
||||||
|
console.sendMessage("");
|
||||||
|
System.exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
String permissionName = "permission.yml";
|
||||||
|
File permissionFile = new File(permissionName);
|
||||||
|
if (!permissionFile.exists()) {
|
||||||
|
try (InputStream in = getClass().getClassLoader().getResourceAsStream(permissionName)) {
|
||||||
|
Files.copy(in, permissionFile.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionManager = new PermissionsManager();
|
||||||
|
permissionManager.loadDefaultPermissionFile(permissionFile);
|
||||||
|
|
||||||
|
eventsManager = new EventsManager();
|
||||||
|
|
||||||
|
pluginFolder = new File("plugins");
|
||||||
|
pluginFolder.mkdirs();
|
||||||
|
|
||||||
|
File defaultCommandsJar = new File(pluginFolder, "LimboDefaultCmd.jar");
|
||||||
|
defaultCommandsJar.delete();
|
||||||
|
console.sendMessage("Downloading limbo default commands module from github...");
|
||||||
|
ReadableByteChannel rbc = Channels.newChannel(new URL("https://github.com/LOOHP/Limbo/raw/master/modules/LimboDefaultCmd.jar").openStream());
|
||||||
|
FileOutputStream fos = new FileOutputStream(defaultCommandsJar);
|
||||||
|
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||||
|
fos.close();
|
||||||
|
|
||||||
|
pluginManager = new PluginManager(pluginFolder);
|
||||||
|
|
||||||
|
for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
|
||||||
|
console.sendMessage("Enabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
|
||||||
|
plugin.onEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
server = new ServerConnection(properties.getServerIp(), properties.getServerPort());
|
||||||
|
|
||||||
|
console.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isNoGui() {
|
||||||
|
return noGui;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerImplementationVersion() {
|
||||||
|
return serverImplementationVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getServerImplmentationProtocol() {
|
||||||
|
return serverImplmentationProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerConnection getServer() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Player> getPlayersByName() {
|
||||||
|
return playersByName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<UUID, Player> getPlayersByUUID() {
|
||||||
|
return playersByUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerProperties getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PermissionsManager getPermissionManager() {
|
||||||
|
return permissionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getInternalDataFolder() {
|
||||||
|
return internalDataFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtomicInteger getEntityIdCount() {
|
||||||
|
return entityIdCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventsManager getEventsManager() {
|
||||||
|
return eventsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PermissionsManager getPermissionsManager() {
|
||||||
|
return permissionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getPluginFolder() {
|
||||||
|
return pluginFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginManager getPluginManager() {
|
||||||
|
return pluginManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private World loadDefaultWorld() throws IOException {
|
||||||
|
console.sendMessage("Loading world " + properties.getLevelName() + " with the schematic file " + properties.getSchemFileName() + " ...");
|
||||||
|
|
||||||
|
File schem = new File(properties.getSchemFileName());
|
||||||
|
|
||||||
|
if (!schem.exists()) {
|
||||||
|
console.sendMessage("Schemetic file " + properties.getSchemFileName() + " for world " + properties.getLevelName() + " not found!");
|
||||||
|
console.sendMessage("Server will exit!");
|
||||||
|
System.exit(1);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
World world = Schematic.toWorld(properties.getLevelName().getKey(), Environment.fromNamespacedKey(properties.getLevelDimension()), (CompoundTag) NBTUtil.read(schem).getTag());
|
||||||
|
|
||||||
|
console.sendMessage("Loaded world " + properties.getLevelName() + "!");
|
||||||
|
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerProperties getServerProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerConnection getServerConnection() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Console getConsole() {
|
||||||
|
return console;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Player> getPlayers() {
|
||||||
|
return new HashSet<>(playersByUUID.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer(String name) {
|
||||||
|
return playersByName.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer(UUID uuid) {
|
||||||
|
return playersByUUID.get(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPlayer(Player player) {
|
||||||
|
playersByName.put(player.getName(), player);
|
||||||
|
playersByUUID.put(player.getUUID(), player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePlayer(Player player) {
|
||||||
|
playersByName.remove(player.getName());
|
||||||
|
playersByUUID.remove(player.getUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<World> getWorlds() {
|
||||||
|
return new ArrayList<>(worlds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public World getWorld(String name) {
|
||||||
|
for (World world : worlds) {
|
||||||
|
if (world.getName().equalsIgnoreCase(name)) {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public String buildServerListResponseJson(String version, int protocol, BaseComponent[] motd, int maxPlayers, int playersOnline, BufferedImage favicon) throws IOException {
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
|
||||||
|
JSONObject versionJson = new JSONObject();
|
||||||
|
versionJson.put("name", version);
|
||||||
|
versionJson.put("protocol", protocol);
|
||||||
|
json.put("version", versionJson);
|
||||||
|
|
||||||
|
JSONObject playersJson = new JSONObject();
|
||||||
|
playersJson.put("max", maxPlayers);
|
||||||
|
playersJson.put("online", playersOnline);
|
||||||
|
json.put("players", playersJson);
|
||||||
|
|
||||||
|
json.put("description", "%MOTD%");
|
||||||
|
|
||||||
|
if (favicon != null) {
|
||||||
|
if (favicon.getWidth() == 64 && favicon.getHeight() == 64) {
|
||||||
|
String base64 = "data:image/png;base64," + ImageUtils.imgToBase64String(favicon, "png");
|
||||||
|
json.put("favicon", base64);
|
||||||
|
} else {
|
||||||
|
console.sendMessage("Server List Favicon must be 64 x 64 in size!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject modInfoJson = new JSONObject();
|
||||||
|
modInfoJson.put("type", "FML");
|
||||||
|
modInfoJson.put("modList", new JSONArray());
|
||||||
|
json.put("modinfo", modInfoJson);
|
||||||
|
|
||||||
|
|
||||||
|
TreeMap<String, Object> treeMap = new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
|
||||||
|
treeMap.putAll(json);
|
||||||
|
|
||||||
|
Gson g = new GsonBuilder().create();
|
||||||
|
|
||||||
|
return g.toJson(treeMap).replace("\"%MOTD%\"", ComponentSerializer.toString(motd));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String buildLegacyPingResponse(String version, BaseComponent[] motd, int maxPlayers, int playersOnline) {
|
||||||
|
String begin = "§1";
|
||||||
|
return String.join("\00", begin, "127", version, String.join("", Arrays.asList(motd).stream().map(each -> each.toLegacyText()).collect(Collectors.toList())), String.valueOf(playersOnline), String.valueOf(maxPlayers));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopServer() {
|
||||||
|
console.sendMessage("Stopping Server...");
|
||||||
|
|
||||||
|
for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
|
||||||
|
console.sendMessage("Disabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
|
||||||
|
plugin.onDisable();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Player player : getPlayers()) {
|
||||||
|
player.disconnect("Server closed");
|
||||||
|
}
|
||||||
|
while (!getPlayers().isEmpty()) {
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(500);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.logs.close();
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNextEntityId() {
|
||||||
|
if (entityIdCount.get() == Integer.MAX_VALUE) {
|
||||||
|
return entityIdCount.getAndSet(0);
|
||||||
|
} else {
|
||||||
|
return entityIdCount.getAndIncrement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispatchCommand(CommandSender sender, String str) {
|
||||||
|
String[] command;
|
||||||
|
if (str.startsWith("/")) {
|
||||||
|
command = CustomStringUtils.splitStringToArgs(str.substring(1));
|
||||||
|
} else {
|
||||||
|
command = CustomStringUtils.splitStringToArgs(str);
|
||||||
|
}
|
||||||
|
dispatchCommand(sender, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispatchCommand(CommandSender sender, String... args) {
|
||||||
|
try {
|
||||||
|
Limbo.getInstance().getPluginManager().fireExecutors(sender, args);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
package com.loohp.limbo.Location;
|
||||||
|
|
||||||
|
import com.loohp.limbo.World.World;
|
||||||
|
|
||||||
|
public class Location {
|
||||||
|
|
||||||
|
World world;
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
float yaw;
|
||||||
|
float pitch;
|
||||||
|
|
||||||
|
public Location(World world, double x, double y, double z, float yaw, float pitch) {
|
||||||
|
this.world = world;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location(World world, double x, double y, double z) {
|
||||||
|
this(world, x, y, z, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Location clone() {
|
||||||
|
return new Location(this.world, this.x, this.y, this.z, this.yaw, this.pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public World getWorld() {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWorld(World world) {
|
||||||
|
this.world = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(double x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(double y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZ(double z) {
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getYaw() {
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYaw(float yaw) {
|
||||||
|
this.yaw = yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPitch(float pitch) {
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Location{" + "world=" + world + ",x=" + x + ",y=" + y + ",z=" + z + ",pitch=" + pitch + ",yaw=" + yaw + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + Float.floatToIntBits(pitch);
|
||||||
|
result = prime * result + ((world == null) ? 0 : world.hashCode());
|
||||||
|
long temp;
|
||||||
|
temp = Double.doubleToLongBits(x);
|
||||||
|
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
temp = Double.doubleToLongBits(y);
|
||||||
|
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
result = prime * result + Float.floatToIntBits(yaw);
|
||||||
|
temp = Double.doubleToLongBits(z);
|
||||||
|
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
Location other = (Location) obj;
|
||||||
|
if (Float.floatToIntBits(pitch) != Float.floatToIntBits(other.pitch))
|
||||||
|
return false;
|
||||||
|
if (world == null) {
|
||||||
|
if (other.world != null)
|
||||||
|
return false;
|
||||||
|
} else if (!world.equals(other.world))
|
||||||
|
return false;
|
||||||
|
if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
|
||||||
|
return false;
|
||||||
|
if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
|
||||||
|
return false;
|
||||||
|
if (Float.floatToIntBits(yaw) != Float.floatToIntBits(other.yaw))
|
||||||
|
return false;
|
||||||
|
if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,976 @@
|
||||||
|
package com.loohp.limbo.Metrics;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
import com.loohp.limbo.File.FileConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bStats collects some data for plugin authors.
|
||||||
|
*
|
||||||
|
* Check out https://bStats.org/ to learn more about bStats!
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public class Metrics {
|
||||||
|
|
||||||
|
static {
|
||||||
|
// Maven's Relocate is clever and changes strings, too. So we have to use this little "trick" ... :D
|
||||||
|
final String defaultPackage = new String(new byte[] { 'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's' });
|
||||||
|
final String examplePackage = new String(new byte[] { 'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e' });
|
||||||
|
// We want to make sure nobody just copy & pastes the example and use the wrong package names
|
||||||
|
if (Metrics.class.getPackage().getName().equals(defaultPackage) || Metrics.class.getPackage().getName().equals(examplePackage)) {
|
||||||
|
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The version of this bStats class
|
||||||
|
public static final int B_STATS_VERSION = 1;
|
||||||
|
|
||||||
|
// The url to which the data is sent
|
||||||
|
private static final String URL = "https://bStats.org/submitData/bukkit";
|
||||||
|
|
||||||
|
// Should failed requests be logged?
|
||||||
|
private static boolean logFailedRequests;
|
||||||
|
|
||||||
|
// The uuid of the server
|
||||||
|
private static String serverUUID;
|
||||||
|
|
||||||
|
// A list with all custom charts
|
||||||
|
private final List<CustomChart> charts = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*/
|
||||||
|
public Metrics() {
|
||||||
|
|
||||||
|
// Get the config file
|
||||||
|
File configFile = new File(new File("plugins", "bStats"), "config.yml");
|
||||||
|
FileConfiguration config = new FileConfiguration(configFile);
|
||||||
|
|
||||||
|
// Check if the config file exists
|
||||||
|
if (config.get("serverUuid", String.class) == null) {
|
||||||
|
|
||||||
|
// Add default values
|
||||||
|
config.set("enabled", true);
|
||||||
|
// Every server gets it's unique random id.
|
||||||
|
config.set("serverUuid", UUID.randomUUID().toString());
|
||||||
|
// Should failed request be logged?
|
||||||
|
config.set("logFailedRequests", false);
|
||||||
|
|
||||||
|
// Inform the server owners about bStats
|
||||||
|
config.setHeader(
|
||||||
|
"bStats collects some data for plugin authors like how many servers are using their plugins.\n" +
|
||||||
|
"To honor their work, you should not disable it.\n" +
|
||||||
|
"This has nearly no effect on the server performance!\n" +
|
||||||
|
"Check out https://bStats.org/ to learn more :)"
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
config.saveConfig(configFile);
|
||||||
|
} catch (IOException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the data
|
||||||
|
serverUUID = config.get("serverUuid", String.class);
|
||||||
|
logFailedRequests = config.get("logFailedRequests", Boolean.class);
|
||||||
|
if (config.get("enabled", Boolean.class)) {
|
||||||
|
startSubmitting();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a custom chart.
|
||||||
|
*
|
||||||
|
* @param chart The chart to add.
|
||||||
|
*/
|
||||||
|
public void addCustomChart(CustomChart chart) {
|
||||||
|
if (chart == null) {
|
||||||
|
throw new IllegalArgumentException("Chart cannot be null!");
|
||||||
|
}
|
||||||
|
charts.add(chart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the Scheduler which submits our data every 30 minutes.
|
||||||
|
*/
|
||||||
|
private void startSubmitting() {
|
||||||
|
final Timer timer = new Timer(true);
|
||||||
|
timer.scheduleAtFixedRate(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
submitData();
|
||||||
|
}
|
||||||
|
}, 1000*60*5, 1000*60*30);
|
||||||
|
// Submit the data every 30 minutes, first time after 5 minutes to give other plugins enough time to start
|
||||||
|
// WARNING: Changing the frequency has no effect but your plugin WILL be blocked/deleted!
|
||||||
|
// WARNING: Just don't do it!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the plugin specific data.
|
||||||
|
*
|
||||||
|
* @return The plugin specific data.
|
||||||
|
*/
|
||||||
|
public JSONObject getPluginData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
|
||||||
|
String pluginName = "Limbo";
|
||||||
|
String pluginVersion = new BufferedReader(new InputStreamReader(Limbo.class.getClassLoader().getResourceAsStream("META-INF/MANIFEST.MF"))).lines().filter(each -> each.startsWith("Limbo-Version:")).findFirst().orElse("Limbo-Version: unknown").substring(14).trim();
|
||||||
|
|
||||||
|
data.put("pluginName", pluginName); // Append the name of the plugin
|
||||||
|
data.put("pluginVersion", pluginVersion); // Append the version of the plugin
|
||||||
|
JSONArray customCharts = new JSONArray();
|
||||||
|
for (CustomChart customChart : charts) {
|
||||||
|
// Add the data of the custom charts
|
||||||
|
JSONObject chart = customChart.getRequestJsonObject();
|
||||||
|
if (chart == null) { // If the chart is null, we skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
customCharts.add(chart);
|
||||||
|
}
|
||||||
|
data.put("customCharts", customCharts);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the server specific data.
|
||||||
|
*
|
||||||
|
* @return The server specific data.
|
||||||
|
*/
|
||||||
|
private JSONObject getServerData() {
|
||||||
|
// Minecraft specific data
|
||||||
|
int playerAmount = Limbo.getInstance().getPlayers().size();
|
||||||
|
int onlineMode = 0;
|
||||||
|
String limboVersion = Limbo.getInstance().serverImplementationVersion;
|
||||||
|
limboVersion = limboVersion.substring(limboVersion.indexOf("MC: ") + 4, limboVersion.length() - 1);
|
||||||
|
|
||||||
|
// OS/Java specific data
|
||||||
|
String javaVersion = System.getProperty("java.version");
|
||||||
|
String osName = System.getProperty("os.name");
|
||||||
|
String osArch = System.getProperty("os.arch");
|
||||||
|
String osVersion = System.getProperty("os.version");
|
||||||
|
int coreCount = Runtime.getRuntime().availableProcessors();
|
||||||
|
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
|
||||||
|
data.put("serverUUID", serverUUID);
|
||||||
|
|
||||||
|
data.put("playerAmount", playerAmount);
|
||||||
|
data.put("onlineMode", onlineMode);
|
||||||
|
data.put("limboVersion", limboVersion);
|
||||||
|
|
||||||
|
data.put("javaVersion", javaVersion);
|
||||||
|
data.put("osName", osName);
|
||||||
|
data.put("osArch", osArch);
|
||||||
|
data.put("osVersion", osVersion);
|
||||||
|
data.put("coreCount", coreCount);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects the data and sends it afterwards.
|
||||||
|
*/
|
||||||
|
private void submitData() {
|
||||||
|
final JSONObject data = getServerData();
|
||||||
|
|
||||||
|
JSONArray pluginData = new JSONArray();
|
||||||
|
pluginData.add(this.getPluginData());
|
||||||
|
data.put("plugins", pluginData);
|
||||||
|
|
||||||
|
// Create a new thread for the connection to the bStats server
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
// Send the data
|
||||||
|
sendData(data);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Something went wrong! :(
|
||||||
|
if (logFailedRequests) {
|
||||||
|
System.err.println("Could not submit stats for Limbo " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, "Limbo Metrics Submission Thread").start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the data to the bStats server.
|
||||||
|
*
|
||||||
|
* @param data The data to send.
|
||||||
|
* @throws Exception If the request failed.
|
||||||
|
*/
|
||||||
|
private static void sendData(JSONObject data) throws Exception {
|
||||||
|
if (data == null) {
|
||||||
|
throw new IllegalArgumentException("Data cannot be null!");
|
||||||
|
}
|
||||||
|
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
|
||||||
|
|
||||||
|
// Compress the data to save bandwidth
|
||||||
|
byte[] compressedData = compress(data.toString());
|
||||||
|
|
||||||
|
// Add headers
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.addRequestProperty("Accept", "application/json");
|
||||||
|
connection.addRequestProperty("Connection", "close");
|
||||||
|
connection.addRequestProperty("Content-Encoding", "gzip"); // We gzip our request
|
||||||
|
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||||
|
connection.setRequestProperty("Content-Type", "application/json"); // We send our data in JSON format
|
||||||
|
connection.setRequestProperty("User-Agent", "MC-Server/" + B_STATS_VERSION);
|
||||||
|
|
||||||
|
// Send data
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
|
||||||
|
outputStream.write(compressedData);
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
|
||||||
|
connection.getInputStream().close(); // We don't care about the response - Just send our data :)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gzips the given String.
|
||||||
|
*
|
||||||
|
* @param str The string to gzip.
|
||||||
|
* @return The gzipped String.
|
||||||
|
* @throws IOException If the compression failed.
|
||||||
|
*/
|
||||||
|
private static byte[] compress(final String str) throws IOException {
|
||||||
|
if (str == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
GZIPOutputStream gzip = new GZIPOutputStream(outputStream);
|
||||||
|
gzip.write(str.getBytes("UTF-8"));
|
||||||
|
gzip.close();
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom chart.
|
||||||
|
*/
|
||||||
|
public static abstract class CustomChart {
|
||||||
|
|
||||||
|
// The id of the chart
|
||||||
|
protected final String chartId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public CustomChart(String chartId) {
|
||||||
|
if (chartId == null || chartId.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("ChartId cannot be null or empty!");
|
||||||
|
}
|
||||||
|
this.chartId = chartId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JSONObject getRequestJsonObject() {
|
||||||
|
JSONObject chart = new JSONObject();
|
||||||
|
chart.put("chartId", chartId);
|
||||||
|
try {
|
||||||
|
JSONObject data = getChartData();
|
||||||
|
if (data == null) {
|
||||||
|
// If the data is null we don't send the chart.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
chart.put("data", data);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
if (logFailedRequests) {
|
||||||
|
System.err.println("Failed to get data for custom chart with id " + chartId + t);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract JSONObject getChartData();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom simple pie.
|
||||||
|
*/
|
||||||
|
public static abstract class SimplePie extends CustomChart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public SimplePie(String chartId) {
|
||||||
|
super(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the pie.
|
||||||
|
*
|
||||||
|
* @return The value of the pie.
|
||||||
|
*/
|
||||||
|
public abstract String getValue();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
String value = getValue();
|
||||||
|
if (value == null || value.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("value", value);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom advanced pie.
|
||||||
|
*/
|
||||||
|
public static abstract class AdvancedPie extends CustomChart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public AdvancedPie(String chartId) {
|
||||||
|
super(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the values of the pie.
|
||||||
|
*
|
||||||
|
* @param valueMap Just an empty map. The only reason it exists is to make your life easier.
|
||||||
|
* You don't have to create a map yourself!
|
||||||
|
* @return The values of the pie.
|
||||||
|
*/
|
||||||
|
public abstract HashMap<String, Integer> getValues(HashMap<String, Integer> valueMap);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
HashMap<String, Integer> map = getValues(new HashMap<String, Integer>());
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean allSkipped = true;
|
||||||
|
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue() == 0) {
|
||||||
|
continue; // Skip this invalid
|
||||||
|
}
|
||||||
|
allSkipped = false;
|
||||||
|
values.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
if (allSkipped) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom single line chart.
|
||||||
|
*/
|
||||||
|
public static abstract class SingleLineChart extends CustomChart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public SingleLineChart(String chartId) {
|
||||||
|
super(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the chart.
|
||||||
|
*
|
||||||
|
* @return The value of the chart.
|
||||||
|
*/
|
||||||
|
public abstract int getValue();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
int value = getValue();
|
||||||
|
if (value == 0) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("value", value);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom multi line chart.
|
||||||
|
*/
|
||||||
|
public static abstract class MultiLineChart extends CustomChart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public MultiLineChart(String chartId) {
|
||||||
|
super(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the values of the chart.
|
||||||
|
*
|
||||||
|
* @param valueMap Just an empty map. The only reason it exists is to make your life easier.
|
||||||
|
* You don't have to create a map yourself!
|
||||||
|
* @return The values of the chart.
|
||||||
|
*/
|
||||||
|
public abstract HashMap<String, Integer> getValues(HashMap<String, Integer> valueMap);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
HashMap<String, Integer> map = getValues(new HashMap<String, Integer>());
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean allSkipped = true;
|
||||||
|
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue() == 0) {
|
||||||
|
continue; // Skip this invalid
|
||||||
|
}
|
||||||
|
allSkipped = false;
|
||||||
|
values.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
if (allSkipped) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom simple bar chart.
|
||||||
|
*/
|
||||||
|
public static abstract class SimpleBarChart extends CustomChart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public SimpleBarChart(String chartId) {
|
||||||
|
super(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the chart.
|
||||||
|
*
|
||||||
|
* @param valueMap Just an empty map. The only reason it exists is to make your life easier.
|
||||||
|
* You don't have to create a map yourself!
|
||||||
|
* @return The value of the chart.
|
||||||
|
*/
|
||||||
|
public abstract HashMap<String, Integer> getValues(HashMap<String, Integer> valueMap);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
HashMap<String, Integer> map = getValues(new HashMap<String, Integer>());
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||||
|
JSONArray categoryValues = new JSONArray();
|
||||||
|
categoryValues.add(entry.getValue());
|
||||||
|
values.put(entry.getKey(), categoryValues);
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom advanced bar chart.
|
||||||
|
*/
|
||||||
|
public static abstract class AdvancedBarChart extends CustomChart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public AdvancedBarChart(String chartId) {
|
||||||
|
super(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the chart.
|
||||||
|
*
|
||||||
|
* @param valueMap Just an empty map. The only reason it exists is to make your life easier.
|
||||||
|
* You don't have to create a map yourself!
|
||||||
|
* @return The value of the chart.
|
||||||
|
*/
|
||||||
|
public abstract HashMap<String, int[]> getValues(HashMap<String, int[]> valueMap);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
HashMap<String, int[]> map = getValues(new HashMap<String, int[]>());
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean allSkipped = true;
|
||||||
|
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue().length == 0) {
|
||||||
|
continue; // Skip this invalid
|
||||||
|
}
|
||||||
|
allSkipped = false;
|
||||||
|
JSONArray categoryValues = new JSONArray();
|
||||||
|
for (int categoryValue : entry.getValue()) {
|
||||||
|
categoryValues.add(categoryValue);
|
||||||
|
}
|
||||||
|
values.put(entry.getKey(), categoryValues);
|
||||||
|
}
|
||||||
|
if (allSkipped) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom simple map chart.
|
||||||
|
*/
|
||||||
|
public static abstract class SimpleMapChart extends CustomChart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public SimpleMapChart(String chartId) {
|
||||||
|
super(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the chart.
|
||||||
|
*
|
||||||
|
* @return The value of the chart.
|
||||||
|
*/
|
||||||
|
public abstract Country getValue();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
Country value = getValue();
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("value", value.getCountryIsoTag());
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom advanced map chart.
|
||||||
|
*/
|
||||||
|
public static abstract class AdvancedMapChart extends CustomChart {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*
|
||||||
|
* @param chartId The id of the chart.
|
||||||
|
*/
|
||||||
|
public AdvancedMapChart(String chartId) {
|
||||||
|
super(chartId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the chart.
|
||||||
|
*
|
||||||
|
* @param valueMap Just an empty map. The only reason it exists is to make your life easier.
|
||||||
|
* You don't have to create a map yourself!
|
||||||
|
* @return The value of the chart.
|
||||||
|
*/
|
||||||
|
public abstract HashMap<Country, Integer> getValues(HashMap<Country, Integer> valueMap);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JSONObject getChartData() {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
JSONObject values = new JSONObject();
|
||||||
|
HashMap<Country, Integer> map = getValues(new HashMap<Country, Integer>());
|
||||||
|
if (map == null || map.isEmpty()) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
boolean allSkipped = true;
|
||||||
|
for (Map.Entry<Country, Integer> entry : map.entrySet()) {
|
||||||
|
if (entry.getValue() == 0) {
|
||||||
|
continue; // Skip this invalid
|
||||||
|
}
|
||||||
|
allSkipped = false;
|
||||||
|
values.put(entry.getKey().getCountryIsoTag(), entry.getValue());
|
||||||
|
}
|
||||||
|
if (allSkipped) {
|
||||||
|
// Null = skip the chart
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
data.put("values", values);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A enum which is used for custom maps.
|
||||||
|
*/
|
||||||
|
public enum Country {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bStats will use the country of the server.
|
||||||
|
*/
|
||||||
|
AUTO_DETECT("AUTO", "Auto Detected"),
|
||||||
|
|
||||||
|
ANDORRA("AD", "Andorra"),
|
||||||
|
UNITED_ARAB_EMIRATES("AE", "United Arab Emirates"),
|
||||||
|
AFGHANISTAN("AF", "Afghanistan"),
|
||||||
|
ANTIGUA_AND_BARBUDA("AG", "Antigua and Barbuda"),
|
||||||
|
ANGUILLA("AI", "Anguilla"),
|
||||||
|
ALBANIA("AL", "Albania"),
|
||||||
|
ARMENIA("AM", "Armenia"),
|
||||||
|
NETHERLANDS_ANTILLES("AN", "Netherlands Antilles"),
|
||||||
|
ANGOLA("AO", "Angola"),
|
||||||
|
ANTARCTICA("AQ", "Antarctica"),
|
||||||
|
ARGENTINA("AR", "Argentina"),
|
||||||
|
AMERICAN_SAMOA("AS", "American Samoa"),
|
||||||
|
AUSTRIA("AT", "Austria"),
|
||||||
|
AUSTRALIA("AU", "Australia"),
|
||||||
|
ARUBA("AW", "Aruba"),
|
||||||
|
ALAND_ISLANDS("AX", "Åland Islands"),
|
||||||
|
AZERBAIJAN("AZ", "Azerbaijan"),
|
||||||
|
BOSNIA_AND_HERZEGOVINA("BA", "Bosnia and Herzegovina"),
|
||||||
|
BARBADOS("BB", "Barbados"),
|
||||||
|
BANGLADESH("BD", "Bangladesh"),
|
||||||
|
BELGIUM("BE", "Belgium"),
|
||||||
|
BURKINA_FASO("BF", "Burkina Faso"),
|
||||||
|
BULGARIA("BG", "Bulgaria"),
|
||||||
|
BAHRAIN("BH", "Bahrain"),
|
||||||
|
BURUNDI("BI", "Burundi"),
|
||||||
|
BENIN("BJ", "Benin"),
|
||||||
|
SAINT_BARTHELEMY("BL", "Saint Barthélemy"),
|
||||||
|
BERMUDA("BM", "Bermuda"),
|
||||||
|
BRUNEI("BN", "Brunei"),
|
||||||
|
BOLIVIA("BO", "Bolivia"),
|
||||||
|
BONAIRE_SINT_EUSTATIUS_AND_SABA("BQ", "Bonaire, Sint Eustatius and Saba"),
|
||||||
|
BRAZIL("BR", "Brazil"),
|
||||||
|
BAHAMAS("BS", "Bahamas"),
|
||||||
|
BHUTAN("BT", "Bhutan"),
|
||||||
|
BOUVET_ISLAND("BV", "Bouvet Island"),
|
||||||
|
BOTSWANA("BW", "Botswana"),
|
||||||
|
BELARUS("BY", "Belarus"),
|
||||||
|
BELIZE("BZ", "Belize"),
|
||||||
|
CANADA("CA", "Canada"),
|
||||||
|
COCOS_ISLANDS("CC", "Cocos Islands"),
|
||||||
|
THE_DEMOCRATIC_REPUBLIC_OF_CONGO("CD", "The Democratic Republic Of Congo"),
|
||||||
|
CENTRAL_AFRICAN_REPUBLIC("CF", "Central African Republic"),
|
||||||
|
CONGO("CG", "Congo"),
|
||||||
|
SWITZERLAND("CH", "Switzerland"),
|
||||||
|
COTE_D_IVOIRE("CI", "Côte d'Ivoire"),
|
||||||
|
COOK_ISLANDS("CK", "Cook Islands"),
|
||||||
|
CHILE("CL", "Chile"),
|
||||||
|
CAMEROON("CM", "Cameroon"),
|
||||||
|
CHINA("CN", "China"),
|
||||||
|
COLOMBIA("CO", "Colombia"),
|
||||||
|
COSTA_RICA("CR", "Costa Rica"),
|
||||||
|
CUBA("CU", "Cuba"),
|
||||||
|
CAPE_VERDE("CV", "Cape Verde"),
|
||||||
|
CURACAO("CW", "Curaçao"),
|
||||||
|
CHRISTMAS_ISLAND("CX", "Christmas Island"),
|
||||||
|
CYPRUS("CY", "Cyprus"),
|
||||||
|
CZECH_REPUBLIC("CZ", "Czech Republic"),
|
||||||
|
GERMANY("DE", "Germany"),
|
||||||
|
DJIBOUTI("DJ", "Djibouti"),
|
||||||
|
DENMARK("DK", "Denmark"),
|
||||||
|
DOMINICA("DM", "Dominica"),
|
||||||
|
DOMINICAN_REPUBLIC("DO", "Dominican Republic"),
|
||||||
|
ALGERIA("DZ", "Algeria"),
|
||||||
|
ECUADOR("EC", "Ecuador"),
|
||||||
|
ESTONIA("EE", "Estonia"),
|
||||||
|
EGYPT("EG", "Egypt"),
|
||||||
|
WESTERN_SAHARA("EH", "Western Sahara"),
|
||||||
|
ERITREA("ER", "Eritrea"),
|
||||||
|
SPAIN("ES", "Spain"),
|
||||||
|
ETHIOPIA("ET", "Ethiopia"),
|
||||||
|
FINLAND("FI", "Finland"),
|
||||||
|
FIJI("FJ", "Fiji"),
|
||||||
|
FALKLAND_ISLANDS("FK", "Falkland Islands"),
|
||||||
|
MICRONESIA("FM", "Micronesia"),
|
||||||
|
FAROE_ISLANDS("FO", "Faroe Islands"),
|
||||||
|
FRANCE("FR", "France"),
|
||||||
|
GABON("GA", "Gabon"),
|
||||||
|
UNITED_KINGDOM("GB", "United Kingdom"),
|
||||||
|
GRENADA("GD", "Grenada"),
|
||||||
|
GEORGIA("GE", "Georgia"),
|
||||||
|
FRENCH_GUIANA("GF", "French Guiana"),
|
||||||
|
GUERNSEY("GG", "Guernsey"),
|
||||||
|
GHANA("GH", "Ghana"),
|
||||||
|
GIBRALTAR("GI", "Gibraltar"),
|
||||||
|
GREENLAND("GL", "Greenland"),
|
||||||
|
GAMBIA("GM", "Gambia"),
|
||||||
|
GUINEA("GN", "Guinea"),
|
||||||
|
GUADELOUPE("GP", "Guadeloupe"),
|
||||||
|
EQUATORIAL_GUINEA("GQ", "Equatorial Guinea"),
|
||||||
|
GREECE("GR", "Greece"),
|
||||||
|
SOUTH_GEORGIA_AND_THE_SOUTH_SANDWICH_ISLANDS("GS", "South Georgia And The South Sandwich Islands"),
|
||||||
|
GUATEMALA("GT", "Guatemala"),
|
||||||
|
GUAM("GU", "Guam"),
|
||||||
|
GUINEA_BISSAU("GW", "Guinea-Bissau"),
|
||||||
|
GUYANA("GY", "Guyana"),
|
||||||
|
HONG_KONG("HK", "Hong Kong"),
|
||||||
|
HEARD_ISLAND_AND_MCDONALD_ISLANDS("HM", "Heard Island And McDonald Islands"),
|
||||||
|
HONDURAS("HN", "Honduras"),
|
||||||
|
CROATIA("HR", "Croatia"),
|
||||||
|
HAITI("HT", "Haiti"),
|
||||||
|
HUNGARY("HU", "Hungary"),
|
||||||
|
INDONESIA("ID", "Indonesia"),
|
||||||
|
IRELAND("IE", "Ireland"),
|
||||||
|
ISRAEL("IL", "Israel"),
|
||||||
|
ISLE_OF_MAN("IM", "Isle Of Man"),
|
||||||
|
INDIA("IN", "India"),
|
||||||
|
BRITISH_INDIAN_OCEAN_TERRITORY("IO", "British Indian Ocean Territory"),
|
||||||
|
IRAQ("IQ", "Iraq"),
|
||||||
|
IRAN("IR", "Iran"),
|
||||||
|
ICELAND("IS", "Iceland"),
|
||||||
|
ITALY("IT", "Italy"),
|
||||||
|
JERSEY("JE", "Jersey"),
|
||||||
|
JAMAICA("JM", "Jamaica"),
|
||||||
|
JORDAN("JO", "Jordan"),
|
||||||
|
JAPAN("JP", "Japan"),
|
||||||
|
KENYA("KE", "Kenya"),
|
||||||
|
KYRGYZSTAN("KG", "Kyrgyzstan"),
|
||||||
|
CAMBODIA("KH", "Cambodia"),
|
||||||
|
KIRIBATI("KI", "Kiribati"),
|
||||||
|
COMOROS("KM", "Comoros"),
|
||||||
|
SAINT_KITTS_AND_NEVIS("KN", "Saint Kitts And Nevis"),
|
||||||
|
NORTH_KOREA("KP", "North Korea"),
|
||||||
|
SOUTH_KOREA("KR", "South Korea"),
|
||||||
|
KUWAIT("KW", "Kuwait"),
|
||||||
|
CAYMAN_ISLANDS("KY", "Cayman Islands"),
|
||||||
|
KAZAKHSTAN("KZ", "Kazakhstan"),
|
||||||
|
LAOS("LA", "Laos"),
|
||||||
|
LEBANON("LB", "Lebanon"),
|
||||||
|
SAINT_LUCIA("LC", "Saint Lucia"),
|
||||||
|
LIECHTENSTEIN("LI", "Liechtenstein"),
|
||||||
|
SRI_LANKA("LK", "Sri Lanka"),
|
||||||
|
LIBERIA("LR", "Liberia"),
|
||||||
|
LESOTHO("LS", "Lesotho"),
|
||||||
|
LITHUANIA("LT", "Lithuania"),
|
||||||
|
LUXEMBOURG("LU", "Luxembourg"),
|
||||||
|
LATVIA("LV", "Latvia"),
|
||||||
|
LIBYA("LY", "Libya"),
|
||||||
|
MOROCCO("MA", "Morocco"),
|
||||||
|
MONACO("MC", "Monaco"),
|
||||||
|
MOLDOVA("MD", "Moldova"),
|
||||||
|
MONTENEGRO("ME", "Montenegro"),
|
||||||
|
SAINT_MARTIN("MF", "Saint Martin"),
|
||||||
|
MADAGASCAR("MG", "Madagascar"),
|
||||||
|
MARSHALL_ISLANDS("MH", "Marshall Islands"),
|
||||||
|
MACEDONIA("MK", "Macedonia"),
|
||||||
|
MALI("ML", "Mali"),
|
||||||
|
MYANMAR("MM", "Myanmar"),
|
||||||
|
MONGOLIA("MN", "Mongolia"),
|
||||||
|
MACAO("MO", "Macao"),
|
||||||
|
NORTHERN_MARIANA_ISLANDS("MP", "Northern Mariana Islands"),
|
||||||
|
MARTINIQUE("MQ", "Martinique"),
|
||||||
|
MAURITANIA("MR", "Mauritania"),
|
||||||
|
MONTSERRAT("MS", "Montserrat"),
|
||||||
|
MALTA("MT", "Malta"),
|
||||||
|
MAURITIUS("MU", "Mauritius"),
|
||||||
|
MALDIVES("MV", "Maldives"),
|
||||||
|
MALAWI("MW", "Malawi"),
|
||||||
|
MEXICO("MX", "Mexico"),
|
||||||
|
MALAYSIA("MY", "Malaysia"),
|
||||||
|
MOZAMBIQUE("MZ", "Mozambique"),
|
||||||
|
NAMIBIA("NA", "Namibia"),
|
||||||
|
NEW_CALEDONIA("NC", "New Caledonia"),
|
||||||
|
NIGER("NE", "Niger"),
|
||||||
|
NORFOLK_ISLAND("NF", "Norfolk Island"),
|
||||||
|
NIGERIA("NG", "Nigeria"),
|
||||||
|
NICARAGUA("NI", "Nicaragua"),
|
||||||
|
NETHERLANDS("NL", "Netherlands"),
|
||||||
|
NORWAY("NO", "Norway"),
|
||||||
|
NEPAL("NP", "Nepal"),
|
||||||
|
NAURU("NR", "Nauru"),
|
||||||
|
NIUE("NU", "Niue"),
|
||||||
|
NEW_ZEALAND("NZ", "New Zealand"),
|
||||||
|
OMAN("OM", "Oman"),
|
||||||
|
PANAMA("PA", "Panama"),
|
||||||
|
PERU("PE", "Peru"),
|
||||||
|
FRENCH_POLYNESIA("PF", "French Polynesia"),
|
||||||
|
PAPUA_NEW_GUINEA("PG", "Papua New Guinea"),
|
||||||
|
PHILIPPINES("PH", "Philippines"),
|
||||||
|
PAKISTAN("PK", "Pakistan"),
|
||||||
|
POLAND("PL", "Poland"),
|
||||||
|
SAINT_PIERRE_AND_MIQUELON("PM", "Saint Pierre And Miquelon"),
|
||||||
|
PITCAIRN("PN", "Pitcairn"),
|
||||||
|
PUERTO_RICO("PR", "Puerto Rico"),
|
||||||
|
PALESTINE("PS", "Palestine"),
|
||||||
|
PORTUGAL("PT", "Portugal"),
|
||||||
|
PALAU("PW", "Palau"),
|
||||||
|
PARAGUAY("PY", "Paraguay"),
|
||||||
|
QATAR("QA", "Qatar"),
|
||||||
|
REUNION("RE", "Reunion"),
|
||||||
|
ROMANIA("RO", "Romania"),
|
||||||
|
SERBIA("RS", "Serbia"),
|
||||||
|
RUSSIA("RU", "Russia"),
|
||||||
|
RWANDA("RW", "Rwanda"),
|
||||||
|
SAUDI_ARABIA("SA", "Saudi Arabia"),
|
||||||
|
SOLOMON_ISLANDS("SB", "Solomon Islands"),
|
||||||
|
SEYCHELLES("SC", "Seychelles"),
|
||||||
|
SUDAN("SD", "Sudan"),
|
||||||
|
SWEDEN("SE", "Sweden"),
|
||||||
|
SINGAPORE("SG", "Singapore"),
|
||||||
|
SAINT_HELENA("SH", "Saint Helena"),
|
||||||
|
SLOVENIA("SI", "Slovenia"),
|
||||||
|
SVALBARD_AND_JAN_MAYEN("SJ", "Svalbard And Jan Mayen"),
|
||||||
|
SLOVAKIA("SK", "Slovakia"),
|
||||||
|
SIERRA_LEONE("SL", "Sierra Leone"),
|
||||||
|
SAN_MARINO("SM", "San Marino"),
|
||||||
|
SENEGAL("SN", "Senegal"),
|
||||||
|
SOMALIA("SO", "Somalia"),
|
||||||
|
SURINAME("SR", "Suriname"),
|
||||||
|
SOUTH_SUDAN("SS", "South Sudan"),
|
||||||
|
SAO_TOME_AND_PRINCIPE("ST", "Sao Tome And Principe"),
|
||||||
|
EL_SALVADOR("SV", "El Salvador"),
|
||||||
|
SINT_MAARTEN_DUTCH_PART("SX", "Sint Maarten (Dutch part)"),
|
||||||
|
SYRIA("SY", "Syria"),
|
||||||
|
SWAZILAND("SZ", "Swaziland"),
|
||||||
|
TURKS_AND_CAICOS_ISLANDS("TC", "Turks And Caicos Islands"),
|
||||||
|
CHAD("TD", "Chad"),
|
||||||
|
FRENCH_SOUTHERN_TERRITORIES("TF", "French Southern Territories"),
|
||||||
|
TOGO("TG", "Togo"),
|
||||||
|
THAILAND("TH", "Thailand"),
|
||||||
|
TAJIKISTAN("TJ", "Tajikistan"),
|
||||||
|
TOKELAU("TK", "Tokelau"),
|
||||||
|
TIMOR_LESTE("TL", "Timor-Leste"),
|
||||||
|
TURKMENISTAN("TM", "Turkmenistan"),
|
||||||
|
TUNISIA("TN", "Tunisia"),
|
||||||
|
TONGA("TO", "Tonga"),
|
||||||
|
TURKEY("TR", "Turkey"),
|
||||||
|
TRINIDAD_AND_TOBAGO("TT", "Trinidad and Tobago"),
|
||||||
|
TUVALU("TV", "Tuvalu"),
|
||||||
|
TAIWAN("TW", "Taiwan"),
|
||||||
|
TANZANIA("TZ", "Tanzania"),
|
||||||
|
UKRAINE("UA", "Ukraine"),
|
||||||
|
UGANDA("UG", "Uganda"),
|
||||||
|
UNITED_STATES_MINOR_OUTLYING_ISLANDS("UM", "United States Minor Outlying Islands"),
|
||||||
|
UNITED_STATES("US", "United States"),
|
||||||
|
URUGUAY("UY", "Uruguay"),
|
||||||
|
UZBEKISTAN("UZ", "Uzbekistan"),
|
||||||
|
VATICAN("VA", "Vatican"),
|
||||||
|
SAINT_VINCENT_AND_THE_GRENADINES("VC", "Saint Vincent And The Grenadines"),
|
||||||
|
VENEZUELA("VE", "Venezuela"),
|
||||||
|
BRITISH_VIRGIN_ISLANDS("VG", "British Virgin Islands"),
|
||||||
|
U_S__VIRGIN_ISLANDS("VI", "U.S. Virgin Islands"),
|
||||||
|
VIETNAM("VN", "Vietnam"),
|
||||||
|
VANUATU("VU", "Vanuatu"),
|
||||||
|
WALLIS_AND_FUTUNA("WF", "Wallis And Futuna"),
|
||||||
|
SAMOA("WS", "Samoa"),
|
||||||
|
YEMEN("YE", "Yemen"),
|
||||||
|
MAYOTTE("YT", "Mayotte"),
|
||||||
|
SOUTH_AFRICA("ZA", "South Africa"),
|
||||||
|
ZAMBIA("ZM", "Zambia"),
|
||||||
|
ZIMBABWE("ZW", "Zimbabwe");
|
||||||
|
|
||||||
|
private String isoTag;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
Country(String isoTag, String name) {
|
||||||
|
this.isoTag = isoTag;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the country.
|
||||||
|
*
|
||||||
|
* @return The name of the country.
|
||||||
|
*/
|
||||||
|
public String getCountryName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the iso tag of the country.
|
||||||
|
*
|
||||||
|
* @return The iso tag of the country.
|
||||||
|
*/
|
||||||
|
public String getCountryIsoTag() {
|
||||||
|
return isoTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a country by it's iso tag.
|
||||||
|
*
|
||||||
|
* @param isoTag The iso tag of the county.
|
||||||
|
* @return The country with the given iso tag or <code>null</code> if unknown.
|
||||||
|
*/
|
||||||
|
public static Country byIsoTag(String isoTag) {
|
||||||
|
for (Country country : Country.values()) {
|
||||||
|
if (country.getCountryIsoTag().equals(isoTag)) {
|
||||||
|
return country;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a country by a locale.
|
||||||
|
*
|
||||||
|
* @param locale The locale.
|
||||||
|
* @return The country from the giben locale or <code>null</code> if unknown country or
|
||||||
|
* if the locale does not contain a country.
|
||||||
|
*/
|
||||||
|
public static Country byLocale(Locale locale) {
|
||||||
|
return byIsoTag(locale.getCountry());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,36 +1,17 @@
|
||||||
/*
|
package com.loohp.limbo.Permissions;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.permissions;
|
|
||||||
|
|
||||||
import com.loohp.limbo.Console;
|
|
||||||
import com.loohp.limbo.commands.CommandSender;
|
|
||||||
import com.loohp.limbo.file.FileConfiguration;
|
|
||||||
import com.loohp.limbo.player.Player;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Console;
|
||||||
|
import com.loohp.limbo.Commands.CommandSender;
|
||||||
|
import com.loohp.limbo.File.FileConfiguration;
|
||||||
|
import com.loohp.limbo.Player.Player;
|
||||||
|
|
||||||
public class PermissionsManager {
|
public class PermissionsManager {
|
||||||
|
|
||||||
private Map<String, List<String>> users;
|
private Map<String, List<String>> users;
|
||||||
|
|
@ -42,7 +23,7 @@ public class PermissionsManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void loadDefaultPermissionFile(File file) throws IOException {
|
public void loadDefaultPermissionFile(File file) throws FileNotFoundException {
|
||||||
FileConfiguration config = new FileConfiguration(file);
|
FileConfiguration config = new FileConfiguration(file);
|
||||||
permissions.put("default", new ArrayList<>());
|
permissions.put("default", new ArrayList<>());
|
||||||
try {
|
try {
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
package com.loohp.limbo.Player;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
import com.loohp.limbo.Commands.CommandSender;
|
||||||
|
import com.loohp.limbo.Events.PlayerChatEvent;
|
||||||
|
import com.loohp.limbo.Location.Location;
|
||||||
|
import com.loohp.limbo.Server.ClientConnection;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutChat;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutGameState;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPositionAndLook;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutRespawn;
|
||||||
|
import com.loohp.limbo.Utils.GameMode;
|
||||||
|
import com.loohp.limbo.World.DimensionRegistry;
|
||||||
|
import com.loohp.limbo.World.World;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
|
||||||
|
public class Player implements CommandSender {
|
||||||
|
|
||||||
|
public final ClientConnection clientConnection;
|
||||||
|
|
||||||
|
private final String username;
|
||||||
|
private final UUID uuid;
|
||||||
|
private GameMode gamemode;
|
||||||
|
|
||||||
|
private int entityId;
|
||||||
|
|
||||||
|
private Location location;
|
||||||
|
|
||||||
|
public Player(ClientConnection clientConnection, String username, UUID uuid, int entityId, Location location) {
|
||||||
|
this.clientConnection = clientConnection;
|
||||||
|
this.username = username;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.entityId = entityId;
|
||||||
|
this.location = location.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameMode getGamemode() {
|
||||||
|
return gamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGamemode(GameMode gamemode) {
|
||||||
|
if (!this.gamemode.equals(gamemode)) {
|
||||||
|
try {
|
||||||
|
PacketPlayOutGameState state = new PacketPlayOutGameState(3, gamemode.getId());
|
||||||
|
clientConnection.sendPacket(state);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.gamemode = gamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void setGamemodeSilent(GameMode gamemode) {
|
||||||
|
this.gamemode = gamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public World getWorld() {
|
||||||
|
return location.clone().getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void setEntityId(int entityId) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEntityId() {
|
||||||
|
return entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getLocation() {
|
||||||
|
return location.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(Location location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUUID() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(String permission) {
|
||||||
|
return Limbo.getInstance().getPermissionsManager().hasPermission(this, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(String message) {
|
||||||
|
sendMessage(TextComponent.fromLegacyText(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(BaseComponent component) {
|
||||||
|
sendMessage(new BaseComponent[] { component });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void teleport(Location location) {
|
||||||
|
try {
|
||||||
|
if (!this.location.getWorld().equals(location.getWorld())) {
|
||||||
|
PacketPlayOutRespawn respawn = new PacketPlayOutRespawn(location.getWorld(), DimensionRegistry.getCodec(), 0, gamemode, false, false, true);
|
||||||
|
clientConnection.sendPacket(respawn);
|
||||||
|
}
|
||||||
|
PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch(), 1);
|
||||||
|
clientConnection.sendPacket(positionLook);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(BaseComponent[] component) {
|
||||||
|
try {
|
||||||
|
PacketPlayOutChat chat = new PacketPlayOutChat(ComponentSerializer.toString(component), 0, new UUID(0, 0));
|
||||||
|
clientConnection.sendPacket(chat);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect() {
|
||||||
|
disconnect("Disconnected!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect(String reason) {
|
||||||
|
disconnect(TextComponent.fromLegacyText(reason));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect(BaseComponent reason) {
|
||||||
|
disconnect(new BaseComponent[] {reason});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect(BaseComponent[] reason) {
|
||||||
|
clientConnection.disconnect(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void chat(String message) {
|
||||||
|
String prefix = "<" + username + "> ";
|
||||||
|
PlayerChatEvent event = (PlayerChatEvent) Limbo.getInstance().getEventsManager().callEvent(new PlayerChatEvent(this, prefix, message, false));
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
String chat = event.getPrefix() + event.getMessage();
|
||||||
|
Limbo.getInstance().getConsole().sendMessage(chat);
|
||||||
|
for (Player each : Limbo.getInstance().getPlayers()) {
|
||||||
|
each.sendMessage(chat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.loohp.limbo.Plugins;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
import com.loohp.limbo.File.FileConfiguration;
|
||||||
|
|
||||||
|
public class LimboPlugin {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private File dataFolder;
|
||||||
|
private PluginInfo info;
|
||||||
|
|
||||||
|
public final void setInfo(FileConfiguration file) {
|
||||||
|
info = new PluginInfo(file);
|
||||||
|
name = info.getName();
|
||||||
|
dataFolder = new File(Limbo.getInstance().getPluginFolder(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onLoad() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onEnable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onDisable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getDataFolder() {
|
||||||
|
return new File(dataFolder.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginInfo getInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Limbo getServer() {
|
||||||
|
return Limbo.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.loohp.limbo.Plugins;
|
||||||
|
|
||||||
|
import com.loohp.limbo.File.FileConfiguration;
|
||||||
|
|
||||||
|
public class PluginInfo {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private String author;
|
||||||
|
private String version;
|
||||||
|
private String main;
|
||||||
|
|
||||||
|
public PluginInfo(FileConfiguration file) {
|
||||||
|
name = file.get("name", String.class);
|
||||||
|
description = file.get("description", String.class) == null ? "" : file.get("description", String.class);
|
||||||
|
author = file.get("author", String.class);
|
||||||
|
version = file.get("version", String.class);
|
||||||
|
main = file.get("main", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMainClass() {
|
||||||
|
return main;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
package com.loohp.limbo.Plugins;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
import com.loohp.limbo.Commands.CommandExecutor;
|
||||||
|
import com.loohp.limbo.Commands.CommandSender;
|
||||||
|
import com.loohp.limbo.Commands.TabCompletor;
|
||||||
|
import com.loohp.limbo.File.FileConfiguration;
|
||||||
|
|
||||||
|
public class PluginManager {
|
||||||
|
|
||||||
|
private Map<String, LimboPlugin> plugins;
|
||||||
|
private List<Executor> executors;
|
||||||
|
private File pluginFolder;
|
||||||
|
|
||||||
|
public PluginManager(File pluginFolder) {
|
||||||
|
this.pluginFolder = pluginFolder;
|
||||||
|
this.executors = new ArrayList<>();
|
||||||
|
|
||||||
|
this.plugins = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (File file : pluginFolder.listFiles()) {
|
||||||
|
if (file.isFile() && file.getName().endsWith(".jar")) {
|
||||||
|
boolean found = false;
|
||||||
|
try (ZipInputStream zip = new ZipInputStream(new FileInputStream(file))) {
|
||||||
|
while (true) {
|
||||||
|
ZipEntry entry = zip.getNextEntry();
|
||||||
|
if (entry == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String name = entry.getName();
|
||||||
|
if (name.endsWith("plugin.yml") || name.endsWith("limbo.yml")) {
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
FileConfiguration pluginYaml = new FileConfiguration(zip);
|
||||||
|
String main = pluginYaml.get("main", String.class);
|
||||||
|
String pluginName = pluginYaml.get("name", String.class);
|
||||||
|
|
||||||
|
if (plugins.containsKey(pluginName)) {
|
||||||
|
System.err.println("Ambiguous plugin name in " + file.getName() + " with the plugin \"" + plugins.get(pluginName).getClass().getName() + "\"");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
URLClassLoader url = new URLClassLoader(new URL[] {file.toURI().toURL()});
|
||||||
|
Class<?> plugin = url.loadClass(main);
|
||||||
|
LimboPlugin clazz = (LimboPlugin) plugin.getDeclaredConstructor().newInstance();
|
||||||
|
clazz.setInfo(pluginYaml);
|
||||||
|
plugins.put(clazz.getName(), clazz);
|
||||||
|
clazz.onLoad();
|
||||||
|
System.out.println("Loading plugin " + file.getName() + " " + clazz.getInfo().getVersion() + " by " + clazz.getInfo().getAuthor());
|
||||||
|
url.close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Unable to load plugin \"" + file.getName() + "\"");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
System.err.println("Jar file " + file.getName() + " has no plugin.yml!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<LimboPlugin> getPlugins() {
|
||||||
|
return new ArrayList<>(plugins.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public LimboPlugin getPlugin(String name) {
|
||||||
|
return plugins.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fireExecutors(CommandSender sender, String[] args) throws Exception {
|
||||||
|
Limbo.getInstance().getConsole().sendMessage(sender.getName() + " executed server command: /" + String.join(" ", args));
|
||||||
|
for (Executor entry : executors) {
|
||||||
|
try {
|
||||||
|
entry.executor.execute(sender, args);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error while passing command \"" + args[0] + "\" to the plugin \"" + entry.plugin.getName() + "\"");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getTabOptions(CommandSender sender, String[] args) {
|
||||||
|
List<String> options = new ArrayList<>();
|
||||||
|
for (Executor entry : executors) {
|
||||||
|
if (entry.tab.isPresent()) {
|
||||||
|
try {
|
||||||
|
options.addAll(entry.tab.get().tabComplete(sender, args));
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error while passing tab completion to the plugin \"" + entry.plugin.getName() + "\"");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerCommands(LimboPlugin plugin, CommandExecutor executor) {
|
||||||
|
executors.add(new Executor(plugin, executor));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregsiterAllCommands(LimboPlugin plugin) {
|
||||||
|
executors.removeIf(each -> each.plugin.equals(plugin));
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getPluginFolder() {
|
||||||
|
return new File(pluginFolder.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class Executor {
|
||||||
|
public LimboPlugin plugin;
|
||||||
|
public CommandExecutor executor;
|
||||||
|
public Optional<TabCompletor> tab;
|
||||||
|
|
||||||
|
public Executor(LimboPlugin plugin, CommandExecutor executor) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.executor = executor;
|
||||||
|
if (executor instanceof TabCompletor) {
|
||||||
|
this.tab = Optional.of((TabCompletor) executor);
|
||||||
|
} else {
|
||||||
|
this.tab = Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,426 @@
|
||||||
|
package com.loohp.limbo.Server;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.loohp.limbo.DeclareCommands;
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
import com.loohp.limbo.Events.PlayerJoinEvent;
|
||||||
|
import com.loohp.limbo.Events.PlayerLoginEvent;
|
||||||
|
import com.loohp.limbo.Events.PlayerQuitEvent;
|
||||||
|
import com.loohp.limbo.Events.StatusPingEvent;
|
||||||
|
import com.loohp.limbo.File.ServerProperties;
|
||||||
|
import com.loohp.limbo.Location.Location;
|
||||||
|
import com.loohp.limbo.Player.Player;
|
||||||
|
import com.loohp.limbo.Server.Packets.Packet;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketHandshakingIn;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketLoginInLoginStart;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketLoginOutDisconnect;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketLoginOutLoginSuccess;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketOut;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayInChat;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayInKeepAlive;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayInPosition;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayInPositionAndLook;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayInRotation;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayInTabComplete;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutDeclareCommands;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutDisconnect;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutLogin;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutMapChunk;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerAbilities;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerAbilities.PlayerAbilityFlags;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoAction;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoData;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoData.PlayerInfoDataAddPlayer.PlayerSkinProperty;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPositionAndLook;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutShowPlayerSkins;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutSpawnPosition;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutTabComplete;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutTabComplete.TabCompleteMatches;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutUpdateViewPosition;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketStatusInPing;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketStatusInRequest;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketStatusOutPong;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketStatusOutResponse;
|
||||||
|
import com.loohp.limbo.Utils.CustomStringUtils;
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.MojangAPIUtils;
|
||||||
|
import com.loohp.limbo.Utils.MojangAPIUtils.SkinResponse;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
import com.loohp.limbo.World.BlockPosition;
|
||||||
|
import com.loohp.limbo.World.DimensionRegistry;
|
||||||
|
import com.loohp.limbo.World.World;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import net.querz.mca.Chunk;
|
||||||
|
|
||||||
|
public class ClientConnection extends Thread {
|
||||||
|
|
||||||
|
public enum ClientState {
|
||||||
|
LEGACY,
|
||||||
|
HANDSHAKE,
|
||||||
|
STATUS,
|
||||||
|
LOGIN,
|
||||||
|
PLAY,
|
||||||
|
DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Socket client_socket;
|
||||||
|
private boolean running;
|
||||||
|
private ClientState state;
|
||||||
|
|
||||||
|
private Player player;
|
||||||
|
private long lastKeepAlivePayLoad;
|
||||||
|
|
||||||
|
protected DataOutputStream output;
|
||||||
|
protected DataInputStream input;
|
||||||
|
|
||||||
|
private InetAddress inetAddress;
|
||||||
|
|
||||||
|
public ClientConnection(Socket client_socket) {
|
||||||
|
this.client_socket = client_socket;
|
||||||
|
this.inetAddress = client_socket.getInetAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
public InetAddress getInetAddress() {
|
||||||
|
return inetAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastKeepAlivePayLoad() {
|
||||||
|
return lastKeepAlivePayLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastKeepAlivePayLoad(long payLoad) {
|
||||||
|
this.lastKeepAlivePayLoad = payLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientState getClientState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Socket getSocket() {
|
||||||
|
return client_socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendPacket(PacketOut packet) throws IOException {
|
||||||
|
byte[] packetByte = packet.serializePacket();
|
||||||
|
DataTypeIO.writeVarInt(output, packetByte.length);
|
||||||
|
output.write(packetByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnect(BaseComponent[] reason) {
|
||||||
|
try {
|
||||||
|
PacketPlayOutDisconnect packet = new PacketPlayOutDisconnect(ComponentSerializer.toString(reason));
|
||||||
|
byte[] packetByte = packet.serializePacket();
|
||||||
|
DataTypeIO.writeVarInt(output, packetByte.length);
|
||||||
|
output.write(packetByte);
|
||||||
|
output.flush();
|
||||||
|
} catch (IOException e) {}
|
||||||
|
try {
|
||||||
|
client_socket.close();
|
||||||
|
} catch (IOException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disconnectDuringLogin(BaseComponent[] reason) {
|
||||||
|
try {
|
||||||
|
PacketLoginOutDisconnect packet = new PacketLoginOutDisconnect(ComponentSerializer.toString(reason));
|
||||||
|
byte[] packetByte = packet.serializePacket();
|
||||||
|
DataTypeIO.writeVarInt(output, packetByte.length);
|
||||||
|
output.write(packetByte);
|
||||||
|
output.flush();
|
||||||
|
} catch (IOException e) {}
|
||||||
|
try {
|
||||||
|
client_socket.close();
|
||||||
|
} catch (IOException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
running = true;
|
||||||
|
state = ClientState.HANDSHAKE;
|
||||||
|
try {
|
||||||
|
client_socket.setKeepAlive(true);
|
||||||
|
input = new DataInputStream(client_socket.getInputStream());
|
||||||
|
output = new DataOutputStream(client_socket.getOutputStream());
|
||||||
|
int handShakeSize = DataTypeIO.readVarInt(input);
|
||||||
|
|
||||||
|
//legacy ping
|
||||||
|
if (handShakeSize == 0xFE) {
|
||||||
|
state = ClientState.LEGACY;
|
||||||
|
output.writeByte(255);
|
||||||
|
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort();
|
||||||
|
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Legacy Status has pinged");
|
||||||
|
ServerProperties p = Limbo.getInstance().getServerProperties();
|
||||||
|
StatusPingEvent event = Limbo.getInstance().getEventsManager().callEvent(new StatusPingEvent(this, p.getVersionString(), p.getProtocol(), ComponentSerializer.parse(p.getMotdJson()), p.getMaxPlayers(), Limbo.getInstance().getPlayers().size(), p.getFavicon().orElse(null)));
|
||||||
|
String response = Limbo.getInstance().buildLegacyPingResponse(event.getVersion(), event.getMotd(), event.getMaxPlayers(), event.getPlayersOnline());
|
||||||
|
byte[] bytes = response.getBytes(StandardCharsets.UTF_16BE);
|
||||||
|
output.writeShort(response.length());
|
||||||
|
output.write(bytes);
|
||||||
|
|
||||||
|
client_socket.close();
|
||||||
|
state = ClientState.DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
int handShakeId = DataTypeIO.readVarInt(input);
|
||||||
|
|
||||||
|
PacketHandshakingIn handshake = new PacketHandshakingIn(input);
|
||||||
|
|
||||||
|
boolean isBungeecord = Limbo.getInstance().getServerProperties().isBungeecord();
|
||||||
|
String bungeeForwarding = handshake.getServerAddress();
|
||||||
|
UUID bungeeUUID = null;
|
||||||
|
SkinResponse bungeeSkin = null;
|
||||||
|
|
||||||
|
switch (handshake.getHandshakeType()) {
|
||||||
|
case STATUS:
|
||||||
|
state = ClientState.STATUS;
|
||||||
|
while (client_socket.isConnected()) {
|
||||||
|
DataTypeIO.readVarInt(input);
|
||||||
|
int packetId = DataTypeIO.readVarInt(input);
|
||||||
|
Class<? extends Packet> packetType = Packet.getStatusIn().get(packetId);
|
||||||
|
if (packetType == null) {
|
||||||
|
//do nothing
|
||||||
|
} else if (packetType.equals(PacketStatusInRequest.class)) {
|
||||||
|
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort();
|
||||||
|
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Handshake Status has pinged");
|
||||||
|
ServerProperties p = Limbo.getInstance().getServerProperties();
|
||||||
|
StatusPingEvent event = Limbo.getInstance().getEventsManager().callEvent(new StatusPingEvent(this, p.getVersionString(), p.getProtocol(), ComponentSerializer.parse(p.getMotdJson()), p.getMaxPlayers(), Limbo.getInstance().getPlayers().size(), p.getFavicon().orElse(null)));
|
||||||
|
PacketStatusOutResponse packet = new PacketStatusOutResponse(Limbo.getInstance().buildServerListResponseJson(event.getVersion(), event.getProtocol(), event.getMotd(), event.getMaxPlayers(), event.getPlayersOnline(), event.getFavicon()));
|
||||||
|
sendPacket(packet);
|
||||||
|
} else if (packetType.equals(PacketStatusInPing.class)) {
|
||||||
|
PacketStatusInPing ping = new PacketStatusInPing(input);
|
||||||
|
PacketStatusOutPong packet = new PacketStatusOutPong(ping.getPayload());
|
||||||
|
sendPacket(packet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOGIN:
|
||||||
|
state = ClientState.LOGIN;
|
||||||
|
|
||||||
|
if (isBungeecord) {
|
||||||
|
try {
|
||||||
|
String[] data = bungeeForwarding.split("\\x00");
|
||||||
|
//String host = data[0];
|
||||||
|
String ip = data[1];
|
||||||
|
|
||||||
|
bungeeUUID = UUID.fromString(data[2].replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"));
|
||||||
|
inetAddress = InetAddress.getByName(ip);
|
||||||
|
|
||||||
|
String skinJson = data[3];
|
||||||
|
|
||||||
|
String skin = skinJson.split("\"value\":\"")[1].split("\"")[0];
|
||||||
|
String signature = skinJson.split("\"signature\":\"")[1].split("\"")[0];
|
||||||
|
bungeeSkin = new SkinResponse(skin, signature);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Limbo.getInstance().getConsole().sendMessage("If you wish to use bungeecord's IP forwarding, please enable that in your bungeecord config.yml as well!");
|
||||||
|
disconnectDuringLogin(new BaseComponent[] {new TextComponent(ChatColor.RED + "Please connect from the proxy!")});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (client_socket.isConnected()) {
|
||||||
|
int size = DataTypeIO.readVarInt(input);
|
||||||
|
int packetId = DataTypeIO.readVarInt(input);
|
||||||
|
Class<? extends Packet> packetType = Packet.getLoginIn().get(packetId);
|
||||||
|
|
||||||
|
if (packetType == null) {
|
||||||
|
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
|
||||||
|
} else if (packetType.equals(PacketLoginInLoginStart.class)) {
|
||||||
|
PacketLoginInLoginStart start = new PacketLoginInLoginStart(input);
|
||||||
|
String username = start.getUsername();
|
||||||
|
UUID uuid = isBungeecord ? bungeeUUID : UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
PacketLoginOutLoginSuccess success = new PacketLoginOutLoginSuccess(uuid, username);
|
||||||
|
sendPacket(success);
|
||||||
|
|
||||||
|
state = ClientState.PLAY;
|
||||||
|
|
||||||
|
player = new Player(this, username, uuid, Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn());
|
||||||
|
Limbo.getInstance().addPlayer(player);
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerLoginEvent event = Limbo.getInstance().getEventsManager().callEvent(new PlayerLoginEvent(this, false));
|
||||||
|
if (event.isCancelled()) {
|
||||||
|
disconnectDuringLogin(event.getCancelReason());
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == ClientState.PLAY) {
|
||||||
|
|
||||||
|
TimeUnit.MILLISECONDS.sleep(500);
|
||||||
|
|
||||||
|
ServerProperties p = Limbo.getInstance().getServerProperties();
|
||||||
|
PacketPlayOutLogin join = new PacketPlayOutLogin(player.getEntityId(), false, p.getDefaultGamemode(), Limbo.getInstance().getWorlds().stream().map(each -> new NamespacedKey(each.getName()).toString()).collect(Collectors.toList()).toArray(new String[Limbo.getInstance().getWorlds().size()]), DimensionRegistry.getCodec(), p.getWorldSpawn().getWorld(), 0, (byte) p.getMaxPlayers(), 8, p.isReducedDebugInfo(), true, false, true);
|
||||||
|
sendPacket(join);
|
||||||
|
player.setGamemodeSilent(p.getDefaultGamemode());
|
||||||
|
|
||||||
|
Location s = p.getWorldSpawn();
|
||||||
|
|
||||||
|
//PacketPlayOutKeepAlive alive = new PacketPlayOutKeepAlive((long) (Math.random() * Long.MAX_VALUE));
|
||||||
|
|
||||||
|
World world = s.getWorld();
|
||||||
|
|
||||||
|
for (int x = 0; x < world.getChunks().length; x++) {
|
||||||
|
for (int z = 0; z < world.getChunks()[x].length; z++) {
|
||||||
|
Chunk chunk = world.getChunks()[x][z];
|
||||||
|
if (chunk != null) {
|
||||||
|
PacketPlayOutMapChunk chunkdata = new PacketPlayOutMapChunk(x, z, chunk, world.getEnvironment());
|
||||||
|
sendPacket(chunkdata);
|
||||||
|
//System.out.println(x + ", " + z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SkinResponse skinresponce = isBungeecord ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName());
|
||||||
|
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null;
|
||||||
|
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, player.getUUID(), new PlayerInfoData.PlayerInfoDataAddPlayer(player.getName(), Optional.ofNullable(skin), p.getDefaultGamemode(), 0, false, Optional.empty()));
|
||||||
|
sendPacket(info);
|
||||||
|
/*
|
||||||
|
for (ClientConnection client : Limbo.getInstance().getServerConnection().getClients()) {
|
||||||
|
DataOutputStream other = new DataOutputStream(client.getSocket().getOutputStream());
|
||||||
|
DataTypeIO.writeVarInt(other, packetByte.length);
|
||||||
|
other.write(packetByte);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
PacketPlayOutShowPlayerSkins show = new PacketPlayOutShowPlayerSkins(player.getEntityId());
|
||||||
|
sendPacket(show);
|
||||||
|
|
||||||
|
PacketPlayOutPlayerAbilities abilities;
|
||||||
|
if (p.isAllowFlight()) {
|
||||||
|
abilities = new PacketPlayOutPlayerAbilities(0.05F, 0.1F, PlayerAbilityFlags.ALLOW_FLYING);
|
||||||
|
} else {
|
||||||
|
abilities = new PacketPlayOutPlayerAbilities(0.05F, 0.1F);
|
||||||
|
}
|
||||||
|
sendPacket(abilities);
|
||||||
|
|
||||||
|
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
|
||||||
|
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had connected to the Limbo server!");
|
||||||
|
|
||||||
|
PacketPlayOutDeclareCommands declare = DeclareCommands.getDeclareCommandsPacket(player);
|
||||||
|
if (declare != null) {
|
||||||
|
sendPacket(declare);
|
||||||
|
}
|
||||||
|
|
||||||
|
Limbo.getInstance().getEventsManager().callEvent(new PlayerJoinEvent(player));
|
||||||
|
|
||||||
|
PacketPlayOutSpawnPosition spawnPos = new PacketPlayOutSpawnPosition(BlockPosition.from(s));
|
||||||
|
sendPacket(spawnPos);
|
||||||
|
|
||||||
|
PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch(), 1);
|
||||||
|
player.setLocation(new Location(world, s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch()));
|
||||||
|
sendPacket(positionLook);
|
||||||
|
|
||||||
|
while (client_socket.isConnected()) {
|
||||||
|
try {
|
||||||
|
int size = DataTypeIO.readVarInt(input);
|
||||||
|
int packetId = DataTypeIO.readVarInt(input);
|
||||||
|
Class<? extends Packet> packetType = Packet.getPlayIn().get(packetId);
|
||||||
|
//System.out.println(packetId + " -> " + packetType);
|
||||||
|
if (packetType == null) {
|
||||||
|
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
|
||||||
|
} else if (packetType.equals(PacketPlayInPositionAndLook.class)) {
|
||||||
|
PacketPlayInPositionAndLook pos = new PacketPlayInPositionAndLook(input);
|
||||||
|
player.setLocation(new Location(player.getWorld(), pos.getX(), pos.getY(), pos.getZ(), pos.getYaw(), pos.getPitch()));
|
||||||
|
|
||||||
|
PacketPlayOutUpdateViewPosition response = new PacketPlayOutUpdateViewPosition((int) player.getLocation().getX() >> 4, (int) player.getLocation().getZ() >> 4);
|
||||||
|
sendPacket(response);
|
||||||
|
} else if (packetType.equals(PacketPlayInPosition.class)) {
|
||||||
|
PacketPlayInPosition pos = new PacketPlayInPosition(input);
|
||||||
|
player.setLocation(new Location(player.getWorld(), pos.getX(), pos.getY(), pos.getZ(), player.getLocation().getYaw(), player.getLocation().getPitch()));
|
||||||
|
|
||||||
|
PacketPlayOutUpdateViewPosition response = new PacketPlayOutUpdateViewPosition((int) player.getLocation().getX() >> 4, (int) player.getLocation().getZ() >> 4);
|
||||||
|
sendPacket(response);
|
||||||
|
} else if (packetType.equals(PacketPlayInRotation.class)) {
|
||||||
|
PacketPlayInRotation pos = new PacketPlayInRotation(input);
|
||||||
|
player.setLocation(new Location(player.getWorld(), player.getLocation().getX(), player.getLocation().getY(), player.getLocation().getZ(), pos.getYaw(), pos.getPitch()));
|
||||||
|
|
||||||
|
PacketPlayOutUpdateViewPosition response = new PacketPlayOutUpdateViewPosition((int) player.getLocation().getX() >> 4, (int) player.getLocation().getZ() >> 4);
|
||||||
|
sendPacket(response);
|
||||||
|
} else if (packetType.equals(PacketPlayInKeepAlive.class)) {
|
||||||
|
PacketPlayInKeepAlive alive = new PacketPlayInKeepAlive(input);
|
||||||
|
if (alive.getPayload() != lastKeepAlivePayLoad) {
|
||||||
|
Limbo.getInstance().getConsole().sendMessage("Incorrect Payload recieved in KeepAlive packet for player " + player.getName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (packetType.equals(PacketPlayInTabComplete.class)) {
|
||||||
|
PacketPlayInTabComplete request = new PacketPlayInTabComplete(input);
|
||||||
|
String[] command = CustomStringUtils.splitStringToArgs(request.getText().substring(1));
|
||||||
|
|
||||||
|
List<TabCompleteMatches> matches = new ArrayList<TabCompleteMatches>();
|
||||||
|
|
||||||
|
matches.addAll(Limbo.getInstance().getPluginManager().getTabOptions(player, command).stream().map(each -> new TabCompleteMatches(each)).collect(Collectors.toList()));
|
||||||
|
|
||||||
|
int start = CustomStringUtils.getIndexOfArg(request.getText(), command.length - 1) + 1;
|
||||||
|
int length = command[command.length - 1].length();
|
||||||
|
|
||||||
|
PacketPlayOutTabComplete response = new PacketPlayOutTabComplete(request.getId(), start, length, matches.toArray(new TabCompleteMatches[matches.size()]));
|
||||||
|
sendPacket(response);
|
||||||
|
} else if (packetType.equals(PacketPlayInChat.class)) {
|
||||||
|
PacketPlayInChat chat = new PacketPlayInChat(input);
|
||||||
|
if (chat.getMessage().startsWith("/")) {
|
||||||
|
Limbo.getInstance().dispatchCommand(player, chat.getMessage());
|
||||||
|
} else {
|
||||||
|
player.chat(chat.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Limbo.getInstance().getEventsManager().callEvent(new PlayerQuitEvent(player));
|
||||||
|
|
||||||
|
str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
|
||||||
|
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had disconnected!");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
client_socket.close();
|
||||||
|
} catch (IOException e) {}
|
||||||
|
state = ClientState.DISCONNECTED;
|
||||||
|
|
||||||
|
if (player != null) {
|
||||||
|
Limbo.getInstance().removePlayer(player);
|
||||||
|
}
|
||||||
|
Limbo.getInstance().getServerConnection().getClients().remove(this);
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.loohp.limbo.Server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
import com.loohp.limbo.Server.ClientConnection.ClientState;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutKeepAlive;
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class KeepAliveSender extends Thread {
|
||||||
|
|
||||||
|
private Random random;
|
||||||
|
|
||||||
|
public KeepAliveSender() {
|
||||||
|
random = new Random();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
for (ClientConnection client : Limbo.getInstance().getServerConnection().getClients()) {
|
||||||
|
if (client.getClientState().equals(ClientState.PLAY)) {
|
||||||
|
try {
|
||||||
|
PacketPlayOutKeepAlive packet = new PacketPlayOutKeepAlive(random.nextLong());
|
||||||
|
byte[] packetByte = packet.serializePacket();
|
||||||
|
DataTypeIO.writeVarInt(client.output, packetByte.length);
|
||||||
|
client.output.write(packetByte);
|
||||||
|
client.setLastKeepAlivePayLoad(packet.getPayload());
|
||||||
|
} catch (IOException ignore) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TimeUnit.SECONDS.sleep(5);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Packet {
|
||||||
|
|
||||||
|
private static Map<Integer, Class<? extends PacketIn>> HandshakeIn;
|
||||||
|
|
||||||
|
private static Map<Integer, Class<? extends PacketIn>> StatusIn;
|
||||||
|
private static Map<Class<? extends PacketOut>, Integer> StatusOut;
|
||||||
|
|
||||||
|
private static Map<Integer, Class<? extends PacketIn>> LoginIn;
|
||||||
|
private static Map<Class<? extends PacketOut>, Integer> LoginOut;
|
||||||
|
|
||||||
|
private static Map<Integer, Class<? extends PacketIn>> PlayIn;
|
||||||
|
private static Map<Class<? extends PacketOut>, Integer> PlayOut;
|
||||||
|
|
||||||
|
public static Map<Integer, Class<? extends PacketIn>> getHandshakeIn() {
|
||||||
|
return HandshakeIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setHandshakeIn(Map<Integer, Class<? extends PacketIn>> handshakeIn) {
|
||||||
|
HandshakeIn = handshakeIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Integer, Class<? extends PacketIn>> getStatusIn() {
|
||||||
|
return StatusIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setStatusIn(Map<Integer, Class<? extends PacketIn>> statusIn) {
|
||||||
|
StatusIn = statusIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Class<? extends PacketOut>, Integer> getStatusOut() {
|
||||||
|
return StatusOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setStatusOut(Map<Class<? extends PacketOut>, Integer> statusOut) {
|
||||||
|
StatusOut = statusOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Integer, Class<? extends PacketIn>> getLoginIn() {
|
||||||
|
return LoginIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLoginIn(Map<Integer, Class<? extends PacketIn>> loginIn) {
|
||||||
|
LoginIn = loginIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Class<? extends PacketOut>, Integer> getLoginOut() {
|
||||||
|
return LoginOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLoginOut(Map<Class<? extends PacketOut>, Integer> loginOut) {
|
||||||
|
LoginOut = loginOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Integer, Class<? extends PacketIn>> getPlayIn() {
|
||||||
|
return PlayIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPlayIn(Map<Integer, Class<? extends PacketIn>> playIn) {
|
||||||
|
PlayIn = playIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<Class<? extends PacketOut>, Integer> getPlayOut() {
|
||||||
|
return PlayOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPlayOut(Map<Class<? extends PacketOut>, Integer> playOut) {
|
||||||
|
PlayOut = playOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketHandshakingIn extends PacketIn {
|
||||||
|
|
||||||
|
public static enum HandshakeType {
|
||||||
|
STATUS(1),
|
||||||
|
LOGIN(2);
|
||||||
|
|
||||||
|
int networkId;
|
||||||
|
|
||||||
|
HandshakeType(int networkId) {
|
||||||
|
this.networkId = networkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNetworkId() {
|
||||||
|
return networkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandshakeType fromNetworkId(int networkId) {
|
||||||
|
for (HandshakeType type : HandshakeType.values()) {
|
||||||
|
if (type.getNetworkId() == networkId) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Invalid HandshakeType networkId, expected 0 or 1, but got " + networkId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================
|
||||||
|
|
||||||
|
private int protocolVersion;
|
||||||
|
private String serverAddress;
|
||||||
|
private int serverPort;
|
||||||
|
private HandshakeType handshakeType;
|
||||||
|
|
||||||
|
public PacketHandshakingIn(int protocolVersion, String serverAddress, int serverPort, HandshakeType handshakeType) {
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
|
this.serverAddress = serverAddress;
|
||||||
|
this.serverPort = serverPort;
|
||||||
|
this.handshakeType = handshakeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketHandshakingIn(DataInputStream in) throws IOException {
|
||||||
|
this(DataTypeIO.readVarInt(in), DataTypeIO.readString(in), in.readShort() & 0xFFFF, HandshakeType.fromNetworkId(DataTypeIO.readVarInt(in)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getProtocolVersion() {
|
||||||
|
return protocolVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerAddress() {
|
||||||
|
return serverAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getServerPort() {
|
||||||
|
return serverPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HandshakeType getHandshakeType() {
|
||||||
|
return handshakeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
public abstract class PacketIn extends Packet {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketLoginInLoginStart extends PacketIn {
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public PacketLoginInLoginStart(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketLoginInLoginStart(DataInputStream in) throws IOException {
|
||||||
|
this(DataTypeIO.readString(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
|
||||||
|
public class PacketLoginInPluginMessaging extends PacketIn {
|
||||||
|
|
||||||
|
private int messageId;
|
||||||
|
private NamespacedKey channel;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketLoginInPluginMessaging(int messageId, NamespacedKey channel, byte[] data) {
|
||||||
|
this.messageId = messageId;
|
||||||
|
this.channel = channel;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketLoginInPluginMessaging(DataInputStream in, int packetLength, int packetId) throws IOException {
|
||||||
|
messageId = DataTypeIO.readVarInt(in);
|
||||||
|
String rawChannel = DataTypeIO.readString(in);
|
||||||
|
channel = new NamespacedKey(rawChannel);
|
||||||
|
int dataLength = packetLength - DataTypeIO.getVarIntLength(packetId) - DataTypeIO.getVarIntLength(messageId) - DataTypeIO.getStringLength(rawChannel, StandardCharsets.UTF_8);
|
||||||
|
data = new byte[dataLength];
|
||||||
|
in.read(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMessageId() {
|
||||||
|
return messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketLoginOutDisconnect extends PacketOut {
|
||||||
|
|
||||||
|
private String jsonReason;
|
||||||
|
|
||||||
|
public PacketLoginOutDisconnect(String jsonReason) {
|
||||||
|
this.jsonReason = jsonReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJsonReason() {
|
||||||
|
return jsonReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getLoginOut().get(getClass()));
|
||||||
|
DataTypeIO.writeString(output, jsonReason, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketLoginOutLoginSuccess extends PacketOut {
|
||||||
|
|
||||||
|
private UUID uuid;
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public PacketLoginOutLoginSuccess(UUID uuid, String username) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getLoginOut().get(getClass()));
|
||||||
|
DataTypeIO.writeUUID(output, uuid);
|
||||||
|
DataTypeIO.writeString(output, username, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
|
||||||
|
public class PacketLoginOutPluginMessaging extends PacketOut {
|
||||||
|
|
||||||
|
private int messageId;
|
||||||
|
private NamespacedKey channel;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketLoginOutPluginMessaging(int messageId, NamespacedKey channel, byte[] data) {
|
||||||
|
this.messageId = messageId;
|
||||||
|
this.channel = channel;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMessageId() {
|
||||||
|
return messageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getLoginOut().get(getClass()));
|
||||||
|
DataTypeIO.writeVarInt(output, messageId);
|
||||||
|
DataTypeIO.writeString(output, channel.toString(), StandardCharsets.UTF_8);
|
||||||
|
output.write(data);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public abstract class PacketOut extends Packet {
|
||||||
|
|
||||||
|
public abstract byte[] serializePacket() throws IOException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketPlayInChat extends PacketIn {
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public PacketPlayInChat(String message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketPlayInChat(DataInputStream in) throws IOException {
|
||||||
|
this(DataTypeIO.readString(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketPlayInKeepAlive extends PacketIn {
|
||||||
|
|
||||||
|
long payload;
|
||||||
|
|
||||||
|
public PacketPlayInKeepAlive(long payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketPlayInKeepAlive(DataInputStream in) throws IOException {
|
||||||
|
this(in.readLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
|
||||||
|
public class PacketPlayInPluginMessaging extends PacketIn {
|
||||||
|
|
||||||
|
private NamespacedKey channel;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketPlayInPluginMessaging(NamespacedKey channel, byte[] data) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketPlayInPluginMessaging(DataInputStream in, int packetLength, int packetId) throws IOException {
|
||||||
|
String rawChannel = DataTypeIO.readString(in);
|
||||||
|
channel = new NamespacedKey(rawChannel);
|
||||||
|
int dataLength = packetLength - DataTypeIO.getVarIntLength(packetId) - DataTypeIO.getStringLength(rawChannel, StandardCharsets.UTF_8);
|
||||||
|
data = new byte[dataLength];
|
||||||
|
in.read(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketPlayInPosition extends PacketIn {
|
||||||
|
|
||||||
|
private double x;
|
||||||
|
private double y;
|
||||||
|
private double z;
|
||||||
|
private boolean onGround;
|
||||||
|
|
||||||
|
public PacketPlayInPosition(double x, double y, double z, boolean onGround) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.onGround = onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketPlayInPosition(DataInputStream in) throws IOException {
|
||||||
|
this(in.readDouble(), in.readDouble(), in.readDouble(), in.readBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onGround() {
|
||||||
|
return onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketPlayInPositionAndLook extends PacketIn {
|
||||||
|
|
||||||
|
private double x;
|
||||||
|
private double y;
|
||||||
|
private double z;
|
||||||
|
private float yaw;
|
||||||
|
private float pitch;
|
||||||
|
private boolean onGround;
|
||||||
|
|
||||||
|
public PacketPlayInPositionAndLook(double x, double y, double z, float yaw, float pitch, boolean onGround) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
this.onGround = onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketPlayInPositionAndLook(DataInputStream in) throws IOException {
|
||||||
|
this(in.readDouble(), in.readDouble(), in.readDouble(), in.readFloat(), in.readFloat(), in.readBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getYaw() {
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onGround() {
|
||||||
|
return onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketPlayInRotation extends PacketIn {
|
||||||
|
|
||||||
|
private float yaw;
|
||||||
|
private float pitch;
|
||||||
|
private boolean onGround;
|
||||||
|
|
||||||
|
public PacketPlayInRotation(float yaw, float pitch, boolean onGround) {
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
this.onGround = onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketPlayInRotation(DataInputStream in) throws IOException {
|
||||||
|
this(in.readFloat(), in.readFloat(), in.readBoolean());
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getYaw() {
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onGround() {
|
||||||
|
return onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketPlayInTabComplete extends PacketIn {
|
||||||
|
|
||||||
|
private int id;
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
public PacketPlayInTabComplete(int id, String text) {
|
||||||
|
this.id = id;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketPlayInTabComplete(DataInputStream in) throws IOException {
|
||||||
|
this(DataTypeIO.readVarInt(in), DataTypeIO.readString(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketPlayOutChat extends PacketOut {
|
||||||
|
|
||||||
|
private String json;
|
||||||
|
private int position;
|
||||||
|
private UUID sender;
|
||||||
|
|
||||||
|
public PacketPlayOutChat(String json, int position, UUID sender) {
|
||||||
|
this.json = json;
|
||||||
|
this.position = position;
|
||||||
|
this.sender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJson() {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getSender() {
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
DataTypeIO.writeString(output, json, StandardCharsets.UTF_8);
|
||||||
|
output.writeByte(position);
|
||||||
|
DataTypeIO.writeUUID(output, sender);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketPlayOutDeclareCommands extends PacketOut {
|
||||||
|
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketPlayOutDeclareCommands(byte[] data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
output.write(data);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketPlayOutDisconnect extends PacketOut {
|
||||||
|
|
||||||
|
private String jsonReason;
|
||||||
|
|
||||||
|
public PacketPlayOutDisconnect(String jsonReason) {
|
||||||
|
this.jsonReason = jsonReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJsonReason() {
|
||||||
|
return jsonReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
DataTypeIO.writeString(output, jsonReason, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketPlayOutGameState extends PacketOut {
|
||||||
|
|
||||||
|
private int reason;
|
||||||
|
private float value;
|
||||||
|
|
||||||
|
public PacketPlayOutGameState(int reason, float value) {
|
||||||
|
this.reason = reason;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
output.writeByte(reason);
|
||||||
|
output.writeFloat(value);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketPlayOutKeepAlive extends PacketOut {
|
||||||
|
|
||||||
|
long payload;
|
||||||
|
|
||||||
|
public PacketPlayOutKeepAlive(long payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
output.writeLong(payload);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.GameMode;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
import com.loohp.limbo.World.World;
|
||||||
|
import com.loohp.limbo.World.World.Environment;
|
||||||
|
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
import net.querz.nbt.tag.ListTag;
|
||||||
|
|
||||||
|
public class PacketPlayOutLogin extends PacketOut {
|
||||||
|
|
||||||
|
private int entityId;
|
||||||
|
private boolean isHardcore;
|
||||||
|
private GameMode gamemode;
|
||||||
|
private String[] worldsNames;
|
||||||
|
private CompoundTag dimensionCodec;
|
||||||
|
private Environment dimension;
|
||||||
|
private String worldName;
|
||||||
|
private long hashedSeed;
|
||||||
|
private byte maxPlayers;
|
||||||
|
private int viewDistance;
|
||||||
|
private boolean reducedDebugInfo;
|
||||||
|
private boolean enableRespawnScreen;
|
||||||
|
private boolean isDebug;
|
||||||
|
private boolean isFlat;
|
||||||
|
|
||||||
|
public PacketPlayOutLogin(int entityId, boolean isHardcore, GameMode gamemode,
|
||||||
|
String[] worldsNames, CompoundTag dimensionCodec, World world, long hashedSeed,
|
||||||
|
byte maxPlayers, int viewDistance, boolean reducedDebugInfo, boolean enableRespawnScreen, boolean isDebug,
|
||||||
|
boolean isFlat) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
this.isHardcore = isHardcore;
|
||||||
|
this.gamemode = gamemode;
|
||||||
|
this.worldsNames = worldsNames;
|
||||||
|
this.dimensionCodec = dimensionCodec;
|
||||||
|
this.dimension = world.getEnvironment();
|
||||||
|
this.worldName = new NamespacedKey(world.getName()).toString();
|
||||||
|
this.hashedSeed = hashedSeed;
|
||||||
|
this.maxPlayers = maxPlayers;
|
||||||
|
this.viewDistance = viewDistance;
|
||||||
|
this.reducedDebugInfo = reducedDebugInfo;
|
||||||
|
this.enableRespawnScreen = enableRespawnScreen;
|
||||||
|
this.isDebug = isDebug;
|
||||||
|
this.isFlat = isFlat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEntityId() {
|
||||||
|
return entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHardcore() {
|
||||||
|
return isHardcore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameMode getGamemode() {
|
||||||
|
return gamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getWorldsNames() {
|
||||||
|
return worldsNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag getDimensionCodec() {
|
||||||
|
return dimensionCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment getDimension() {
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWorldName() {
|
||||||
|
return worldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getHashedSeed() {
|
||||||
|
return hashedSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getMaxPlayers() {
|
||||||
|
return maxPlayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getViewDistance() {
|
||||||
|
return viewDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReducedDebugInfo() {
|
||||||
|
return reducedDebugInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnableRespawnScreen() {
|
||||||
|
return enableRespawnScreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDebug() {
|
||||||
|
return isDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFlat() {
|
||||||
|
return isFlat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
output.writeInt(entityId);
|
||||||
|
output.writeBoolean(isHardcore);
|
||||||
|
output.writeByte((byte) gamemode.getId());
|
||||||
|
output.writeByte((byte) gamemode.getId());
|
||||||
|
DataTypeIO.writeVarInt(output, worldsNames.length);
|
||||||
|
for (int u = 0; u < worldsNames.length; u++) {
|
||||||
|
DataTypeIO.writeString(output, worldsNames[u], StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
DataTypeIO.writeCompoundTag(output, dimensionCodec);
|
||||||
|
CompoundTag tag = null;
|
||||||
|
ListTag<CompoundTag> list = dimensionCodec.getCompoundTag("minecraft:dimension_type").getListTag("value").asCompoundTagList();
|
||||||
|
for (CompoundTag each : list) {
|
||||||
|
if (each.getString("name").equals(dimension.getNamespacedKey().toString())) {
|
||||||
|
tag = each.getCompoundTag("element");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataTypeIO.writeCompoundTag(output, tag != null ? tag : list.get(0));
|
||||||
|
DataTypeIO.writeString(output, worldName, StandardCharsets.UTF_8);
|
||||||
|
output.writeLong(hashedSeed);
|
||||||
|
DataTypeIO.writeVarInt(output, maxPlayers);
|
||||||
|
DataTypeIO.writeVarInt(output, viewDistance);
|
||||||
|
output.writeBoolean(reducedDebugInfo);
|
||||||
|
output.writeBoolean(enableRespawnScreen);
|
||||||
|
output.writeBoolean(isDebug);
|
||||||
|
output.writeBoolean(isFlat);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.ChunkDataUtils;
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.World.GeneratedBlockDataMappings;
|
||||||
|
import com.loohp.limbo.World.World.Environment;
|
||||||
|
|
||||||
|
import net.querz.mca.Chunk;
|
||||||
|
import net.querz.mca.Section;
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
import net.querz.nbt.tag.ListTag;
|
||||||
|
|
||||||
|
public class PacketPlayOutMapChunk extends PacketOut {
|
||||||
|
|
||||||
|
private int chunkX;
|
||||||
|
private int chunkZ;
|
||||||
|
private Chunk chunk;
|
||||||
|
private Environment environment;
|
||||||
|
|
||||||
|
public PacketPlayOutMapChunk(int chunkX, int chunkZ, Chunk chunk, Environment environment) {
|
||||||
|
this.chunkX = chunkX;
|
||||||
|
this.chunkZ = chunkZ;
|
||||||
|
this.chunk = chunk;
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public PacketPlayOutMapChunk(int chunkX, int chunkZ, Chunk chunk) {
|
||||||
|
this(chunkZ, chunkZ, chunk, Environment.NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chunk getChunk() {
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChunkX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChunkZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment getEnvironment() {
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
|
||||||
|
output.writeInt(chunkX);
|
||||||
|
output.writeInt(chunkZ);
|
||||||
|
output.writeBoolean(true);
|
||||||
|
int bitmask = 0;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
Section section = chunk.getSection(i);
|
||||||
|
if (section != null) {
|
||||||
|
bitmask = bitmask | (int) Math.pow(2, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataTypeIO.writeVarInt(output, bitmask);
|
||||||
|
DataTypeIO.writeCompoundTag(output, chunk.getHeightMaps());
|
||||||
|
|
||||||
|
DataTypeIO.writeVarInt(output, 1024);
|
||||||
|
int biome;
|
||||||
|
switch (environment) {
|
||||||
|
case END:
|
||||||
|
biome = 9; //the_end
|
||||||
|
break;
|
||||||
|
case NETHER:
|
||||||
|
biome = 8; //nether_waste
|
||||||
|
break;
|
||||||
|
case NORMAL:
|
||||||
|
default:
|
||||||
|
biome = 1; //plains
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 1024; i++) {
|
||||||
|
DataTypeIO.writeVarInt(output, biome);
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream dataOut = new DataOutputStream(dataBuffer);
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
Section section = chunk.getSection(i);
|
||||||
|
if (section != null) {
|
||||||
|
int counter = 0;
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
CompoundTag tag = section.getBlockStateAt(x, y, z);
|
||||||
|
if (tag != null && !tag.getString("Name").equals("minecraft:air")) {
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataOut.writeShort(counter);
|
||||||
|
|
||||||
|
int newBits = 32 - Integer.numberOfLeadingZeros(section.getPalette().size() - 1);
|
||||||
|
newBits = Math.max(newBits, 4);
|
||||||
|
|
||||||
|
if (newBits <= 8) {
|
||||||
|
if (newBits == 4) {
|
||||||
|
dataOut.writeByte(4);
|
||||||
|
} else {
|
||||||
|
newBits = 8;
|
||||||
|
ChunkDataUtils.adjustBlockStateBits(newBits, section, chunk.getDataVersion());
|
||||||
|
dataOut.writeByte(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypeIO.writeVarInt(dataOut, section.getPalette().size());
|
||||||
|
//System.out.println(section.getPalette().size());
|
||||||
|
Iterator<CompoundTag> itr1 = section.getPalette().iterator();
|
||||||
|
//System.out.println("Nonnull -> " + i + " " + newBits);
|
||||||
|
counter = 0;
|
||||||
|
while (itr1.hasNext()) {
|
||||||
|
CompoundTag tag = itr1.next();
|
||||||
|
DataTypeIO.writeVarInt(dataOut, GeneratedBlockDataMappings.getGlobalPaletteIDFromState(tag));
|
||||||
|
//System.out.println(tag + " -> " + GeneratedDataUtils.getGlobalPaletteIDFromState(tag));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dataOut.writeByte(14);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypeIO.writeVarInt(dataOut, section.getBlockStates().length);
|
||||||
|
for (int u = 0; u < section.getBlockStates().length; u++) {
|
||||||
|
dataOut.writeLong(section.getBlockStates()[u]);
|
||||||
|
//System.out.println(Arrays.toString(section.getBlockStates()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] data = dataBuffer.toByteArray();
|
||||||
|
DataTypeIO.writeVarInt(output, data.length);
|
||||||
|
output.write(data);
|
||||||
|
|
||||||
|
ListTag<CompoundTag> tileEntities = chunk.getTileEntities();
|
||||||
|
DataTypeIO.writeVarInt(output, tileEntities.size());
|
||||||
|
for (CompoundTag each : tileEntities) {
|
||||||
|
DataTypeIO.writeCompoundTag(output, each);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,4 @@
|
||||||
/*
|
package com.loohp.limbo.Server.Packets;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.network.protocol.packets;
|
|
||||||
|
|
||||||
import com.loohp.limbo.registry.PacketRegistry;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
|
|
@ -31,9 +10,9 @@ public class PacketPlayOutPlayerAbilities extends PacketOut {
|
||||||
INVULNERABLE(0x01),
|
INVULNERABLE(0x01),
|
||||||
FLY(0x02),
|
FLY(0x02),
|
||||||
ALLOW_FLYING(0x04),
|
ALLOW_FLYING(0x04),
|
||||||
CREATIVE(0x08);
|
INSTANT_BREAK(0x08);
|
||||||
|
|
||||||
private final int bitvalue;
|
int bitvalue;
|
||||||
|
|
||||||
PlayerAbilityFlags(int bitvalue) {
|
PlayerAbilityFlags(int bitvalue) {
|
||||||
this.bitvalue = bitvalue;
|
this.bitvalue = bitvalue;
|
||||||
|
|
@ -44,9 +23,9 @@ public class PacketPlayOutPlayerAbilities extends PacketOut {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final PlayerAbilityFlags[] flags;
|
private PlayerAbilityFlags[] flags;
|
||||||
private final float flySpeed;
|
private float flySpeed;
|
||||||
private final float fieldOfField;
|
private float fieldOfField;
|
||||||
|
|
||||||
public PacketPlayOutPlayerAbilities(float flySpeed, float fieldOfField, PlayerAbilityFlags... flags) {
|
public PacketPlayOutPlayerAbilities(float flySpeed, float fieldOfField, PlayerAbilityFlags... flags) {
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
|
|
@ -71,12 +50,12 @@ public class PacketPlayOutPlayerAbilities extends PacketOut {
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
DataOutputStream output = new DataOutputStream(buffer);
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
output.writeByte(PacketRegistry.getPacketId(getClass()));
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
int value = 0;
|
||||||
byte value = 0;
|
|
||||||
for (PlayerAbilityFlags flag : flags) {
|
for (PlayerAbilityFlags flag : flags) {
|
||||||
value = (byte) (value | flag.getValue());
|
value = value | flag.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
output.writeByte(value);
|
output.writeByte(value);
|
||||||
output.writeFloat(flySpeed);
|
output.writeFloat(flySpeed);
|
||||||
output.writeFloat(fieldOfField);
|
output.writeFloat(fieldOfField);
|
||||||
|
|
@ -0,0 +1,168 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerInfo.PlayerInfoData.PlayerInfoDataAddPlayer;
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.GameMode;
|
||||||
|
|
||||||
|
public class PacketPlayOutPlayerInfo extends PacketOut {
|
||||||
|
|
||||||
|
public enum PlayerInfoAction {
|
||||||
|
ADD_PLAYER(0), UPDATE_GAMEMODE(1), UPDATE_LATENCY(2), UPDATE_DISPLAY_NAME(3), REMOVE_PLAYER(4);
|
||||||
|
|
||||||
|
int id;
|
||||||
|
|
||||||
|
PlayerInfoAction(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayerInfoAction action;
|
||||||
|
private UUID uuid;
|
||||||
|
private PlayerInfoData data;
|
||||||
|
|
||||||
|
public PacketPlayOutPlayerInfo(PlayerInfoAction action, UUID uuid, PlayerInfoData data) {
|
||||||
|
this.action = action;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerInfoAction getAction() {
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerInfoData getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
DataTypeIO.writeVarInt(output, action.getId());
|
||||||
|
DataTypeIO.writeVarInt(output, 1);
|
||||||
|
DataTypeIO.writeUUID(output, uuid);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case ADD_PLAYER:
|
||||||
|
PlayerInfoDataAddPlayer data = (PlayerInfoDataAddPlayer) this.data;
|
||||||
|
DataTypeIO.writeString(output, data.getName(), StandardCharsets.UTF_8);
|
||||||
|
if (data.getProperty().isPresent()) {
|
||||||
|
DataTypeIO.writeVarInt(output, 1);
|
||||||
|
DataTypeIO.writeString(output, "textures", StandardCharsets.UTF_8);
|
||||||
|
DataTypeIO.writeString(output, data.getProperty().get().getSkin(), StandardCharsets.UTF_8);
|
||||||
|
output.writeBoolean(true);
|
||||||
|
DataTypeIO.writeString(output, data.getProperty().get().getSignature(), StandardCharsets.UTF_8);
|
||||||
|
} else {
|
||||||
|
DataTypeIO.writeVarInt(output, 0);
|
||||||
|
}
|
||||||
|
DataTypeIO.writeVarInt(output, data.getGamemode().getId());
|
||||||
|
DataTypeIO.writeVarInt(output, data.getPing());
|
||||||
|
if (data.getDisplayNameJson().isPresent()) {
|
||||||
|
output.writeBoolean(true);
|
||||||
|
DataTypeIO.writeString(output, data.getDisplayNameJson().get(), StandardCharsets.UTF_8);
|
||||||
|
} else {
|
||||||
|
output.writeBoolean(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REMOVE_PLAYER:
|
||||||
|
break;
|
||||||
|
case UPDATE_DISPLAY_NAME:
|
||||||
|
break;
|
||||||
|
case UPDATE_GAMEMODE:
|
||||||
|
break;
|
||||||
|
case UPDATE_LATENCY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========
|
||||||
|
|
||||||
|
public static class PlayerInfoData {
|
||||||
|
|
||||||
|
public static class PlayerInfoDataAddPlayer extends PlayerInfoData {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private Optional<PlayerSkinProperty> skin;
|
||||||
|
private GameMode gamemode;
|
||||||
|
private int ping;
|
||||||
|
private boolean hasDisplayName;
|
||||||
|
private Optional<String> displayNameJson;
|
||||||
|
|
||||||
|
public PlayerInfoDataAddPlayer(String name, Optional<PlayerSkinProperty> skin, GameMode gamemode, int ping,
|
||||||
|
boolean hasDisplayName, Optional<String> displayNameJson) {
|
||||||
|
this.name = name;
|
||||||
|
this.skin = skin;
|
||||||
|
this.gamemode = gamemode;
|
||||||
|
this.ping = ping;
|
||||||
|
this.hasDisplayName = hasDisplayName;
|
||||||
|
this.displayNameJson = displayNameJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<PlayerSkinProperty> getProperty() {
|
||||||
|
return skin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameMode getGamemode() {
|
||||||
|
return gamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPing() {
|
||||||
|
return ping;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHasDisplayName() {
|
||||||
|
return hasDisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> getDisplayNameJson() {
|
||||||
|
return displayNameJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlayerSkinProperty {
|
||||||
|
|
||||||
|
private String skin;
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
public PlayerSkinProperty(String skin, String signature) {
|
||||||
|
this.skin = skin;
|
||||||
|
this.signature = signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSkin() {
|
||||||
|
return skin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSignature() {
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
|
||||||
|
public class PacketPlayOutPluginMessaging extends PacketOut {
|
||||||
|
|
||||||
|
private NamespacedKey channel;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
public PacketPlayOutPluginMessaging(NamespacedKey channel, byte[] data) {
|
||||||
|
this.channel = channel;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
DataTypeIO.writeString(output, channel.toString(), StandardCharsets.UTF_8);
|
||||||
|
output.write(data);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketPlayOutPositionAndLook extends PacketOut {
|
||||||
|
|
||||||
|
public enum PlayerTeleportFlags {
|
||||||
|
X((byte) 0x01),
|
||||||
|
Y((byte) 0x02),
|
||||||
|
Z((byte) 0x04),
|
||||||
|
Y_ROT((byte) 0x08),
|
||||||
|
X_ROT((byte) 0x10);
|
||||||
|
|
||||||
|
byte bit;
|
||||||
|
|
||||||
|
PlayerTeleportFlags(byte bit) {
|
||||||
|
this.bit = bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getBit() {
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double x;
|
||||||
|
private double y;
|
||||||
|
private double z;
|
||||||
|
private float yaw;
|
||||||
|
private float pitch;
|
||||||
|
private Set<PlayerTeleportFlags> flags;
|
||||||
|
private int teleportId;
|
||||||
|
|
||||||
|
public PacketPlayOutPositionAndLook(double x, double y, double z, float yaw, float pitch, int teleportId, PlayerTeleportFlags... flags) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
this.teleportId = teleportId;
|
||||||
|
this.flags = Arrays.asList(flags).stream().collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getYaw() {
|
||||||
|
return yaw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPitch() {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<PlayerTeleportFlags> getFlags() {
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTeleportId() {
|
||||||
|
return teleportId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
output.writeDouble(x);
|
||||||
|
output.writeDouble(y);
|
||||||
|
output.writeDouble(z);
|
||||||
|
output.writeFloat(yaw);
|
||||||
|
output.writeFloat(pitch);
|
||||||
|
|
||||||
|
byte flag = 0;
|
||||||
|
for (PlayerTeleportFlags each : flags) {
|
||||||
|
flag = (byte) (flag | each.getBit());
|
||||||
|
}
|
||||||
|
|
||||||
|
output.writeByte(flag);
|
||||||
|
DataTypeIO.writeVarInt(output, teleportId);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.Utils.GameMode;
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
import com.loohp.limbo.World.World;
|
||||||
|
import com.loohp.limbo.World.World.Environment;
|
||||||
|
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
import net.querz.nbt.tag.ListTag;
|
||||||
|
|
||||||
|
public class PacketPlayOutRespawn extends PacketOut {
|
||||||
|
|
||||||
|
private Environment dimension;
|
||||||
|
private String worldName;
|
||||||
|
private CompoundTag dimensionCodec;
|
||||||
|
private long hashedSeed;
|
||||||
|
private GameMode gamemode;
|
||||||
|
private boolean isDebug;
|
||||||
|
private boolean isFlat;
|
||||||
|
private boolean copyMetaData;
|
||||||
|
|
||||||
|
public PacketPlayOutRespawn(World world, CompoundTag dimensionCodec, long hashedSeed, GameMode gamemode, boolean isDebug,
|
||||||
|
boolean isFlat, boolean copyMetaData) {
|
||||||
|
this.dimension = world.getEnvironment();
|
||||||
|
this.dimensionCodec = dimensionCodec;
|
||||||
|
this.worldName = new NamespacedKey(world.getName()).toString();
|
||||||
|
this.hashedSeed = hashedSeed;
|
||||||
|
this.gamemode = gamemode;
|
||||||
|
this.isDebug = isDebug;
|
||||||
|
this.isFlat = isFlat;
|
||||||
|
this.copyMetaData = copyMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag getDimensionCodec() {
|
||||||
|
return dimensionCodec;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment getDimension() {
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWorldName() {
|
||||||
|
return worldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getHashedSeed() {
|
||||||
|
return hashedSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GameMode getGamemode() {
|
||||||
|
return gamemode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDebug() {
|
||||||
|
return isDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFlat() {
|
||||||
|
return isFlat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCopyMetaData() {
|
||||||
|
return copyMetaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
CompoundTag tag = null;
|
||||||
|
ListTag<CompoundTag> list = dimensionCodec.getCompoundTag("minecraft:dimension_type").getListTag("value").asCompoundTagList();
|
||||||
|
for (CompoundTag each : list) {
|
||||||
|
if (each.getString("name").equals(dimension.getNamespacedKey().toString())) {
|
||||||
|
tag = each.getCompoundTag("element");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DataTypeIO.writeCompoundTag(output, tag != null ? tag : list.get(0));
|
||||||
|
DataTypeIO.writeString(output, worldName, StandardCharsets.UTF_8);
|
||||||
|
output.writeLong(hashedSeed);
|
||||||
|
output.writeByte((byte) gamemode.getId());
|
||||||
|
output.writeByte((byte) gamemode.getId());
|
||||||
|
output.writeBoolean(isDebug);
|
||||||
|
output.writeBoolean(isFlat);
|
||||||
|
output.writeBoolean(copyMetaData);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketPlayOutShowPlayerSkins extends PacketOut {
|
||||||
|
|
||||||
|
private int entityId;
|
||||||
|
|
||||||
|
public PacketPlayOutShowPlayerSkins(int entityId) {
|
||||||
|
this.entityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEntityId() {
|
||||||
|
return entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
|
||||||
|
DataTypeIO.writeVarInt(output, entityId);
|
||||||
|
output.writeByte(16);
|
||||||
|
DataTypeIO.writeVarInt(output, 0);
|
||||||
|
int bitmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40;
|
||||||
|
output.writeByte(bitmask);
|
||||||
|
output.writeByte(0xff);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
import com.loohp.limbo.World.BlockPosition;
|
||||||
|
|
||||||
|
public class PacketPlayOutSpawnPosition extends PacketOut {
|
||||||
|
|
||||||
|
private BlockPosition position;
|
||||||
|
|
||||||
|
public PacketPlayOutSpawnPosition(BlockPosition position) {
|
||||||
|
this.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockPosition getPosition() {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
DataTypeIO.writeBlockPosition(output, position);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,27 +1,4 @@
|
||||||
/*
|
package com.loohp.limbo.Server.Packets;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.network.protocol.packets;
|
|
||||||
|
|
||||||
import com.loohp.limbo.registry.PacketRegistry;
|
|
||||||
import com.loohp.limbo.utils.DataTypeIO;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
|
|
@ -29,12 +6,17 @@ import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
|
||||||
public class PacketPlayOutTabComplete extends PacketOut {
|
public class PacketPlayOutTabComplete extends PacketOut {
|
||||||
|
|
||||||
private final int id;
|
private int id;
|
||||||
private final int start;
|
private int start;
|
||||||
private final int length;
|
private int length;
|
||||||
private final TabCompleteMatches[] matches;
|
private TabCompleteMatches[] matches;
|
||||||
|
|
||||||
public PacketPlayOutTabComplete(int id, int start, int length, TabCompleteMatches... matches) {
|
public PacketPlayOutTabComplete(int id, int start, int length, TabCompleteMatches... matches) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
@ -64,7 +46,7 @@ public class PacketPlayOutTabComplete extends PacketOut {
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
DataOutputStream output = new DataOutputStream(buffer);
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
output.writeByte(PacketRegistry.getPacketId(getClass()));
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
DataTypeIO.writeVarInt(output, id);
|
DataTypeIO.writeVarInt(output, id);
|
||||||
DataTypeIO.writeVarInt(output, start);
|
DataTypeIO.writeVarInt(output, start);
|
||||||
DataTypeIO.writeVarInt(output, length);
|
DataTypeIO.writeVarInt(output, length);
|
||||||
|
|
@ -74,7 +56,7 @@ public class PacketPlayOutTabComplete extends PacketOut {
|
||||||
DataTypeIO.writeString(output, match.getMatch(), StandardCharsets.UTF_8);
|
DataTypeIO.writeString(output, match.getMatch(), StandardCharsets.UTF_8);
|
||||||
if (match.getTooltip().isPresent()) {
|
if (match.getTooltip().isPresent()) {
|
||||||
output.writeBoolean(true);
|
output.writeBoolean(true);
|
||||||
DataTypeIO.writeComponent(output, match.getTooltip().get());
|
DataTypeIO.writeString(output, ComponentSerializer.toString(match.getTooltip().get()), StandardCharsets.UTF_8);
|
||||||
} else {
|
} else {
|
||||||
output.writeBoolean(false);
|
output.writeBoolean(false);
|
||||||
}
|
}
|
||||||
|
|
@ -86,23 +68,18 @@ public class PacketPlayOutTabComplete extends PacketOut {
|
||||||
public static class TabCompleteMatches {
|
public static class TabCompleteMatches {
|
||||||
|
|
||||||
private String match;
|
private String match;
|
||||||
private Optional<Component> tooltip;
|
private Optional<BaseComponent[]> tooltip;
|
||||||
|
|
||||||
public TabCompleteMatches(String match) {
|
public TabCompleteMatches(String match, BaseComponent... tooltip) {
|
||||||
this.match = match;
|
this.match = match;
|
||||||
this.tooltip = Optional.empty();
|
this.tooltip = tooltip.length > 0 ? Optional.of(tooltip) : Optional.empty();
|
||||||
}
|
|
||||||
|
|
||||||
public TabCompleteMatches(String match, Component tooltip) {
|
|
||||||
this.match = match;
|
|
||||||
this.tooltip = Optional.ofNullable(tooltip);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMatch() {
|
public String getMatch() {
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Component> getTooltip() {
|
public Optional<BaseComponent[]> getTooltip() {
|
||||||
return tooltip;
|
return tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketPlayOutUpdateViewPosition extends PacketOut {
|
||||||
|
|
||||||
|
private int chunkX;
|
||||||
|
private int chunkZ;
|
||||||
|
|
||||||
|
public PacketPlayOutUpdateViewPosition(int chunkX, int chunkZ) {
|
||||||
|
this.chunkX = chunkX;
|
||||||
|
this.chunkZ = chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChunkX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChunkZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getPlayOut().get(getClass()));
|
||||||
|
DataTypeIO.writeVarInt(output, chunkX);
|
||||||
|
DataTypeIO.writeVarInt(output, chunkZ);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketStatusInPing extends PacketIn {
|
||||||
|
|
||||||
|
private long payload;
|
||||||
|
|
||||||
|
public PacketStatusInPing(long payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketStatusInPing(DataInputStream in) throws IOException {
|
||||||
|
this(in.readLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
|
||||||
|
public class PacketStatusInRequest extends PacketIn {
|
||||||
|
|
||||||
|
public PacketStatusInRequest() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketStatusInRequest(DataInputStream in) {
|
||||||
|
this();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PacketStatusOutPong extends PacketOut {
|
||||||
|
|
||||||
|
private long payload;
|
||||||
|
|
||||||
|
public PacketStatusOutPong(long payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getStatusOut().get(getClass()));
|
||||||
|
output.writeLong(payload);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.loohp.limbo.Server.Packets;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.DataTypeIO;
|
||||||
|
|
||||||
|
public class PacketStatusOutResponse extends PacketOut {
|
||||||
|
|
||||||
|
private String json;
|
||||||
|
|
||||||
|
public PacketStatusOutResponse(String json) {
|
||||||
|
this.json = json;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJson() {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serializePacket() throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
output.writeByte(Packet.getStatusOut().get(getClass()));
|
||||||
|
DataTypeIO.writeString(output, json, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
return buffer.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package com.loohp.limbo.Server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ServerConnection extends Thread {
|
||||||
|
|
||||||
|
private ServerSocket serverSocket;
|
||||||
|
private List<ClientConnection> clients;
|
||||||
|
private String ip;
|
||||||
|
private int port;
|
||||||
|
private KeepAliveSender keepAliveSender;
|
||||||
|
|
||||||
|
public ServerConnection(String ip, int port) {
|
||||||
|
clients = new ArrayList<ClientConnection>();
|
||||||
|
this.ip = ip;
|
||||||
|
this.port = port;
|
||||||
|
start();
|
||||||
|
keepAliveSender = new KeepAliveSender();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
serverSocket = new ServerSocket(port, 50, InetAddress.getByName(ip));
|
||||||
|
System.out.println("Limbo server listening on /" + serverSocket.getInetAddress().getHostName() + ":" + serverSocket.getLocalPort());
|
||||||
|
while (true) {
|
||||||
|
Socket connection = serverSocket.accept();
|
||||||
|
//String str = connection.getInetAddress().getHostName() + ":" + connection.getPort();
|
||||||
|
//System.out.println("[/127.0.0.1:57310] <-> InitialHandler has pinged);
|
||||||
|
ClientConnection sc = new ClientConnection(connection);
|
||||||
|
clients.add(sc);
|
||||||
|
sc.start();
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeepAliveSender getKeepAliveSender() {
|
||||||
|
return keepAliveSender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerSocket getServerSocket() {
|
||||||
|
return serverSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClientConnection> getClients() {
|
||||||
|
return clients;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,29 +1,4 @@
|
||||||
/*
|
package com.loohp.limbo.Utils;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.utils;
|
|
||||||
|
|
||||||
import com.google.common.io.ByteArrayDataInput;
|
|
||||||
import com.google.common.io.ByteArrayDataOutput;
|
|
||||||
import com.google.common.io.ByteStreams;
|
|
||||||
import com.loohp.limbo.network.protocol.packets.PacketPlayOutPluginMessaging;
|
|
||||||
import net.kyori.adventure.key.Key;
|
|
||||||
|
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
@ -31,15 +6,18 @@ import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class BungeeLoginMessageUtils {
|
import com.google.common.io.ByteArrayDataInput;
|
||||||
|
import com.google.common.io.ByteArrayDataOutput;
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
import com.loohp.limbo.Server.Packets.PacketPlayOutPluginMessaging;
|
||||||
|
|
||||||
public static final String BUNGEECORD_MAIN = Key.key("bungeecord", "main").toString();
|
public class BungeeLoginMessageUtils {
|
||||||
|
|
||||||
public static void sendUUIDRequest(DataOutputStream output) throws IOException {
|
public static void sendUUIDRequest(DataOutputStream output) throws IOException {
|
||||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||||
out.writeUTF("UUID");
|
out.writeUTF("UUID");
|
||||||
|
|
||||||
PacketPlayOutPluginMessaging packet = new PacketPlayOutPluginMessaging(BUNGEECORD_MAIN, out.toByteArray());
|
PacketPlayOutPluginMessaging packet = new PacketPlayOutPluginMessaging(new NamespacedKey("bungeecord", "main"), out.toByteArray());
|
||||||
byte[] packetByte = packet.serializePacket();
|
byte[] packetByte = packet.serializePacket();
|
||||||
DataTypeIO.writeVarInt(output, packetByte.length);
|
DataTypeIO.writeVarInt(output, packetByte.length);
|
||||||
output.write(packetByte);
|
output.write(packetByte);
|
||||||
|
|
@ -51,7 +29,7 @@ public class BungeeLoginMessageUtils {
|
||||||
if (subchannel.equals("UUID")) {
|
if (subchannel.equals("UUID")) {
|
||||||
return UUID.fromString(in.readUTF());
|
return UUID.fromString(in.readUTF());
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Bungeecord Message received is not an IP");
|
throw new RuntimeException("Bungeecord Message receieved is not an IP");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,7 +37,7 @@ public class BungeeLoginMessageUtils {
|
||||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||||
out.writeUTF("IP");
|
out.writeUTF("IP");
|
||||||
|
|
||||||
PacketPlayOutPluginMessaging packet = new PacketPlayOutPluginMessaging(BUNGEECORD_MAIN, out.toByteArray());
|
PacketPlayOutPluginMessaging packet = new PacketPlayOutPluginMessaging(new NamespacedKey("bungeecord", "main"), out.toByteArray());
|
||||||
byte[] packetByte = packet.serializePacket();
|
byte[] packetByte = packet.serializePacket();
|
||||||
DataTypeIO.writeVarInt(output, packetByte.length);
|
DataTypeIO.writeVarInt(output, packetByte.length);
|
||||||
output.write(packetByte);
|
output.write(packetByte);
|
||||||
|
|
@ -73,7 +51,7 @@ public class BungeeLoginMessageUtils {
|
||||||
in.readInt();
|
in.readInt();
|
||||||
return InetAddress.getByName(ip);
|
return InetAddress.getByName(ip);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Bungeecord Message received is not an IP");
|
throw new RuntimeException("Bungeecord Message receieved is not an IP");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,23 +1,4 @@
|
||||||
/*
|
package com.loohp.limbo.Utils;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.utils;
|
|
||||||
|
|
||||||
import net.querz.mca.Section;
|
import net.querz.mca.Section;
|
||||||
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.loohp.limbo.Utils;
|
||||||
|
|
||||||
|
public class CustomArrayUtils {
|
||||||
|
|
||||||
|
public static int[] longArrayToIntArray(long[] numbers) {
|
||||||
|
int[] intNumbers = new int[numbers.length];
|
||||||
|
for(int i = 0; i < numbers.length; i++) {
|
||||||
|
intNumbers[i] = (int) numbers[i];
|
||||||
|
}
|
||||||
|
return intNumbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] longArrayToByteArray(long[] numbers) {
|
||||||
|
byte[] intNumbers = new byte[numbers.length];
|
||||||
|
for(int i = 0; i < numbers.length; i++) {
|
||||||
|
intNumbers[i] = (byte) numbers[i];
|
||||||
|
}
|
||||||
|
return intNumbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
package com.loohp.limbo.Utils;
|
||||||
|
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
|
import net.querz.nbt.tag.ByteArrayTag;
|
||||||
|
import net.querz.nbt.tag.ByteTag;
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
import net.querz.nbt.tag.DoubleTag;
|
||||||
|
import net.querz.nbt.tag.FloatTag;
|
||||||
|
import net.querz.nbt.tag.IntArrayTag;
|
||||||
|
import net.querz.nbt.tag.IntTag;
|
||||||
|
import net.querz.nbt.tag.ListTag;
|
||||||
|
import net.querz.nbt.tag.LongArrayTag;
|
||||||
|
import net.querz.nbt.tag.LongTag;
|
||||||
|
import net.querz.nbt.tag.ShortTag;
|
||||||
|
import net.querz.nbt.tag.StringTag;
|
||||||
|
import net.querz.nbt.tag.Tag;
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public class CustomNBTUtils {
|
||||||
|
|
||||||
|
public enum TagClass {
|
||||||
|
CompoundTagClass(CompoundTag.class),
|
||||||
|
ByteTagClass(ByteTag.class),
|
||||||
|
ShortTagClass(ShortTag.class),
|
||||||
|
IntTagClass(IntTag.class),
|
||||||
|
LongTagClass(LongTag.class),
|
||||||
|
FloatTagClass(FloatTag.class),
|
||||||
|
DoubleTagClass(DoubleTag.class),
|
||||||
|
ByteArrayTagClass(ByteArrayTag.class),
|
||||||
|
IntArrayTagClass(IntArrayTag.class),
|
||||||
|
LongArrayTagClass(LongArrayTag.class),
|
||||||
|
StringTagClass(StringTag.class),
|
||||||
|
ListTagClass(ListTag.class);
|
||||||
|
|
||||||
|
Class<? extends Tag> clazz;
|
||||||
|
|
||||||
|
TagClass(Class<? extends Tag> clazz) {
|
||||||
|
this.clazz = clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends Tag> getTagClass() {
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<? extends Tag> getClassFromName(String name) {
|
||||||
|
for (TagClass clazz : TagClass.values()) {
|
||||||
|
if (clazz.getTagClass().getSimpleName().equals(name)) {
|
||||||
|
return clazz.getTagClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag getCompoundTagFromJson(JSONObject json) {
|
||||||
|
CompoundTag tag = new CompoundTag();
|
||||||
|
|
||||||
|
for (Object obj : json.keySet()) {
|
||||||
|
String key = (String) obj;
|
||||||
|
JSONObject inside = (JSONObject) json.get(key);
|
||||||
|
String type = (String) inside.get("type");
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "ByteTag":
|
||||||
|
tag.putByte(key, (byte) (long) inside.get("value"));
|
||||||
|
break;
|
||||||
|
case "ShortTag":
|
||||||
|
tag.putShort(key, (short) (long) inside.get("value"));
|
||||||
|
break;
|
||||||
|
case "IntTag":
|
||||||
|
tag.putInt(key, (int) (long) inside.get("value"));
|
||||||
|
break;
|
||||||
|
case "LongTag":
|
||||||
|
tag.putLong(key, (long) inside.get("value"));
|
||||||
|
break;
|
||||||
|
case "FloatTag":
|
||||||
|
tag.putFloat(key, inside.get("value") instanceof Long ? (float) (long) inside.get("value") : (float) (double) inside.get("value"));
|
||||||
|
break;
|
||||||
|
case "DoubleTag":
|
||||||
|
tag.putDouble(key, inside.get("value") instanceof Long ? (double) (long) inside.get("value") : (double) inside.get("value"));
|
||||||
|
break;
|
||||||
|
case "ByteArrayTag":
|
||||||
|
tag.putByteArray(key, CustomArrayUtils.longArrayToByteArray((long[]) inside.get("value")));
|
||||||
|
break;
|
||||||
|
case "IntArrayTag":
|
||||||
|
tag.putIntArray(key, CustomArrayUtils.longArrayToIntArray((long[]) inside.get("value")));
|
||||||
|
break;
|
||||||
|
case "LongArrayTag":
|
||||||
|
tag.putLongArray(key, (long[]) inside.get("value"));
|
||||||
|
break;
|
||||||
|
case "StringTag":
|
||||||
|
tag.putString(key, (String) inside.get("value"));
|
||||||
|
break;
|
||||||
|
case "CompoundTag":
|
||||||
|
tag.put(key, getCompoundTagFromJson((JSONObject) inside.get("value")));
|
||||||
|
break;
|
||||||
|
case "ListTag":
|
||||||
|
tag.put(key, getListTagFromJson((JSONObject) inside.get("value")));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ListTag<?> getListTagFromJson(JSONObject json) {
|
||||||
|
String type = (String) json.get("type");
|
||||||
|
JSONArray array = (JSONArray) json.get("list");
|
||||||
|
|
||||||
|
ListTag<?> listTag = ListTag.createUnchecked(getClassFromName(type));
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case "ByteTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addByte((byte) (long) obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ShortTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addShort((short) (long) obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "IntTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addInt((int) (long) obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "LongTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addLong((long) obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "FloatTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addFloat(obj instanceof Long ? (float) (long) obj : (float) (double) obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "DoubleTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addDouble(obj instanceof Long ? (double) (long) obj : (double) obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ByteArrayTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addByteArray(CustomArrayUtils.longArrayToByteArray((long[]) obj));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "IntArrayTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addIntArray(CustomArrayUtils.longArrayToIntArray((long[]) obj));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "LongArrayTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addLongArray((long[]) obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "StringTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.addString((String) obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "CompoundTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.asCompoundTagList().add(getCompoundTagFromJson((JSONObject) obj));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "ListTag":
|
||||||
|
for (Object obj : array) {
|
||||||
|
listTag.asListTagList().add(getListTagFromJson((JSONObject) obj));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return listTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,23 +1,4 @@
|
||||||
/*
|
package com.loohp.limbo.Utils;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.utils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
package com.loohp.limbo.Utils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import com.loohp.limbo.World.BlockPosition;
|
||||||
|
|
||||||
|
import net.querz.nbt.io.NBTOutputStream;
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
import net.querz.nbt.tag.Tag;
|
||||||
|
|
||||||
|
public class DataTypeIO {
|
||||||
|
|
||||||
|
public static void writeBlockPosition(DataOutputStream out, BlockPosition position) throws IOException {
|
||||||
|
out.writeLong(((position.getX() & 0x3FFFFFF) << 38) | ((position.getZ() & 0x3FFFFFF) << 12) | (position.getY() & 0xFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeUUID(DataOutputStream out, UUID uuid) throws IOException {
|
||||||
|
out.writeLong(uuid.getMostSignificantBits());
|
||||||
|
out.writeLong(uuid.getLeastSignificantBits());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeCompoundTag(DataOutputStream out, CompoundTag tag) throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
DataOutputStream output = new DataOutputStream(buffer);
|
||||||
|
new NBTOutputStream(output).writeTag(tag, Tag.DEFAULT_MAX_DEPTH);
|
||||||
|
|
||||||
|
byte[] b = buffer.toByteArray();
|
||||||
|
out.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String readString(DataInputStream in) throws IOException {
|
||||||
|
int length = readVarInt(in);
|
||||||
|
|
||||||
|
if (length == -1) {
|
||||||
|
throw new IOException("Premature end of stream.");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] b = new byte[length];
|
||||||
|
in.readFully(b);
|
||||||
|
return new String(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getStringLength(String string, Charset charset) throws IOException {
|
||||||
|
byte[] bytes = string.getBytes(charset);
|
||||||
|
return bytes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeString(DataOutputStream out, String string, Charset charset) throws IOException {
|
||||||
|
byte[] bytes = string.getBytes(charset);
|
||||||
|
writeVarInt(out, bytes.length);
|
||||||
|
out.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int readVarInt(DataInputStream in) throws IOException {
|
||||||
|
int numRead = 0;
|
||||||
|
int result = 0;
|
||||||
|
byte read;
|
||||||
|
do {
|
||||||
|
read = in.readByte();
|
||||||
|
int value = (read & 0b01111111);
|
||||||
|
result |= (value << (7 * numRead));
|
||||||
|
|
||||||
|
numRead++;
|
||||||
|
if (numRead > 5) {
|
||||||
|
throw new RuntimeException("VarInt is too big");
|
||||||
|
}
|
||||||
|
} while ((read & 0b10000000) != 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeVarInt(DataOutputStream out, int value) throws IOException {
|
||||||
|
do {
|
||||||
|
byte temp = (byte)(value & 0b01111111);
|
||||||
|
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
|
||||||
|
value >>>= 7;
|
||||||
|
if (value != 0) {
|
||||||
|
temp |= 0b10000000;
|
||||||
|
}
|
||||||
|
out.writeByte(temp);
|
||||||
|
} while (value != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getVarIntLength(int value) throws IOException {
|
||||||
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream out = new DataOutputStream(buffer);
|
||||||
|
do {
|
||||||
|
byte temp = (byte)(value & 0b01111111);
|
||||||
|
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
|
||||||
|
value >>>= 7;
|
||||||
|
if (value != 0) {
|
||||||
|
temp |= 0b10000000;
|
||||||
|
}
|
||||||
|
out.writeByte(temp);
|
||||||
|
} while (value != 0);
|
||||||
|
return buffer.toByteArray().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long readVarLong(DataInputStream in) throws IOException {
|
||||||
|
int numRead = 0;
|
||||||
|
long result = 0;
|
||||||
|
byte read;
|
||||||
|
do {
|
||||||
|
read = in.readByte();
|
||||||
|
long value = (read & 0b01111111);
|
||||||
|
result |= (value << (7 * numRead));
|
||||||
|
|
||||||
|
numRead++;
|
||||||
|
if (numRead > 10) {
|
||||||
|
throw new RuntimeException("VarLong is too big");
|
||||||
|
}
|
||||||
|
} while ((read & 0b10000000) != 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeVarLong(DataOutputStream out, long value) throws IOException {
|
||||||
|
do {
|
||||||
|
byte temp = (byte)(value & 0b01111111);
|
||||||
|
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
|
||||||
|
value >>>= 7;
|
||||||
|
if (value != 0) {
|
||||||
|
temp |= 0b10000000;
|
||||||
|
}
|
||||||
|
out.writeByte(temp);
|
||||||
|
} while (value != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.loohp.limbo.Utils;
|
||||||
|
|
||||||
|
public enum GameMode {
|
||||||
|
|
||||||
|
SURVIVAL(0, "survival"),
|
||||||
|
CREATIVE(1, "creative"),
|
||||||
|
ADVENTURE(2, "adventure"),
|
||||||
|
SPECTATOR(3, "spectator");
|
||||||
|
|
||||||
|
int id;
|
||||||
|
String name;
|
||||||
|
|
||||||
|
GameMode(int id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameMode fromId(int id) {
|
||||||
|
for (GameMode mode : GameMode.values()) {
|
||||||
|
if (mode.getId() == id) {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GameMode fromName(String name) {
|
||||||
|
for (GameMode mode : GameMode.values()) {
|
||||||
|
if (mode.getName().equalsIgnoreCase(name)) {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.loohp.limbo.Utils;
|
||||||
|
|
||||||
|
import java.awt.image.RenderedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
public class ImageUtils {
|
||||||
|
|
||||||
|
public static String imgToBase64String(final RenderedImage img, String formatName) throws IOException {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ImageIO.write(img, formatName, out);
|
||||||
|
return Base64.getEncoder().encodeToString(out.toByteArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,5 @@
|
||||||
/*
|
package com.loohp.limbo.Utils;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.utils;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
@ -27,6 +7,8 @@ import java.net.URL;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
|
|
||||||
public class MojangAPIUtils {
|
public class MojangAPIUtils {
|
||||||
|
|
||||||
public static class SkinResponse {
|
public static class SkinResponse {
|
||||||
|
|
@ -59,7 +41,7 @@ public class MojangAPIUtils {
|
||||||
connection.addRequestProperty("Cache-Control", "no-cache, no-store, must-revalidate");
|
connection.addRequestProperty("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||||
connection.addRequestProperty("Pragma", "no-cache");
|
connection.addRequestProperty("Pragma", "no-cache");
|
||||||
if (connection.getResponseCode() == HttpsURLConnection.HTTP_OK) {
|
if (connection.getResponseCode() == HttpsURLConnection.HTTP_OK) {
|
||||||
String reply = new BufferedReader(new InputStreamReader(connection.getInputStream())).lines().collect(Collectors.joining()).replace(" ", "");
|
String reply = new BufferedReader(new InputStreamReader(connection.getInputStream())).readLine();
|
||||||
if (!reply.contains("\"error\":\"BadRequestException\"")) {
|
if (!reply.contains("\"error\":\"BadRequestException\"")) {
|
||||||
String uuid = reply.split("\"id\":\"")[1].split("\"")[0];
|
String uuid = reply.split("\"id\":\"")[1].split("\"")[0];
|
||||||
return UUID.fromString(uuid.replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"));
|
return UUID.fromString(uuid.replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"));
|
||||||
|
|
@ -67,7 +49,7 @@ public class MojangAPIUtils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
System.err.println("Connection could not be opened (Response code " + connection.getResponseCode() + ", " + connection.getResponseMessage() + ")");
|
System.out.println("Connection could not be opened (Response code " + connection.getResponseCode() + ", " + connection.getResponseMessage() + ")");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
@ -94,12 +76,12 @@ public class MojangAPIUtils {
|
||||||
connection.addRequestProperty("Cache-Control", "no-cache, no-store, must-revalidate");
|
connection.addRequestProperty("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||||
connection.addRequestProperty("Pragma", "no-cache");
|
connection.addRequestProperty("Pragma", "no-cache");
|
||||||
if (connection.getResponseCode() == HttpsURLConnection.HTTP_OK) {
|
if (connection.getResponseCode() == HttpsURLConnection.HTTP_OK) {
|
||||||
String reply = new BufferedReader(new InputStreamReader(connection.getInputStream())).lines().collect(Collectors.joining("")).replace(" ", "");
|
String reply = String.join("", new BufferedReader(new InputStreamReader(connection.getInputStream())).lines().collect(Collectors.toList())).replace(" ", "");
|
||||||
String skin = reply.split("\"value\":\"")[1].split("\"")[0];
|
String skin = reply.split("\"value\":\"")[1].split("\"")[0];
|
||||||
String signature = reply.split("\"signature\":\"")[1].split("\"")[0];
|
String signature = reply.split("\"signature\":\"")[1].split("\"")[0];
|
||||||
return new SkinResponse(skin, signature);
|
return new SkinResponse(skin, signature);
|
||||||
} else {
|
} else {
|
||||||
System.err.println("Connection could not be opened (Response code " + connection.getResponseCode() + ", " + connection.getResponseMessage() + ")");
|
System.out.println("Connection could not be opened (Response code " + connection.getResponseCode() + ", " + connection.getResponseMessage() + ")");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.loohp.limbo.Utils;
|
||||||
|
|
||||||
|
public class NamespacedKey {
|
||||||
|
|
||||||
|
String namespace;
|
||||||
|
String key;
|
||||||
|
|
||||||
|
public NamespacedKey(String namespacedKey) {
|
||||||
|
int index = namespacedKey.indexOf(":");
|
||||||
|
if (index >= 0) {
|
||||||
|
this.namespace = namespacedKey.substring(0, index);
|
||||||
|
this.key = namespacedKey.substring(index + 1);
|
||||||
|
} else {
|
||||||
|
this.namespace = "minecraft";
|
||||||
|
this.key = namespacedKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey(String namespace, String key) {
|
||||||
|
this.namespace = namespace;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNamespace() {
|
||||||
|
return namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return namespace + ":" + key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((key == null) ? 0 : key.hashCode());
|
||||||
|
result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
NamespacedKey other = (NamespacedKey) obj;
|
||||||
|
if (key == null) {
|
||||||
|
if (other.key != null)
|
||||||
|
return false;
|
||||||
|
} else if (!key.equals(other.key))
|
||||||
|
return false;
|
||||||
|
if (namespace == null) {
|
||||||
|
if (other.namespace != null)
|
||||||
|
return false;
|
||||||
|
} else if (!namespace.equals(other.namespace))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,23 +1,4 @@
|
||||||
/*
|
package com.loohp.limbo.Utils;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.utils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.loohp.limbo.Utils;
|
||||||
|
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
|
||||||
|
public class SchematicConvertionUtils {
|
||||||
|
|
||||||
|
public static CompoundTag toTileEntityTag(CompoundTag tag) {
|
||||||
|
int[] pos = tag.getIntArray("Pos");
|
||||||
|
tag.remove("Pos");
|
||||||
|
tag.remove("Id");
|
||||||
|
tag.putInt("x", pos[0]);
|
||||||
|
tag.putInt("y", pos[1]);
|
||||||
|
tag.putInt("z", pos[2]);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag toBlockTag(String input) {
|
||||||
|
int index = input.indexOf("[");
|
||||||
|
CompoundTag tag = new CompoundTag();
|
||||||
|
if (index < 0) {
|
||||||
|
tag.putString("Name", new NamespacedKey(input).toString());
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.putString("Name", new NamespacedKey(input.substring(0, index)).toString());
|
||||||
|
|
||||||
|
String[] states = input.substring(index + 1, input.lastIndexOf("]")).replace(" ", "").split(",");
|
||||||
|
|
||||||
|
CompoundTag properties = new CompoundTag();
|
||||||
|
for (String state : states) {
|
||||||
|
String key = state.substring(0, state.indexOf("="));
|
||||||
|
String value = state.substring(state.indexOf("=") + 1);
|
||||||
|
properties.putString(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
tag.put("Properties", properties);
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,32 +1,4 @@
|
||||||
/*
|
package com.loohp.limbo.Utils;
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo.utils;
|
|
||||||
|
|
||||||
import org.yaml.snakeyaml.error.YAMLException;
|
|
||||||
import org.yaml.snakeyaml.introspector.BeanAccess;
|
|
||||||
import org.yaml.snakeyaml.introspector.FieldProperty;
|
|
||||||
import org.yaml.snakeyaml.introspector.MethodProperty;
|
|
||||||
import org.yaml.snakeyaml.introspector.MissingProperty;
|
|
||||||
import org.yaml.snakeyaml.introspector.Property;
|
|
||||||
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
|
||||||
import org.yaml.snakeyaml.util.PlatformFeatureDetector;
|
|
||||||
|
|
||||||
import java.beans.FeatureDescriptor;
|
import java.beans.FeatureDescriptor;
|
||||||
import java.beans.IntrospectionException;
|
import java.beans.IntrospectionException;
|
||||||
|
|
@ -42,6 +14,15 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.yaml.snakeyaml.error.YAMLException;
|
||||||
|
import org.yaml.snakeyaml.introspector.BeanAccess;
|
||||||
|
import org.yaml.snakeyaml.introspector.FieldProperty;
|
||||||
|
import org.yaml.snakeyaml.introspector.MethodProperty;
|
||||||
|
import org.yaml.snakeyaml.introspector.MissingProperty;
|
||||||
|
import org.yaml.snakeyaml.introspector.Property;
|
||||||
|
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
||||||
|
import org.yaml.snakeyaml.util.PlatformFeatureDetector;
|
||||||
|
|
||||||
public class YamlOrder extends PropertyUtils {
|
public class YamlOrder extends PropertyUtils {
|
||||||
|
|
||||||
private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>();
|
private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>();
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.loohp.limbo.World;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Location.Location;
|
||||||
|
|
||||||
|
public class BlockPosition {
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
private int z;
|
||||||
|
|
||||||
|
public BlockPosition(int x, int y, int z) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return this.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getY() {
|
||||||
|
return this.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZ() {
|
||||||
|
return this.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BlockPosition from(Location location) {
|
||||||
|
return new BlockPosition((int) Math.floor(location.getX()), (int) Math.floor(location.getY()), (int) Math.floor(location.getZ()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.loohp.limbo.World;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
import com.loohp.limbo.Utils.CustomNBTUtils;
|
||||||
|
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
|
||||||
|
public class DimensionRegistry {
|
||||||
|
|
||||||
|
public static CompoundTag defaultTag;
|
||||||
|
private static File reg;
|
||||||
|
|
||||||
|
static {
|
||||||
|
String reg = "dimension_registry.json";
|
||||||
|
File file = new File(Limbo.getInstance().getInternalDataFolder(), reg);
|
||||||
|
if (!file.exists()) {
|
||||||
|
try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream(reg)) {
|
||||||
|
Files.copy(in, file.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DimensionRegistry.reg = file;
|
||||||
|
|
||||||
|
resetTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resetTag() {
|
||||||
|
try {
|
||||||
|
JSONObject json = (JSONObject) new JSONParser().parse(new FileReader(reg));
|
||||||
|
CompoundTag tag = CustomNBTUtils.getCompoundTagFromJson((JSONObject) json.get("value"));
|
||||||
|
defaultTag = tag;
|
||||||
|
} catch (IOException | ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompoundTag getCodec() {
|
||||||
|
return defaultTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
package com.loohp.limbo.World;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Limbo;
|
||||||
|
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
|
||||||
|
public class GeneratedBlockDataMappings {
|
||||||
|
|
||||||
|
private static JSONObject globalPalette = new JSONObject();
|
||||||
|
|
||||||
|
static {
|
||||||
|
String block = "blocks.json";
|
||||||
|
File file = new File(Limbo.getInstance().getInternalDataFolder(), block);
|
||||||
|
if (!file.exists()) {
|
||||||
|
try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream(block)) {
|
||||||
|
Files.copy(in, file.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
globalPalette = (JSONObject) new JSONParser().parse(new FileReader(file));
|
||||||
|
} catch (IOException | ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static int getGlobalPaletteIDFromState(CompoundTag tag) {
|
||||||
|
String blockname = tag.getString("Name");
|
||||||
|
|
||||||
|
JSONObject data = (JSONObject) globalPalette.get(blockname);
|
||||||
|
Object obj = data.get("properties");
|
||||||
|
if (obj == null) {
|
||||||
|
return (int) (long) ((JSONObject) ((JSONArray) data.get("states")).get(0)).get("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
//JSONObject properties = (JSONObject) obj;
|
||||||
|
|
||||||
|
if (tag.containsKey("Properties")) {
|
||||||
|
CompoundTag blockProp = tag.get("Properties", CompoundTag.class);
|
||||||
|
Map<String, String> blockstate = new HashMap<>();
|
||||||
|
for (String key : blockProp.keySet()) {
|
||||||
|
blockstate.put(key, blockProp.getString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object entry : (JSONArray) data.get("states")) {
|
||||||
|
JSONObject jsonobj = (JSONObject) entry;
|
||||||
|
if (((JSONObject) jsonobj.get("properties")).keySet().stream().allMatch(key -> blockstate.get(key).equals((String) (((JSONObject) jsonobj.get("properties")).get(key))))) {
|
||||||
|
return (int) (long) jsonobj.get("id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Object entry : (JSONArray) data.get("states")) {
|
||||||
|
if (((JSONObject) entry).containsKey("default") && ((boolean) ((JSONObject) entry).get("default"))) {
|
||||||
|
return (int) (long) ((JSONObject) entry).get("id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.loohp.limbo.World;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.SchematicConvertionUtils;
|
||||||
|
import com.loohp.limbo.World.World.Environment;
|
||||||
|
|
||||||
|
import net.querz.mca.Chunk;
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
import net.querz.nbt.tag.ListTag;
|
||||||
|
|
||||||
|
|
||||||
|
public class Schematic {
|
||||||
|
|
||||||
|
public static World toWorld(String name, Environment environment, CompoundTag nbt) {
|
||||||
|
short width = nbt.getShort("Width");
|
||||||
|
short length = nbt.getShort("Length");
|
||||||
|
short height = nbt.getShort("Height");
|
||||||
|
byte[] blocks = nbt.getByteArray("BlockData");
|
||||||
|
CompoundTag palette = nbt.getCompoundTag("Palette");
|
||||||
|
ListTag<CompoundTag> blockEntities = nbt.getListTag("BlockEntities").asTypedList(CompoundTag.class);
|
||||||
|
Map<Integer, String> mapping = new HashMap<>();
|
||||||
|
for (String key : palette.keySet()) {
|
||||||
|
mapping.put(palette.getInt(key), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
World world = new World(name, width, length, environment);
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int z = 0; z < length; z++) {
|
||||||
|
int blockIndex = x + z * width + y * width * length;
|
||||||
|
world.setBlock(x, y, z, mapping.get(blocks[blockIndex] < 0 ? blocks[blockIndex] + 256 : blocks[blockIndex]));
|
||||||
|
Chunk chunk = world.getChunkAtWorldPos(x, z);
|
||||||
|
|
||||||
|
Iterator<CompoundTag> itr = blockEntities.iterator();
|
||||||
|
while (itr.hasNext()) {
|
||||||
|
CompoundTag tag = itr.next();
|
||||||
|
int[] pos = tag.getIntArray("Pos");
|
||||||
|
|
||||||
|
if (pos[0] == x && pos[1] == y && pos[2] == z) {
|
||||||
|
ListTag<CompoundTag> newTag = chunk.getTileEntities();
|
||||||
|
newTag.add(SchematicConvertionUtils.toTileEntityTag(tag));
|
||||||
|
chunk.setTileEntities(newTag);
|
||||||
|
itr.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Chunk[] chunkarray : world.getChunks()) {
|
||||||
|
for (Chunk chunk : chunkarray) {
|
||||||
|
if (chunk != null) {
|
||||||
|
CompoundTag heightMap = new CompoundTag();
|
||||||
|
heightMap.putLongArray("MOTION_BLOCKING", new long[] {1371773531765642314L,1389823183635651148L,1371738278539598925L,1389823183635388492L,1353688558756731469L,1389823114781694027L,1317765589597723213L,1371773531899860042L,1389823183635651149L,1371773462911685197L,1389823183635650636L,1353688626805119565L,1371773531900123211L,1335639250618849869L,1371738278674077258L,1389823114781694028L,1353723811310638154L,1371738278674077259L,1335674228429068364L,1335674228429067338L,1335674228698027594L,1317624576693539402L,1335709481520370249L,1299610178184057417L,1335638906349064264L,1299574993811968586L,1299574924958011464L,1299610178184056904L,1299574924958011464L,1299610109330100296L,1299574924958011464L,1299574924823793736L,1299574924958011465L,1281525273222484040L,1299574924958011464L,1281525273222484040L,9548107335L});
|
||||||
|
chunk.setHeightMaps(heightMap);
|
||||||
|
chunk.setBiomes(new int[256]);
|
||||||
|
//chunk.cleanupPalettesAndBlockStates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.loohp.limbo.World;
|
||||||
|
|
||||||
|
import com.loohp.limbo.Utils.NamespacedKey;
|
||||||
|
import com.loohp.limbo.Utils.SchematicConvertionUtils;
|
||||||
|
|
||||||
|
import net.querz.mca.Chunk;
|
||||||
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
import net.querz.nbt.tag.ListTag;
|
||||||
|
|
||||||
|
public class World {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private Environment environment;
|
||||||
|
private Chunk[][] chunks;
|
||||||
|
|
||||||
|
public World(String name, int width, int length, Environment environment) {
|
||||||
|
this.name = name;
|
||||||
|
this.environment = environment;
|
||||||
|
this.chunks = new Chunk[(width >> 4) + 1][(length >> 4) + 1];
|
||||||
|
|
||||||
|
for (int x = 0; x < chunks.length; x++) {
|
||||||
|
for (int z = 0; z < chunks[x].length; z++) {
|
||||||
|
chunks[x][z] = Chunk.newChunk();
|
||||||
|
Chunk chunk = chunks[x][z];
|
||||||
|
chunk.cleanupPalettesAndBlockStates();
|
||||||
|
CompoundTag heightMap = new CompoundTag();
|
||||||
|
heightMap.putLongArray("MOTION_BLOCKING",
|
||||||
|
new long[] { 1371773531765642314L, 1389823183635651148L, 1371738278539598925L,
|
||||||
|
1389823183635388492L, 1353688558756731469L, 1389823114781694027L, 1317765589597723213L,
|
||||||
|
1371773531899860042L, 1389823183635651149L, 1371773462911685197L, 1389823183635650636L,
|
||||||
|
1353688626805119565L, 1371773531900123211L, 1335639250618849869L, 1371738278674077258L,
|
||||||
|
1389823114781694028L, 1353723811310638154L, 1371738278674077259L, 1335674228429068364L,
|
||||||
|
1335674228429067338L, 1335674228698027594L, 1317624576693539402L, 1335709481520370249L,
|
||||||
|
1299610178184057417L, 1335638906349064264L, 1299574993811968586L, 1299574924958011464L,
|
||||||
|
1299610178184056904L, 1299574924958011464L, 1299610109330100296L, 1299574924958011464L,
|
||||||
|
1299574924823793736L, 1299574924958011465L, 1281525273222484040L, 1299574924958011464L,
|
||||||
|
1281525273222484040L, 9548107335L });
|
||||||
|
chunk.setHeightMaps(heightMap);
|
||||||
|
chunk.setBiomes(new int[256]);
|
||||||
|
chunk.setTileEntities(new ListTag<CompoundTag>(CompoundTag.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlock(int x, int y, int z, String blockdata) {
|
||||||
|
Chunk chunk = this.chunks[(x >> 4)][(z >> 4)];
|
||||||
|
if (chunk == null) {
|
||||||
|
chunk = Chunk.newChunk();
|
||||||
|
this.chunks[(x >> 4)][(z >> 4)] = chunk;
|
||||||
|
}
|
||||||
|
CompoundTag block = SchematicConvertionUtils.toBlockTag(blockdata);
|
||||||
|
chunk.setBlockStateAt(x, y, z, block, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chunk[][] getChunks() {
|
||||||
|
return this.chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chunk getChunkAtWorldPos(int x, int z) {
|
||||||
|
return this.chunks[(x >> 4)][(z >> 4)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment getEnvironment() {
|
||||||
|
return environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Environment {
|
||||||
|
NORMAL(new NamespacedKey("minecraft:overworld")),
|
||||||
|
NETHER(new NamespacedKey("minecraft:the_nether")),
|
||||||
|
END(new NamespacedKey("minecraft:the_end"));
|
||||||
|
|
||||||
|
NamespacedKey key;
|
||||||
|
|
||||||
|
Environment(NamespacedKey key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NamespacedKey getNamespacedKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Environment fromNamespacedKey(NamespacedKey key) {
|
||||||
|
for (Environment each : Environment.values()) {
|
||||||
|
if (each.getNamespacedKey().equals(key)) {
|
||||||
|
return each;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,590 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo;
|
|
||||||
|
|
||||||
import com.loohp.limbo.commands.CommandSender;
|
|
||||||
import com.loohp.limbo.consolegui.ConsoleTextOutput;
|
|
||||||
import com.loohp.limbo.utils.CustomStringUtils;
|
|
||||||
import jline.console.ConsoleReader;
|
|
||||||
import net.kyori.adventure.audience.MessageType;
|
|
||||||
import net.kyori.adventure.bossbar.BossBar;
|
|
||||||
import net.kyori.adventure.identity.Identity;
|
|
||||||
import net.kyori.adventure.inventory.Book;
|
|
||||||
import net.kyori.adventure.sound.Sound;
|
|
||||||
import net.kyori.adventure.sound.Sound.Emitter;
|
|
||||||
import net.kyori.adventure.sound.SoundStop;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
|
||||||
import net.kyori.adventure.title.TitlePart;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
|
||||||
import org.fusesource.jansi.Ansi;
|
|
||||||
import org.fusesource.jansi.Ansi.Attribute;
|
|
||||||
import org.jline.reader.Candidate;
|
|
||||||
import org.jline.reader.Completer;
|
|
||||||
import org.jline.reader.EndOfFileException;
|
|
||||||
import org.jline.reader.LineReader;
|
|
||||||
import org.jline.reader.LineReader.SuggestionType;
|
|
||||||
import org.jline.reader.LineReaderBuilder;
|
|
||||||
import org.jline.reader.ParsedLine;
|
|
||||||
import org.jline.reader.UserInterruptException;
|
|
||||||
import org.jline.terminal.Terminal;
|
|
||||||
import org.jline.terminal.TerminalBuilder;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class Console implements CommandSender {
|
|
||||||
|
|
||||||
protected static final Map<ChatColor, String> REPLACEMENTS = new HashMap<>();
|
|
||||||
private final static String CONSOLE = "CONSOLE";
|
|
||||||
private final static String PROMPT = "> ";
|
|
||||||
protected final static String ERROR_RED = "\u001B[31;1m";
|
|
||||||
protected final static String RESET_COLOR = "\u001B[0m";
|
|
||||||
|
|
||||||
private final Terminal terminal;
|
|
||||||
private final LineReader tabReader;
|
|
||||||
private final ConsoleReader reader;
|
|
||||||
|
|
||||||
private final InputStream in;
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final PrintStream out;
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final PrintStream err;
|
|
||||||
protected final PrintStream logs;
|
|
||||||
|
|
||||||
public Console(InputStream in, PrintStream out, PrintStream err) throws IOException {
|
|
||||||
String fileName = new SimpleDateFormat("yyyy'-'MM'-'dd'_'HH'-'mm'-'ss'_'zzz'.log'").format(new Date()).replace(":", "");
|
|
||||||
File dir = new File("logs");
|
|
||||||
dir.mkdirs();
|
|
||||||
File logs = new File(dir, fileName);
|
|
||||||
this.logs = new PrintStream(Files.newOutputStream(logs.toPath()), true, StandardCharsets.UTF_8.toString());
|
|
||||||
|
|
||||||
if (in != null) {
|
|
||||||
System.setIn(in);
|
|
||||||
this.in = System.in;
|
|
||||||
} else {
|
|
||||||
this.in = null;
|
|
||||||
}
|
|
||||||
System.setOut(new ConsoleOutputStream(this, out == null ? new PrintStream(new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) {
|
|
||||||
//DO NOTHING
|
|
||||||
}
|
|
||||||
}) : out, this.logs));
|
|
||||||
this.out = System.out;
|
|
||||||
|
|
||||||
System.setErr(new ConsoleErrorStream(this, err == null ? new PrintStream(new OutputStream() {
|
|
||||||
@Override
|
|
||||||
public void write(int b) {
|
|
||||||
//DO NOTHING
|
|
||||||
}
|
|
||||||
}) : err, this.logs));
|
|
||||||
this.err = System.err;
|
|
||||||
|
|
||||||
reader = new ConsoleReader(in, out);
|
|
||||||
reader.setExpandEvents(false);
|
|
||||||
reader.setHandleUserInterrupt(false);
|
|
||||||
|
|
||||||
terminal = TerminalBuilder.builder().streams(in, out).system(true).jansi(true).build();
|
|
||||||
tabReader = LineReaderBuilder.builder().terminal(terminal).completer(new Completer() {
|
|
||||||
@Override
|
|
||||||
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
|
|
||||||
String[] args = CustomStringUtils.splitStringToArgs(line.line());
|
|
||||||
List<String> tab = Limbo.getInstance().getPluginManager().getTabOptions(Limbo.getInstance().getConsole(), args);
|
|
||||||
for (String each : tab) {
|
|
||||||
candidates.add(new Candidate(each));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).build();
|
|
||||||
tabReader.setAutosuggestion(SuggestionType.NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return CONSOLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasPermission(String permission) {
|
|
||||||
return Limbo.getInstance().getPermissionsManager().hasPermission(this, permission);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@Override
|
|
||||||
public void sendMessage(BaseComponent component, UUID uuid) {
|
|
||||||
sendMessage(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@Override
|
|
||||||
public void sendMessage(BaseComponent[] component, UUID uuid) {
|
|
||||||
sendMessage(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessage(String message, UUID uuid) {
|
|
||||||
sendMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@Override
|
|
||||||
public void sendMessage(BaseComponent component) {
|
|
||||||
sendMessage(new BaseComponent[] {component});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
@Override
|
|
||||||
public void sendMessage(BaseComponent[] component) {
|
|
||||||
sendMessage(String.join("", Arrays.asList(component).stream().map(each -> each.toLegacyText()).collect(Collectors.toList())));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessage(Identity source, Component message, MessageType type) {
|
|
||||||
sendMessage(PlainTextComponentSerializer.plainText().serialize(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void openBook(Book book) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stopSound(SoundStop stop) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void playSound(Sound sound, Emitter emitter) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void playSound(Sound sound, double x, double y, double z) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void playSound(Sound sound) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendActionBar(Component message) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendPlayerListHeaderAndFooter(Component header, Component footer) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void sendTitlePart(TitlePart<T> part, T value) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearTitle() {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resetTitle() {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showBossBar(BossBar bar) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void hideBossBar(BossBar bar) {
|
|
||||||
//ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessage(String message) {
|
|
||||||
stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + message), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info] " + message));
|
|
||||||
try {
|
|
||||||
reader.getOutput().append("[" + date + " Info] " + translateToConsole(message) + "\n");
|
|
||||||
reader.getOutput().flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void run() {
|
|
||||||
if (in == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
String command = tabReader.readLine(PROMPT).trim();
|
|
||||||
if (!command.isEmpty()) {
|
|
||||||
String[] input = CustomStringUtils.splitStringToArgs(command);
|
|
||||||
new Thread(() -> Limbo.getInstance().dispatchCommand(this, input)).start();
|
|
||||||
}
|
|
||||||
} catch (UserInterruptException e) {
|
|
||||||
System.exit(0);
|
|
||||||
} catch (EndOfFileException e) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void stashLine() {
|
|
||||||
try {
|
|
||||||
tabReader.callWidget(LineReader.CLEAR);
|
|
||||||
} catch (Exception ignore) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void unstashLine() {
|
|
||||||
try {
|
|
||||||
tabReader.callWidget(LineReader.REDRAW_LINE);
|
|
||||||
tabReader.callWidget(LineReader.REDISPLAY);
|
|
||||||
tabReader.getTerminal().writer().flush();
|
|
||||||
} catch (Exception ignore) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static {
|
|
||||||
REPLACEMENTS.put(ChatColor.BLACK, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.DARK_BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.DARK_GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.DARK_AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.DARK_RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.DARK_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.GOLD, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.DARK_GRAY, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.BLUE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.GREEN, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.AQUA, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.RED, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.RED).bold().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.LIGHT_PURPLE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.YELLOW, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.WHITE, Ansi.ansi().a(Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.MAGIC, Ansi.ansi().a(Attribute.BLINK_SLOW).toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.BOLD, Ansi.ansi().a(Attribute.UNDERLINE_DOUBLE).toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.STRIKETHROUGH, Ansi.ansi().a(Attribute.STRIKETHROUGH_ON).toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.UNDERLINE, Ansi.ansi().a(Attribute.UNDERLINE).toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.ITALIC, Ansi.ansi().a(Attribute.ITALIC).toString());
|
|
||||||
REPLACEMENTS.put(ChatColor.RESET, Ansi.ansi().a(Attribute.RESET).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static String translateToConsole(String str) {
|
|
||||||
for (Entry<ChatColor, String> entry : REPLACEMENTS.entrySet()) {
|
|
||||||
str = str.replace(entry.getKey().toString(), entry.getValue());
|
|
||||||
}
|
|
||||||
str = str.replaceAll("(?i)" + ChatColor.COLOR_CHAR + "x(" + ChatColor.COLOR_CHAR + "[0-9a-f]){6}", "");
|
|
||||||
return str + RESET_COLOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ConsoleOutputStream extends PrintStream {
|
|
||||||
|
|
||||||
private final PrintStream logs;
|
|
||||||
private final Console console;
|
|
||||||
|
|
||||||
public ConsoleOutputStream(Console console, OutputStream out, PrintStream logs) {
|
|
||||||
super(out);
|
|
||||||
this.logs = logs;
|
|
||||||
this.console = console;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PrintStream printf(Locale l, String format, Object... args) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor(String.format(l, "[" + date + " Info]" + format, args)));
|
|
||||||
logs.printf(l, ChatColor.stripColor("[" + date + " Info]" + format), args);
|
|
||||||
PrintStream stream = super.printf(l, Console.translateToConsole("[" + date + " Info]" + format), args);
|
|
||||||
console.unstashLine();
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PrintStream printf(String format, Object... args) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor(String.format("[" + date + " Info]" + format, args)));
|
|
||||||
logs.printf(ChatColor.stripColor("[" + date + " Info]" + format), args);
|
|
||||||
PrintStream stream = super.printf(ChatColor.stripColor("[" + date + " Info]" + format), args);
|
|
||||||
console.unstashLine();
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println() {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info]"), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]"));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]"));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(boolean x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(char x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(char[] x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + String.valueOf(x)), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]" + String.valueOf(x)));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]" + String.valueOf(x)));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(double x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(float x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(int x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(long x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(Object x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info]" + x));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(String string) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Info] " + string), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Info] " + string));
|
|
||||||
super.println(ChatColor.stripColor("[" + date + " Info] " + string));
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ConsoleErrorStream extends PrintStream {
|
|
||||||
|
|
||||||
private final PrintStream logs;
|
|
||||||
private final Console console;
|
|
||||||
|
|
||||||
public ConsoleErrorStream(Console console, OutputStream out, PrintStream logs) {
|
|
||||||
super(out);
|
|
||||||
this.logs = logs;
|
|
||||||
this.console = console;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("resource")
|
|
||||||
@Override
|
|
||||||
public PrintStream printf(Locale l, String format, Object... args) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor(String.format(l, "[" + date + " Error]" + format, args)));
|
|
||||||
logs.printf(l, ChatColor.stripColor("[" + date + " Error]" + format), args);
|
|
||||||
PrintStream stream = super.printf(l, ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + format + RESET_COLOR), args);
|
|
||||||
console.unstashLine();
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("resource")
|
|
||||||
@Override
|
|
||||||
public PrintStream printf(String format, Object... args) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor(String.format("[" + date + " Error]" + format, args)));
|
|
||||||
logs.printf(ChatColor.stripColor("[" + date + " Error]" + format), args);
|
|
||||||
PrintStream stream = super.printf(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + format + RESET_COLOR), args);
|
|
||||||
console.unstashLine();
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println() {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error]"), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]"));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]") + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(boolean x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]" + x));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + x) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(char x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]" + x));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + x) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(char[] x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + String.valueOf(x)), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]" + String.valueOf(x)));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + String.valueOf(x)) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(double x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]" + x));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + x) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(float x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]" + x));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + x) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(int x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]" + x));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + x) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(long x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]" + x));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + x) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(Object x) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + x), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error]" + x));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error]" + x) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void println(String string) {
|
|
||||||
console.stashLine();
|
|
||||||
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
|
|
||||||
ConsoleTextOutput.appendText(ChatColor.stripColor("[" + date + " Error] " + string), true);
|
|
||||||
logs.println(ChatColor.stripColor("[" + date + " Error] " + string));
|
|
||||||
super.println(ERROR_RED + ChatColor.stripColor("[" + date + " Error] " + string) + RESET_COLOR);
|
|
||||||
console.unstashLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,545 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.loohp.limbo.bossbar.KeyedBossBar;
|
|
||||||
import com.loohp.limbo.commands.CommandSender;
|
|
||||||
import com.loohp.limbo.commands.DefaultCommands;
|
|
||||||
import com.loohp.limbo.consolegui.GUI;
|
|
||||||
import com.loohp.limbo.events.EventsManager;
|
|
||||||
import com.loohp.limbo.file.ServerProperties;
|
|
||||||
import com.loohp.limbo.inventory.AnvilInventory;
|
|
||||||
import com.loohp.limbo.inventory.CustomInventory;
|
|
||||||
import com.loohp.limbo.inventory.Inventory;
|
|
||||||
import com.loohp.limbo.inventory.InventoryHolder;
|
|
||||||
import com.loohp.limbo.inventory.InventoryType;
|
|
||||||
import com.loohp.limbo.location.Location;
|
|
||||||
import com.loohp.limbo.metrics.Metrics;
|
|
||||||
import com.loohp.limbo.network.ServerConnection;
|
|
||||||
import com.loohp.limbo.network.protocol.packets.PacketPlayOutBoss;
|
|
||||||
import com.loohp.limbo.permissions.PermissionsManager;
|
|
||||||
import com.loohp.limbo.player.Player;
|
|
||||||
import com.loohp.limbo.plugins.LimboPlugin;
|
|
||||||
import com.loohp.limbo.plugins.PluginManager;
|
|
||||||
import com.loohp.limbo.scheduler.LimboScheduler;
|
|
||||||
import com.loohp.limbo.scheduler.Tick;
|
|
||||||
import com.loohp.limbo.utils.CustomStringUtils;
|
|
||||||
import com.loohp.limbo.utils.ImageUtils;
|
|
||||||
import com.loohp.limbo.utils.NetworkUtils;
|
|
||||||
import com.loohp.limbo.world.Environment;
|
|
||||||
import com.loohp.limbo.world.Schematic;
|
|
||||||
import com.loohp.limbo.world.World;
|
|
||||||
import net.kyori.adventure.bossbar.BossBar;
|
|
||||||
import net.kyori.adventure.key.Key;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
|
||||||
import net.querz.nbt.io.NBTUtil;
|
|
||||||
import net.querz.nbt.tag.CompoundTag;
|
|
||||||
import org.json.simple.JSONArray;
|
|
||||||
import org.json.simple.JSONObject;
|
|
||||||
import org.json.simple.parser.ParseException;
|
|
||||||
|
|
||||||
import javax.swing.UnsupportedLookAndFeelException;
|
|
||||||
import java.awt.GraphicsEnvironment;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Enumeration;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public final class Limbo {
|
|
||||||
|
|
||||||
public static final String LIMBO_BRAND = "Limbo";
|
|
||||||
|
|
||||||
private static Limbo instance;
|
|
||||||
public static boolean noGui = false;
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
|
|
||||||
for (String flag : args) {
|
|
||||||
if (flag.equals("--nogui") || flag.equals("nogui")) {
|
|
||||||
noGui = true;
|
|
||||||
} else if (flag.equals("--help")) {
|
|
||||||
System.out.println("Accepted flags:");
|
|
||||||
System.out.println(" --nogui <- Disable the GUI");
|
|
||||||
System.exit(0);
|
|
||||||
} else {
|
|
||||||
System.out.println("Unknown flag: \"" + flag + "\". Ignoring...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (GraphicsEnvironment.isHeadless()) {
|
|
||||||
noGui = true;
|
|
||||||
}
|
|
||||||
if (!noGui) {
|
|
||||||
System.out.println("Launching Server GUI.. Add \"--nogui\" in launch arguments to disable");
|
|
||||||
Thread t1 = new Thread(() -> {
|
|
||||||
try {
|
|
||||||
GUI.main();
|
|
||||||
} catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
t1.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
new Limbo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Limbo getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================
|
|
||||||
|
|
||||||
public final String SERVER_IMPLEMENTATION_VERSION = "1.21.10";
|
|
||||||
public final int SERVER_IMPLEMENTATION_PROTOCOL = 773;
|
|
||||||
public final String LIMBO_IMPLEMENTATION_VERSION;
|
|
||||||
|
|
||||||
private final AtomicBoolean isRunning;
|
|
||||||
|
|
||||||
private final ServerConnection server;
|
|
||||||
private final Console console;
|
|
||||||
|
|
||||||
private final List<World> worlds = new CopyOnWriteArrayList<>();
|
|
||||||
final Map<String, Player> playersByName = new ConcurrentHashMap<>();
|
|
||||||
final Map<UUID, Player> playersByUUID = new ConcurrentHashMap<>();
|
|
||||||
private final Map<Key, KeyedBossBar> bossBars = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
private final ServerProperties properties;
|
|
||||||
|
|
||||||
private final PluginManager pluginManager;
|
|
||||||
private final EventsManager eventsManager;
|
|
||||||
private final PermissionsManager permissionManager;
|
|
||||||
private final File pluginFolder;
|
|
||||||
|
|
||||||
private final Tick tick;
|
|
||||||
private final LimboScheduler scheduler;
|
|
||||||
|
|
||||||
private final Metrics metrics;
|
|
||||||
|
|
||||||
public final AtomicInteger entityIdCount = new AtomicInteger();
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private Unsafe unsafe;
|
|
||||||
|
|
||||||
public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
|
|
||||||
instance = this;
|
|
||||||
unsafe = new Unsafe(this);
|
|
||||||
isRunning = new AtomicBoolean(true);
|
|
||||||
|
|
||||||
if (!noGui) {
|
|
||||||
while (!GUI.loadFinish) {
|
|
||||||
TimeUnit.MILLISECONDS.sleep(500);
|
|
||||||
}
|
|
||||||
console = new Console(null, System.out, System.err);
|
|
||||||
} else {
|
|
||||||
console = new Console(System.in, System.out, System.err);
|
|
||||||
}
|
|
||||||
|
|
||||||
LIMBO_IMPLEMENTATION_VERSION = getLimboVersion();
|
|
||||||
console.sendMessage("Loading Limbo Version " + LIMBO_IMPLEMENTATION_VERSION + " on Minecraft " + SERVER_IMPLEMENTATION_VERSION);
|
|
||||||
|
|
||||||
String spName = "server.properties";
|
|
||||||
File sp = new File(spName);
|
|
||||||
if (!sp.exists()) {
|
|
||||||
try (InputStream in = getClass().getClassLoader().getResourceAsStream(spName)) {
|
|
||||||
Files.copy(in, sp.toPath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
properties = new ServerProperties(sp);
|
|
||||||
|
|
||||||
if (!properties.isBungeecord()) {
|
|
||||||
console.sendMessage("If you are using bungeecord, consider turning that on in the settings!");
|
|
||||||
} else {
|
|
||||||
console.sendMessage("Starting Limbo server in bungeecord mode!");
|
|
||||||
}
|
|
||||||
|
|
||||||
worlds.add(loadDefaultWorld());
|
|
||||||
Location spawn = properties.getWorldSpawn();
|
|
||||||
properties.setWorldSpawn(new Location(getWorld(properties.getLevelName().value()), spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getYaw(), spawn.getPitch()));
|
|
||||||
|
|
||||||
if (!NetworkUtils.available(properties.getServerPort())) {
|
|
||||||
console.sendMessage("");
|
|
||||||
console.sendMessage("*****FAILED TO BIND PORT [" + properties.getServerPort() + "]*****");
|
|
||||||
console.sendMessage("*****PORT ALREADY IN USE*****");
|
|
||||||
console.sendMessage("*****PERHAPS ANOTHER INSTANCE OF THE SERVER IS ALREADY RUNNING?*****");
|
|
||||||
console.sendMessage("");
|
|
||||||
System.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
String permissionName = "permission.yml";
|
|
||||||
File permissionFile = new File(permissionName);
|
|
||||||
if (!permissionFile.exists()) {
|
|
||||||
try (InputStream in = getClass().getClassLoader().getResourceAsStream(permissionName)) {
|
|
||||||
Files.copy(in, permissionFile.toPath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduler = new LimboScheduler();
|
|
||||||
tick = new Tick(this);
|
|
||||||
|
|
||||||
permissionManager = new PermissionsManager();
|
|
||||||
permissionManager.loadDefaultPermissionFile(permissionFile);
|
|
||||||
|
|
||||||
eventsManager = new EventsManager();
|
|
||||||
|
|
||||||
pluginFolder = new File("plugins");
|
|
||||||
pluginFolder.mkdirs();
|
|
||||||
|
|
||||||
pluginManager = new PluginManager(new DefaultCommands(), pluginFolder);
|
|
||||||
try {
|
|
||||||
Method loadPluginsMethod = PluginManager.class.getDeclaredMethod("loadPlugins");
|
|
||||||
loadPluginsMethod.setAccessible(true);
|
|
||||||
loadPluginsMethod.invoke(pluginManager);
|
|
||||||
loadPluginsMethod.setAccessible(false);
|
|
||||||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
|
|
||||||
try {
|
|
||||||
console.sendMessage("Enabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
|
|
||||||
plugin.onEnable();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
new RuntimeException("Error while enabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server = new ServerConnection(properties.getServerIp(), properties.getServerPort(), false);
|
|
||||||
|
|
||||||
metrics = new Metrics();
|
|
||||||
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
|
||||||
Limbo.getInstance().terminate();
|
|
||||||
}));
|
|
||||||
|
|
||||||
console.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public Unsafe getUnsafe() {
|
|
||||||
return unsafe;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Tick getHeartBeat() {
|
|
||||||
return tick;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LimboScheduler getScheduler() {
|
|
||||||
return scheduler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PermissionsManager getPermissionsManager() {
|
|
||||||
return permissionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventsManager getEventsManager() {
|
|
||||||
return eventsManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getPluginFolder() {
|
|
||||||
return pluginFolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginManager getPluginManager() {
|
|
||||||
return pluginManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
private World loadDefaultWorld() throws IOException {
|
|
||||||
console.sendMessage("Loading world " + properties.getLevelName() + " with the schematic file " + properties.getSchemFileName() + " ...");
|
|
||||||
|
|
||||||
File schem = new File(properties.getSchemFileName());
|
|
||||||
|
|
||||||
if (!schem.exists()) {
|
|
||||||
console.sendMessage("Schemetic file " + properties.getSchemFileName() + " for world " + properties.getLevelName() + " not found!");
|
|
||||||
console.sendMessage("Creating default world...");
|
|
||||||
try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream("spawn.schem")) {
|
|
||||||
Files.copy(in, schem.toPath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
World world = Schematic.toWorld(properties.getLevelName().value(), Environment.fromKey(properties.getLevelDimension()), (CompoundTag) NBTUtil.read(schem).getTag());
|
|
||||||
console.sendMessage("Loaded world " + properties.getLevelName() + "!");
|
|
||||||
return world;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
console.sendMessage("Unable to load world " + properties.getSchemFileName() + "!");
|
|
||||||
e.printStackTrace();
|
|
||||||
console.sendMessage("Server will exit!");
|
|
||||||
System.exit(1);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerWorld(World world) {
|
|
||||||
if (!worlds.contains(world)) {
|
|
||||||
worlds.add(world);
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("World already registered");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregisterWorld(World world) {
|
|
||||||
if (worlds.indexOf(world) == 0) {
|
|
||||||
throw new RuntimeException("World already registered");
|
|
||||||
} else if (!worlds.contains(world)) {
|
|
||||||
throw new RuntimeException("World not registered");
|
|
||||||
} else {
|
|
||||||
for (Player player : world.getPlayers()) {
|
|
||||||
player.teleport(properties.getWorldSpawn());
|
|
||||||
}
|
|
||||||
worlds.remove(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyedBossBar createBossBar(Key Key, Component name, float progress, BossBar.Color color, BossBar.Overlay overlay, BossBar.Flag... flags) {
|
|
||||||
KeyedBossBar keyedBossBar = com.loohp.limbo.bossbar.Unsafe.a(Key, BossBar.bossBar(name, progress, color, overlay, new HashSet<>(Arrays.asList(flags))));
|
|
||||||
bossBars.put(Key, keyedBossBar);
|
|
||||||
return keyedBossBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeBossBar(Key Key) {
|
|
||||||
KeyedBossBar keyedBossBar = bossBars.remove(Key);
|
|
||||||
keyedBossBar.getProperties().removeListener(keyedBossBar.getUnsafe().a());
|
|
||||||
keyedBossBar.getUnsafe().b();
|
|
||||||
PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(keyedBossBar, PacketPlayOutBoss.BossBarAction.REMOVE);
|
|
||||||
for (Player player : keyedBossBar.getPlayers()) {
|
|
||||||
try {
|
|
||||||
player.clientConnection.sendPacket(packetPlayOutBoss);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Key, KeyedBossBar> getBossBars() {
|
|
||||||
return Collections.unmodifiableMap(bossBars);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerProperties getServerProperties() {
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerConnection getServerConnection() {
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Console getConsole() {
|
|
||||||
return console;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Metrics getMetrics() {
|
|
||||||
return metrics;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Player> getPlayers() {
|
|
||||||
return new HashSet<>(playersByUUID.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player getPlayer(String name) {
|
|
||||||
return playersByName.get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player getPlayer(UUID uuid) {
|
|
||||||
return playersByUUID.get(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<World> getWorlds() {
|
|
||||||
return new ArrayList<>(worlds);
|
|
||||||
}
|
|
||||||
|
|
||||||
public World getWorld(String name) {
|
|
||||||
for (World world : worlds) {
|
|
||||||
if (world.getName().equalsIgnoreCase(name)) {
|
|
||||||
return world;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public String buildServerListResponseJson(String version, int protocol, Component motd, int maxPlayers, int playersOnline, BufferedImage favicon) throws IOException {
|
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
|
|
||||||
JSONObject versionJson = new JSONObject();
|
|
||||||
versionJson.put("name", version);
|
|
||||||
versionJson.put("protocol", protocol);
|
|
||||||
json.put("version", versionJson);
|
|
||||||
|
|
||||||
JSONObject playersJson = new JSONObject();
|
|
||||||
playersJson.put("max", maxPlayers);
|
|
||||||
playersJson.put("online", playersOnline);
|
|
||||||
json.put("players", playersJson);
|
|
||||||
|
|
||||||
json.put("description", "%MOTD%");
|
|
||||||
|
|
||||||
if (favicon != null) {
|
|
||||||
if (favicon.getWidth() == 64 && favicon.getHeight() == 64) {
|
|
||||||
String base64 = "data:image/png;base64," + ImageUtils.imgToBase64String(favicon, "png");
|
|
||||||
json.put("favicon", base64);
|
|
||||||
} else {
|
|
||||||
console.sendMessage("Server List Favicon must be 64 x 64 in size!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JSONObject modInfoJson = new JSONObject();
|
|
||||||
modInfoJson.put("type", "FML");
|
|
||||||
modInfoJson.put("modList", new JSONArray());
|
|
||||||
json.put("modinfo", modInfoJson);
|
|
||||||
|
|
||||||
|
|
||||||
TreeMap<String, Object> treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
|
||||||
treeMap.putAll(json);
|
|
||||||
|
|
||||||
Gson g = new GsonBuilder().create();
|
|
||||||
|
|
||||||
return g.toJson(treeMap).replace("\"%MOTD%\"", GsonComponentSerializer.gson().serialize(motd));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String buildLegacyPingResponse(String version, Component motd, int maxPlayers, int playersOnline) {
|
|
||||||
String begin = "<EFBFBD>1";
|
|
||||||
return String.join("\00", begin, "127", version, String.join("", Arrays.asList(motd).stream().map(each -> LegacyComponentSerializer.legacySection().serialize(each)).collect(Collectors.toList())), String.valueOf(playersOnline), String.valueOf(maxPlayers));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void terminate() {
|
|
||||||
isRunning.set(false);
|
|
||||||
console.sendMessage("Stopping Server...");
|
|
||||||
|
|
||||||
for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
|
|
||||||
try {
|
|
||||||
console.sendMessage("Disabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
|
|
||||||
plugin.onDisable();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
new RuntimeException("Error while disabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tick.waitAndKillThreads(5000);
|
|
||||||
|
|
||||||
for (Player player : getPlayers()) {
|
|
||||||
player.disconnect("Server closed");
|
|
||||||
}
|
|
||||||
while (!getPlayers().isEmpty()) {
|
|
||||||
try {
|
|
||||||
TimeUnit.MILLISECONDS.sleep(500);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.sendMessage("Server closed");
|
|
||||||
console.logs.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopServer() {
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRunning() {
|
|
||||||
return isRunning.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNextEntityId() {
|
|
||||||
return entityIdCount.getAndUpdate(i -> i == Integer.MAX_VALUE ? 0 : ++i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispatchCommand(CommandSender sender, String str) {
|
|
||||||
String[] command;
|
|
||||||
if (str.startsWith("/")) {
|
|
||||||
command = CustomStringUtils.splitStringToArgs(str.substring(1));
|
|
||||||
} else {
|
|
||||||
command = CustomStringUtils.splitStringToArgs(str);
|
|
||||||
}
|
|
||||||
dispatchCommand(sender, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispatchCommand(CommandSender sender, String... args) {
|
|
||||||
try {
|
|
||||||
Limbo.getInstance().getPluginManager().fireExecutors(sender, args);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getLimboVersion() throws IOException {
|
|
||||||
Enumeration<URL> manifests = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
|
|
||||||
while (manifests.hasMoreElements()) {
|
|
||||||
URL url = manifests.nextElement();
|
|
||||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
|
|
||||||
Optional<String> line = br.lines().filter(each -> each.startsWith("Limbo-Version:")).findFirst();
|
|
||||||
if (line.isPresent()) {
|
|
||||||
return line.get().substring(14).trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
|
|
||||||
public Inventory createInventory(Component title, int slots, InventoryHolder holder) {
|
|
||||||
return CustomInventory.create(title, slots, holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Inventory createInventory(InventoryType type, InventoryHolder holder) {
|
|
||||||
return createInventory(null, type, holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Inventory createInventory(Component title, InventoryType type, InventoryHolder holder) {
|
|
||||||
if (!type.isCreatable()) {
|
|
||||||
throw new UnsupportedOperationException("This InventoryType cannot be created.");
|
|
||||||
}
|
|
||||||
switch (type) {
|
|
||||||
case ANVIL:
|
|
||||||
return new AnvilInventory(title, holder);
|
|
||||||
default:
|
|
||||||
throw new UnsupportedOperationException("This InventoryType has not been implemented yet.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of Limbo.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
|
|
||||||
* Copyright (C) 2022. Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.loohp.limbo;
|
|
||||||
|
|
||||||
import com.loohp.limbo.entity.DataWatcher;
|
|
||||||
import com.loohp.limbo.entity.Entity;
|
|
||||||
import com.loohp.limbo.location.Location;
|
|
||||||
import com.loohp.limbo.player.Player;
|
|
||||||
import com.loohp.limbo.utils.GameMode;
|
|
||||||
import com.loohp.limbo.world.World;
|
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
|
|
||||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
|
||||||
@Deprecated
|
|
||||||
public class Unsafe {
|
|
||||||
|
|
||||||
private final Limbo instance;
|
|
||||||
private com.loohp.limbo.player.Unsafe playerUnsafe;
|
|
||||||
private com.loohp.limbo.world.Unsafe worldUnsafe;
|
|
||||||
|
|
||||||
protected Unsafe(Limbo instance) {
|
|
||||||
this.instance = instance;
|
|
||||||
try {
|
|
||||||
Constructor<com.loohp.limbo.player.Unsafe> playerConstructor = com.loohp.limbo.player.Unsafe.class.getDeclaredConstructor();
|
|
||||||
playerConstructor.setAccessible(true);
|
|
||||||
playerUnsafe = playerConstructor.newInstance();
|
|
||||||
playerConstructor.setAccessible(false);
|
|
||||||
|
|
||||||
Constructor<com.loohp.limbo.world.Unsafe> worldConstructor = com.loohp.limbo.world.Unsafe.class.getDeclaredConstructor();
|
|
||||||
worldConstructor.setAccessible(true);
|
|
||||||
worldUnsafe = worldConstructor.newInstance();
|
|
||||||
worldConstructor.setAccessible(false);
|
|
||||||
} catch (Exception e) {e.printStackTrace();}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void a(Player player, GameMode mode) {
|
|
||||||
playerUnsafe.a(player, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void a(Player player, byte slot) {
|
|
||||||
playerUnsafe.a(player, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void a(Player player, int entityId) {
|
|
||||||
playerUnsafe.a(player, entityId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void a(World world, Entity entity) {
|
|
||||||
worldUnsafe.a(world, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public DataWatcher b(World world, Entity entity) {
|
|
||||||
return worldUnsafe.b(world, entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void a(Player player, Location location) {
|
|
||||||
playerUnsafe.a(player, location);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void a(Player player) {
|
|
||||||
instance.playersByName.put(player.getName(), player);
|
|
||||||
instance.playersByUUID.put(player.getUniqueId(), player);
|
|
||||||
instance.getMetrics().updatePlayersCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public void b(Player player) {
|
|
||||||
instance.getBossBars().values().forEach(each -> each.hidePlayer(player));
|
|
||||||
instance.playersByName.remove(player.getName());
|
|
||||||
instance.playersByUUID.remove(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue