death
@@ -1,12 +0,0 @@
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
indent_size = 4
|
||||
|
||||
[*.{json,yml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
118
.github/workflows/prerelease.py
vendored
@@ -1,118 +0,0 @@
|
||||
import json
|
||||
|
||||
import requests
|
||||
import os
|
||||
|
||||
GITHUB_TOKEN = os.environ.get('GITHUB_TOKEN')
|
||||
VIRUSTOTAL_API_KEY = os.environ.get('VIRUSTOTAL_API_KEY')
|
||||
DISCORD_WEBHOOK = os.environ.get('DISCORD_WEBHOOK')
|
||||
LAST_COMMIT = os.environ.get('LAST_COMMIT')
|
||||
NEW_COMMIT = os.environ.get('NEW_COMMIT')
|
||||
|
||||
|
||||
def main():
|
||||
directory = os.listdir('./build/libs')
|
||||
jar = [file for file in directory if file.endswith('.jar')][0]
|
||||
version = jar.split('-')[2].split('.jar')[0]
|
||||
|
||||
virus_total_link = None
|
||||
if VIRUSTOTAL_API_KEY is not None:
|
||||
virus_total_req = requests.post(
|
||||
f'https://www.virustotal.com/api/v3/files',
|
||||
files={'file': (jar, open(f'./build/libs/{jar}', 'rb'), 'application/jar')},
|
||||
headers={
|
||||
'x-apikey': VIRUSTOTAL_API_KEY,
|
||||
'accept': 'application/json'
|
||||
}
|
||||
)
|
||||
if virus_total_req.status_code == 200:
|
||||
virus_total_id = virus_total_req.json()['data']['id']
|
||||
virus_total_link = f'https://www.virustotal.com/gui/file-analysis/{virus_total_id}/detection'
|
||||
|
||||
changes = {}
|
||||
changes_message = '**Changes:**\n'
|
||||
html_url = None
|
||||
if GITHUB_TOKEN is not None:
|
||||
github_req = requests.get(
|
||||
f'https://api.github.com/repos/DAMcraft/MeteorServerSeeker/compare/{LAST_COMMIT}...{NEW_COMMIT}',
|
||||
headers={
|
||||
'Authorization': f'Bearer {GITHUB_TOKEN}'
|
||||
}
|
||||
)
|
||||
if github_req.status_code == 200:
|
||||
for commit in github_req.json().get('commits', []):
|
||||
sha = commit['sha']
|
||||
message = commit['commit']['message']
|
||||
changes[sha] = message
|
||||
changes_message += (f'- [`{sha[:7]}`](https://github.com/DAMcraft/MeteorServerSeeker/commit/{sha}/) '
|
||||
f'{message}\n')
|
||||
|
||||
# Delete old release
|
||||
get_tags = requests.get(
|
||||
f"https://api.github.com/repos/DAMcraft/MeteorServerSeeker/releases/tags/latest",
|
||||
headers={
|
||||
"Authorization": f"Bearer {GITHUB_TOKEN}"
|
||||
},
|
||||
)
|
||||
if get_tags.status_code == 200:
|
||||
old_release = get_tags.json()
|
||||
release_id = old_release['id']
|
||||
del_req = requests.delete(
|
||||
f"https://api.github.com/repos/DAMcraft/MeteorServerSeeker/releases/{release_id}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {GITHUB_TOKEN}"
|
||||
}
|
||||
)
|
||||
|
||||
# New release
|
||||
req = requests.post(
|
||||
f"https://api.github.com/repos/DAMcraft/MeteorServerSeeker/releases",
|
||||
headers={
|
||||
'Authorization': f'Bearer {GITHUB_TOKEN}'
|
||||
},
|
||||
json={
|
||||
"tag_name": f"latest",
|
||||
"target_commitish": f"{NEW_COMMIT}",
|
||||
"name": f"Dev Build (Based on {version})",
|
||||
"body": changes_message + f"\nVirusTotal: {virus_total_link}",
|
||||
"draft": False,
|
||||
"prerelease": True,
|
||||
"make_latest": 'true'
|
||||
}
|
||||
)
|
||||
release_id = req.json()['id']
|
||||
html_url = req.json()['html_url']
|
||||
|
||||
# Upload jar
|
||||
requests.post(
|
||||
f"https://uploads.github.com/repos/DAMcraft/MeteorServerSeeker/releases/{release_id}/assets?name={jar}",
|
||||
headers={
|
||||
'Authorization': f'Bearer {GITHUB_TOKEN}',
|
||||
'Content-Type': 'application/jar'
|
||||
},
|
||||
data=open(f'./build/libs/{jar}', 'rb')
|
||||
)
|
||||
|
||||
if DISCORD_WEBHOOK is not None:
|
||||
requests.post(
|
||||
DISCORD_WEBHOOK,
|
||||
files={
|
||||
jar: open(f'./build/libs/{jar}', 'rb'),
|
||||
'payload_json': (None, json.dumps({
|
||||
'embeds': [
|
||||
{
|
||||
'title': "New Dev Build!",
|
||||
'description': f'A new dev build based on {version} has been released!\n'
|
||||
f'[VirusTotal]({virus_total_link})\n'
|
||||
f'{changes_message}\n'
|
||||
f'[View on GitHub]({html_url})',
|
||||
'color': 0x14c384
|
||||
}
|
||||
]
|
||||
}))
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
30
.github/workflows/prerelease.yml
vendored
@@ -1,30 +0,0 @@
|
||||
name: Publish Development Build
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions: write-all
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: 21
|
||||
distribution: adopt
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.12.1
|
||||
|
||||
- name: Build
|
||||
run: ./gradlew build -Pgithub_sha=${{ github.sha }}
|
||||
|
||||
- name: Run python script
|
||||
run: |
|
||||
pip3 install -r ./.github/workflows/requirements.txt
|
||||
python3 ./.github/workflows/prerelease.py
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VIRUSTOTAL_API_KEY: ${{ secrets.VT_API_KEY }}
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
|
||||
LAST_COMMIT: ${{ github.event.before }}
|
||||
NEW_COMMIT: ${{ github.event.after }}
|
19
.github/workflows/pull_request.yml
vendored
@@ -1,19 +0,0 @@
|
||||
name: Build Pull Request
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: 21
|
||||
distribution: adopt
|
||||
- name: Build
|
||||
run: ./gradlew build
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v2.2.4
|
||||
with:
|
||||
name: build-artifacts
|
||||
path: build/libs
|
1
.github/workflows/requirements.txt
vendored
@@ -1 +0,0 @@
|
||||
requests
|
33
.gitignore
vendored
@@ -1,33 +0,0 @@
|
||||
# gradle
|
||||
|
||||
.gradle/
|
||||
build/
|
||||
out/
|
||||
classes/
|
||||
|
||||
# eclipse
|
||||
|
||||
*.launch
|
||||
|
||||
# idea
|
||||
|
||||
.idea/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# vscode
|
||||
|
||||
.settings/
|
||||
.vscode/
|
||||
bin/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# macos
|
||||
|
||||
*.DS_Store
|
||||
|
||||
# fabric
|
||||
|
||||
run/
|
373
LICENSE
@@ -1,373 +0,0 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
40
build.gradle
@@ -1,40 +0,0 @@
|
||||
plugins {
|
||||
id "fabric-loom" version "1.7-SNAPSHOT"
|
||||
}
|
||||
|
||||
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_21
|
||||
|
||||
archivesBaseName = project.archives_base_name
|
||||
version = project.mod_version
|
||||
group = project.maven_group
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "Meteor Dev Releases"
|
||||
url = "https://maven.meteordev.org/releases"
|
||||
}
|
||||
maven {
|
||||
name = "Meteor Dev Snapshots"
|
||||
url = "https://maven.meteordev.org/snapshots"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Fabric
|
||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
// Meteor
|
||||
modImplementation "meteordevelopment:meteor-client:${project.meteor_version}"
|
||||
}
|
||||
|
||||
processResources {
|
||||
filesMatching("fabric.mod.json") {
|
||||
expand "version": project.version, "mc_version": project.minecraft_version, "gh_hash": (System.getenv("GITHUB_SHA") ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
it.options.encoding("UTF-8")
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
org.gradle.jvmargs=-Xmx2G
|
||||
|
||||
# Fabric Properties (https://fabricmc.net/develop)
|
||||
minecraft_version=1.21
|
||||
yarn_mappings=1.21+build.9
|
||||
loader_version=0.15.11
|
||||
fabric_version=0.102.0+1.21
|
||||
|
||||
# Mod Properties
|
||||
mod_version=4.4.0
|
||||
maven_group=de.damcraft
|
||||
archives_base_name=server-seeker
|
||||
|
||||
# Dependencies
|
||||
|
||||
# Meteor (https://maven.meteordev.org)
|
||||
meteor_version=0.5.8-SNAPSHOT
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +0,0 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
networkTimeout=10000
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
244
gradlew
vendored
@@ -1,244 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname country
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
gradlew.bat
vendored
@@ -1,92 +0,0 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
@@ -1,10 +0,0 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
}
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
@@ -1,166 +0,0 @@
|
||||
package de.damcraft.serverseeker;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import de.damcraft.serverseeker.ssapi.responses.UserInfoResponse;
|
||||
import meteordevelopment.meteorclient.systems.Systems;
|
||||
import net.minecraft.util.Util;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.LOG;
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
|
||||
public class DiscordAuth {
|
||||
private static final int port = 7637;
|
||||
|
||||
// Store as a string because it's too big and I don't want to import unnecessary libraries if I join it to a String anyway
|
||||
private static final String clientId = "1087083964432404590";
|
||||
|
||||
public static final String url =
|
||||
"https://discord.com/api/oauth2/authorize" +
|
||||
"?client_id=" + clientId +
|
||||
"&redirect_uri=http%3A%2F%2F127.0.0.1%3A" + port + "%2F" +
|
||||
"&response_type=code" +
|
||||
"&scope=identify";
|
||||
|
||||
private static HttpServer server;
|
||||
|
||||
private static BiConsumer<String, String> callback;
|
||||
|
||||
public static void auth(BiConsumer<String, String> callback) {
|
||||
DiscordAuth.callback = callback;
|
||||
Util.getOperatingSystem().open(url);
|
||||
startServer();
|
||||
}
|
||||
|
||||
private static void startServer() {
|
||||
try {
|
||||
server = HttpServer.create();
|
||||
server.bind(new InetSocketAddress("127.0.0.1", port), 0);
|
||||
server.createContext("/", new AuthHandler());
|
||||
server.start();
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void stopServer() {
|
||||
if (server == null) return;
|
||||
|
||||
server.stop(0);
|
||||
server = null;
|
||||
|
||||
callback = null;
|
||||
}
|
||||
|
||||
private static class AuthHandler implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange req) throws IOException {
|
||||
if (req.getRequestMethod().equals("GET")) {
|
||||
// Login
|
||||
List<NameValuePair> query = URLEncodedUtils.parse(req.getRequestURI(), StandardCharsets.UTF_8);
|
||||
|
||||
boolean ok = false;
|
||||
|
||||
for (NameValuePair pair : query) {
|
||||
if (pair.getName().equals("code")) {
|
||||
handleCode(pair.getValue());
|
||||
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
writeText(req, "Cannot authenticate.");
|
||||
} else writeText(req, "You may now close this page.");
|
||||
stopServer();
|
||||
} else if (req.getRequestMethod().equals("OPTIONS")) {
|
||||
req.getResponseHeaders().add("Allow", "GET, OPTIONS");
|
||||
req.sendResponseHeaders(204, -1);
|
||||
} else {
|
||||
req.sendResponseHeaders(405, -1);
|
||||
LOG.warn("Invalid request method: {}", req.getRequestMethod());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeText(HttpExchange req, String text) throws IOException {
|
||||
OutputStream out = req.getResponseBody();
|
||||
|
||||
req.sendResponseHeaders(200, text.length());
|
||||
|
||||
out.write(text.getBytes(StandardCharsets.UTF_8));
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
public void handleCode(String code) {
|
||||
// Get the ServerSeeker auth token
|
||||
|
||||
JsonObject params = new JsonObject();
|
||||
|
||||
params.addProperty("code", code);
|
||||
params.addProperty("usage", "meteor serverseeker");
|
||||
|
||||
String jsonResp = SmallHttp.post("https://api.serverseeker.net/get_token", params.toString());
|
||||
|
||||
// {"api_key": "..."} or {"error": "..."}
|
||||
|
||||
JsonObject obj = gson.fromJson(jsonResp, JsonObject.class);
|
||||
|
||||
if (obj.has("error")) {
|
||||
System.out.println("Error: " + obj.get("error").getAsString());
|
||||
callback.accept(null, obj.get("error").getAsString());
|
||||
return;
|
||||
}
|
||||
if (!obj.has("api_key")) {
|
||||
System.out.println("Error: No api_key in response.");
|
||||
callback.accept(null, "No api_key in response.");
|
||||
return;
|
||||
}
|
||||
String apiKey = obj.get("api_key").getAsString();
|
||||
Systems.get(ServerSeekerSystem.class).apiKey = apiKey;
|
||||
|
||||
// Get the discord user info
|
||||
params = new JsonObject();
|
||||
|
||||
params.addProperty("api_key", apiKey);
|
||||
|
||||
jsonResp = SmallHttp.post("https://api.serverseeker.net/user_info", params.toString());
|
||||
|
||||
// {
|
||||
// "discord_id": user_id,
|
||||
// "discord_username": discord_username,
|
||||
// "discord_avatar_url": avatar_url
|
||||
// } or {"error": "..."}
|
||||
|
||||
UserInfoResponse userInfo = gson.fromJson(jsonResp, UserInfoResponse.class);
|
||||
|
||||
if (userInfo.isError()) {
|
||||
System.out.println("Error: " + userInfo.error);
|
||||
callback.accept(null, userInfo.error);
|
||||
return;
|
||||
}
|
||||
|
||||
String discordId = userInfo.discord_id;
|
||||
String discordUsername = userInfo.discord_username;
|
||||
String discordAvatarUrl = userInfo.discord_avatar_url;
|
||||
|
||||
Systems.get(ServerSeekerSystem.class).discordId = discordId;
|
||||
Systems.get(ServerSeekerSystem.class).discordUsername = discordUsername;
|
||||
Systems.get(ServerSeekerSystem.class).discordAvatarUrl = discordAvatarUrl == null ? "" : discordAvatarUrl;
|
||||
|
||||
callback.accept(apiKey, null);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
package de.damcraft.serverseeker;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import de.damcraft.serverseeker.ssapi.responses.UserInfoResponse;
|
||||
import meteordevelopment.meteorclient.renderer.Texture;
|
||||
import meteordevelopment.meteorclient.systems.Systems;
|
||||
import meteordevelopment.meteorclient.utils.network.Http;
|
||||
import org.lwjgl.BufferUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.LOG;
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
|
||||
public class DiscordAvatar extends Texture {
|
||||
public DiscordAvatar(String url) {
|
||||
BufferedImage avatar;
|
||||
try {
|
||||
InputStream stream = Http.get(url).sendInputStream();
|
||||
if (stream == null) {
|
||||
JsonObject params = new JsonObject();
|
||||
|
||||
params.addProperty("api_key", Systems.get(ServerSeekerSystem.class).apiKey);
|
||||
|
||||
String jsonResp = SmallHttp.post("https://api.serverseeker.net/user_info", params.toString());
|
||||
|
||||
UserInfoResponse userInfo = gson.fromJson(jsonResp, UserInfoResponse.class);
|
||||
if (userInfo.isError()) {
|
||||
System.out.println("Error: " + userInfo.error);
|
||||
return;
|
||||
}
|
||||
String discordId = userInfo.discord_id;
|
||||
String discordUsername = userInfo.discord_username;
|
||||
String discordAvatarUrl = userInfo.discord_avatar_url == null ? "" : userInfo.discord_avatar_url;
|
||||
|
||||
Systems.get(ServerSeekerSystem.class).discordId = discordId;
|
||||
Systems.get(ServerSeekerSystem.class).discordUsername = discordUsername;
|
||||
Systems.get(ServerSeekerSystem.class).discordAvatarUrl = discordAvatarUrl;
|
||||
|
||||
stream = Http.get(discordAvatarUrl).sendInputStream();
|
||||
}
|
||||
if (stream == null) {
|
||||
System.err.println("Failed to get avatar, are you Vero?");
|
||||
return;
|
||||
}
|
||||
avatar = ImageIO.read(stream);
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] data = new byte[avatar.getWidth() * avatar.getHeight() * 3];
|
||||
int[] pixel = new int[4];
|
||||
int i = 0;
|
||||
|
||||
for (int y = 0; y < avatar.getHeight(); y++) {
|
||||
for (int x = 0; x < avatar.getWidth(); x++) {
|
||||
avatar.getData().getPixel(x, y, pixel);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
data[i] = (byte) pixel[j];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
upload(BufferUtils.createByteBuffer(data.length).put(data));
|
||||
}
|
||||
|
||||
private void upload(ByteBuffer data) {
|
||||
Runnable action = () -> upload(32, 32, data, Texture.Format.RGB, Texture.Filter.Nearest, Texture.Filter.Nearest, false);
|
||||
if (RenderSystem.isOnRenderThread()) action.run();
|
||||
else RenderSystem.recordRenderCall(action::run);
|
||||
}
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
package de.damcraft.serverseeker;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import de.damcraft.serverseeker.country.Countries;
|
||||
import de.damcraft.serverseeker.country.Country;
|
||||
import de.damcraft.serverseeker.country.CountrySetting;
|
||||
import de.damcraft.serverseeker.hud.HistoricPlayersHud;
|
||||
import de.damcraft.serverseeker.modules.BungeeSpoofModule;
|
||||
import de.damcraft.serverseeker.utils.HistoricPlayersUpdater;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
|
||||
import meteordevelopment.meteorclient.MeteorClient;
|
||||
import meteordevelopment.meteorclient.addons.GithubRepo;
|
||||
import meteordevelopment.meteorclient.addons.MeteorAddon;
|
||||
import meteordevelopment.meteorclient.gui.utils.SettingsWidgetFactory;
|
||||
import meteordevelopment.meteorclient.systems.hud.Hud;
|
||||
import meteordevelopment.meteorclient.systems.modules.Category;
|
||||
import meteordevelopment.meteorclient.systems.modules.Modules;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.item.Items;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ServerSeeker extends MeteorAddon {
|
||||
/*
|
||||
Feature list for anticope.pages.dev:
|
||||
(creates features matching the RegEx '(?:add\(new )([^(]+)(?:\([^)]*)\)\)', as anticope checks for that.
|
||||
add(new Find servers with many parameters, for example: Cracked, Description, Player count, much more...())
|
||||
add(new Server database with around 1.000.000 servers!())
|
||||
add(new Over 80.000.000 players tracked!())
|
||||
add(new Search for ANY server you want!())
|
||||
add(new Join misconfigured BungeeCord backends with any name you want!())
|
||||
*/
|
||||
public static final Logger LOG = LogUtils.getLogger();
|
||||
public static final Category CATEGORY = new Category("ServerSeeker", Items.SPYGLASS.getDefaultStack());
|
||||
public static final Map<String, Country> COUNTRY_MAP = new Object2ReferenceOpenHashMap<>();
|
||||
|
||||
public static final Gson gson = new Gson();
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
LOG.info("Loaded the ServerSeeker addon!");
|
||||
|
||||
// Load countries
|
||||
Countries.init();
|
||||
|
||||
Modules.get().add( new BungeeSpoofModule() );
|
||||
Hud.get().register(HistoricPlayersHud.INFO);
|
||||
|
||||
SettingsWidgetFactory.registerCustomFactory(CountrySetting.class, (theme) -> (table, setting) -> {
|
||||
CountrySetting.countrySettingW(table, (CountrySetting) setting, theme);
|
||||
});
|
||||
|
||||
MeteorClient.EVENT_BUS.subscribe(HistoricPlayersUpdater.class);
|
||||
}
|
||||
@Override
|
||||
public void onRegisterCategories() {
|
||||
Modules.registerCategory(CATEGORY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackage() {
|
||||
return "de.damcraft.serverseeker";
|
||||
}
|
||||
|
||||
@Override
|
||||
public GithubRepo getRepo() {
|
||||
return new GithubRepo("DAMcraft", "MeteorServerSeeker");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWebsite() {
|
||||
return "https://serverseeker.net/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommit() {
|
||||
String commit = FabricLoader
|
||||
.getInstance()
|
||||
.getModContainer("serverseeker")
|
||||
.get().getMetadata()
|
||||
.getCustomValue("github:sha")
|
||||
.getAsString();
|
||||
return commit.isEmpty() ? null : commit.trim();
|
||||
}
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
package de.damcraft.serverseeker;
|
||||
|
||||
import meteordevelopment.meteorclient.systems.System;
|
||||
import meteordevelopment.meteorclient.systems.Systems;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
|
||||
public class ServerSeekerSystem extends System<ServerSeekerSystem> {
|
||||
public ServerSeekerSystem() {
|
||||
super("serverseeker");
|
||||
}
|
||||
|
||||
public String apiKey = "";
|
||||
|
||||
public String discordId = "";
|
||||
|
||||
public String discordUsername = "";
|
||||
|
||||
public String discordAvatarUrl = "";
|
||||
|
||||
public static ServerSeekerSystem get() {
|
||||
return Systems.get(ServerSeekerSystem.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtCompound toTag() {
|
||||
NbtCompound tag = new NbtCompound();
|
||||
|
||||
tag.putString("apiKey", apiKey);
|
||||
tag.putString("userId", discordId);
|
||||
tag.putString("username", discordUsername);
|
||||
tag.putString("avatarUrl", discordAvatarUrl);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerSeekerSystem fromTag(NbtCompound tag) {
|
||||
apiKey = tag.getString("apiKey");
|
||||
discordId = tag.getString("userId");
|
||||
discordUsername = tag.getString("username");
|
||||
discordAvatarUrl = tag.getString("avatarUrl");
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
package de.damcraft.serverseeker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.LOG;
|
||||
|
||||
public class SmallHttp {
|
||||
public static String post(String url, String json) {
|
||||
try (HttpClient client = HttpClient.newHttpClient()) {
|
||||
return client.send(HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.POST(HttpRequest.BodyPublishers.ofString(json))
|
||||
.header("Content-Type", "application/json")
|
||||
.build(),
|
||||
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)
|
||||
).body();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
LOG.error(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String get(String url) {
|
||||
try (HttpClient client = HttpClient.newHttpClient()) {
|
||||
return client.send(HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.GET()
|
||||
.build(),
|
||||
HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)
|
||||
).body();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
LOG.error(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static HttpResponse<InputStream> download(String url) {
|
||||
try (HttpClient client = HttpClient.newHttpClient()) {
|
||||
HttpResponse<InputStream> req = client.send(HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.GET()
|
||||
.build(),
|
||||
HttpResponse.BodyHandlers.ofInputStream()
|
||||
);
|
||||
if (req.headers().firstValue("location").isPresent()) {
|
||||
return download(req.headers().firstValue("location").get());
|
||||
}
|
||||
return req;
|
||||
} catch (IOException | InterruptedException e) {
|
||||
LOG.error(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,258 +0,0 @@
|
||||
package de.damcraft.serverseeker.country;
|
||||
|
||||
import de.damcraft.serverseeker.ServerSeeker;
|
||||
|
||||
public class Countries {
|
||||
public static final Country UN = new DefaultCountry("Any", "UN");
|
||||
|
||||
public static void init() {
|
||||
ServerSeeker.COUNTRY_MAP.put("UN", UN);
|
||||
|
||||
ServerSeeker.COUNTRY_MAP.put("AF", new Country("Afghanistan", "AF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AX", new Country("Aland Islands", "AX"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AL", new Country("Albania", "AL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("DZ", new Country("Algeria", "DZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AS", new Country("American Samoa", "AS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AD", new Country("Andorra", "AD"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AO", new Country("Angola", "AO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AI", new Country("Anguilla", "AI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AQ", new Country("Antarctica", "AQ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AG", new Country("Antigua And Barbuda", "AG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AR", new Country("Argentina", "AR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AM", new Country("Armenia", "AM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AW", new Country("Aruba", "AW"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AU", new Country("Australia", "AU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AT", new Country("Austria", "AT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AZ", new Country("Azerbaijan", "AZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BS", new Country("Bahamas", "BS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BH", new Country("Bahrain", "BH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BD", new Country("Bangladesh", "BD"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BB", new Country("Barbados", "BB"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BY", new Country("Belarus", "BY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BE", new Country("Belgium", "BE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BZ", new Country("Belize", "BZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BJ", new Country("Benin", "BJ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BM", new Country("Bermuda", "BM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BT", new Country("Bhutan", "BT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BO", new Country("Bolivia", "BO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BA", new Country("Bosnia And Herzegovina", "BA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BW", new Country("Botswana", "BW"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BV", new Country("Bouvet Island", "BV"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BR", new Country("Brazil", "BR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IO", new Country("British Indian Ocean Territory", "IO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BN", new Country("Brunei Darussalam", "BN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BG", new Country("Bulgaria", "BG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BF", new Country("Burkina Faso", "BF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BI", new Country("Burundi", "BI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KH", new Country("Cambodia", "KH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CM", new Country("Cameroon", "CM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CA", new Country("Canada", "CA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CV", new Country("Cape Verde", "CV"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KY", new Country("Cayman Islands", "KY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CF", new Country("Central African Republic", "CF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TD", new Country("Chad", "TD"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CL", new Country("Chile", "CL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CN", new Country("China", "CN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CX", new Country("Christmas Island", "CX"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CC", new Country("Cocos (Keeling) Islands", "CC"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CO", new Country("Colombia", "CO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KM", new Country("Comoros", "KM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CG", new Country("Congo", "CG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CD", new Country("Congo, Democratic Republic", "CD"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CK", new Country("Cook Islands", "CK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CR", new Country("Costa Rica", "CR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CI", new Country("Cote D'Ivoire", "CI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("HR", new Country("Croatia", "HR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CU", new Country("Cuba", "CU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CY", new Country("Cyprus", "CY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CZ", new Country("Czech Republic", "CZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("DK", new Country("Denmark", "DK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("DJ", new Country("Djibouti", "DJ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("DM", new Country("Dominica", "DM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("DO", new Country("Dominican Republic", "DO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("EC", new Country("Ecuador", "EC"));
|
||||
ServerSeeker.COUNTRY_MAP.put("EG", new Country("Egypt", "EG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SV", new Country("El Salvador", "SV"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GQ", new Country("Equatorial Guinea", "GQ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ER", new Country("Eritrea", "ER"));
|
||||
ServerSeeker.COUNTRY_MAP.put("EE", new Country("Estonia", "EE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ET", new Country("Ethiopia", "ET"));
|
||||
ServerSeeker.COUNTRY_MAP.put("FK", new Country("Falkland Islands (Malvinas)", "FK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("FO", new Country("Faroe Islands", "FO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("FJ", new Country("Fiji", "FJ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("FI", new Country("Finland", "FI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("FR", new Country("France", "FR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GF", new Country("French Guiana", "GF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PF", new Country("French Polynesia", "PF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TF", new Country("French Southern Territories", "TF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GA", new Country("Gabon", "GA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GM", new Country("Gambia", "GM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GE", new Country("Georgia", "GE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("DE", new Country("Germany", "DE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GH", new Country("Ghana", "GH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GI", new Country("Gibraltar", "GI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GR", new Country("Greece", "GR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GL", new Country("Greenland", "GL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GD", new Country("Grenada", "GD"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GP", new Country("Guadeloupe", "GP"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GU", new Country("Guam", "GU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GT", new Country("Guatemala", "GT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GG", new Country("Guernsey", "GG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GN", new Country("Guinea", "GN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GW", new Country("Guinea-Bissau", "GW"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GY", new Country("Guyana", "GY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("HT", new Country("Haiti", "HT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("HM", new Country("Heard Island & Mcdonald Islands", "HM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("VA", new Country("Holy See (Vatican City State)", "VA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("HN", new Country("Honduras", "HN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("HK", new Country("Hong Kong", "HK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("HU", new Country("Hungary", "HU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IS", new Country("Iceland", "IS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IN", new Country("India", "IN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ID", new Country("Indonesia", "ID"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IR", new Country("Iran, Islamic Republic Of", "IR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IQ", new Country("Iraq", "IQ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IE", new Country("Ireland", "IE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IM", new Country("Isle Of Man", "IM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IL", new Country("Israel", "IL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("IT", new Country("Italy", "IT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("JM", new Country("Jamaica", "JM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("JP", new Country("Japan", "JP"));
|
||||
ServerSeeker.COUNTRY_MAP.put("JE", new Country("Jersey", "JE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("JO", new Country("Jordan", "JO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KZ", new Country("Kazakhstan", "KZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KE", new Country("Kenya", "KE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KI", new Country("Kiribati", "KI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KR", new Country("Korea", "KR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KP", new Country("North Korea", "KP"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KW", new Country("Kuwait", "KW"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KG", new Country("Kyrgyzstan", "KG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LA", new Country("Lao People's Democratic Republic", "LA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LV", new Country("Latvia", "LV"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LB", new Country("Lebanon", "LB"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LS", new Country("Lesotho", "LS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LR", new Country("Liberia", "LR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LY", new Country("Libyan Arab Jamahiriya", "LY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LI", new Country("Liechtenstein", "LI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LT", new Country("Lithuania", "LT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LU", new Country("Luxembourg", "LU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MO", new Country("Macao", "MO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MK", new Country("Macedonia", "MK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MG", new Country("Madagascar", "MG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MW", new Country("Malawi", "MW"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MY", new Country("Malaysia", "MY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MV", new Country("Maldives", "MV"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ML", new Country("Mali", "ML"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MT", new Country("Malta", "MT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MH", new Country("Marshall Islands", "MH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MQ", new Country("Martinique", "MQ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MR", new Country("Mauritania", "MR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MU", new Country("Mauritius", "MU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("YT", new Country("Mayotte", "YT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MX", new Country("Mexico", "MX"));
|
||||
ServerSeeker.COUNTRY_MAP.put("FM", new Country("Micronesia, Federated States Of", "FM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MD", new Country("Moldova", "MD"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MC", new Country("Monaco", "MC"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MN", new Country("Mongolia", "MN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ME", new Country("Montenegro", "ME"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MS", new Country("Montserrat", "MS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MA", new Country("Morocco", "MA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MZ", new Country("Mozambique", "MZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MM", new Country("Myanmar", "MM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NA", new Country("Namibia", "NA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NR", new Country("Nauru", "NR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NP", new Country("Nepal", "NP"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NL", new Country("Netherlands", "NL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AN", new Country("Netherlands Antilles", "AN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NC", new Country("New Caledonia", "NC"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NZ", new Country("New Zealand", "NZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NI", new Country("Nicaragua", "NI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NE", new Country("Niger", "NE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NG", new Country("Nigeria", "NG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NU", new Country("Niue", "NU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NF", new Country("Norfolk Island", "NF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MP", new Country("Northern Mariana Islands", "MP"));
|
||||
ServerSeeker.COUNTRY_MAP.put("NO", new Country("Norway", "NO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("OM", new Country("Oman", "OM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PK", new Country("Pakistan", "PK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PW", new Country("Palau", "PW"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PS", new Country("Palestinian Territory, Occupied", "PS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PA", new Country("Panama", "PA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PG", new Country("Papua New Guinea", "PG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PY", new Country("Paraguay", "PY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PE", new Country("Peru", "PE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PH", new Country("Philippines", "PH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PN", new Country("Pitcairn", "PN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PL", new Country("Poland", "PL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PT", new Country("Portugal", "PT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PR", new Country("Puerto Rico", "PR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("QA", new Country("Qatar", "QA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("RE", new Country("Reunion", "RE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("RO", new Country("Romania", "RO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("RU", new Country("Russian Federation", "RU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("RW", new Country("Rwanda", "RW"));
|
||||
ServerSeeker.COUNTRY_MAP.put("BL", new Country("Saint Barthelemy", "BL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SH", new Country("Saint Helena", "SH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("KN", new Country("Saint Kitts And Nevis", "KN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LC", new Country("Saint Lucia", "LC"));
|
||||
ServerSeeker.COUNTRY_MAP.put("MF", new Country("Saint Martin", "MF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("PM", new Country("Saint Pierre And Miquelon", "PM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("VC", new Country("Saint Vincent And Grenadines", "VC"));
|
||||
ServerSeeker.COUNTRY_MAP.put("WS", new Country("Samoa", "WS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SM", new Country("San Marino", "SM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ST", new Country("Sao Tome And Principe", "ST"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SA", new Country("Saudi Arabia", "SA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SN", new Country("Senegal", "SN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("RS", new Country("Serbia", "RS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SC", new Country("Seychelles", "SC"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SL", new Country("Sierra Leone", "SL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SG", new Country("Singapore", "SG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SK", new Country("Slovakia", "SK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SI", new Country("Slovenia", "SI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SB", new Country("Solomon Islands", "SB"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SO", new Country("Somalia", "SO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ZA", new Country("South Africa", "ZA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GS", new Country("South Georgia And Sandwich Isl.", "GS"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ES", new Country("Spain", "ES"));
|
||||
ServerSeeker.COUNTRY_MAP.put("LK", new Country("Sri Lanka", "LK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SD", new Country("Sudan", "SD"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SR", new Country("Suriname", "SR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SJ", new Country("Svalbard And Jan Mayen", "SJ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SZ", new Country("Swaziland", "SZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SE", new Country("Sweden", "SE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("CH", new Country("Switzerland", "CH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("SY", new Country("Syrian Arab Republic", "SY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TW", new Country("Taiwan", "TW"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TJ", new Country("Tajikistan", "TJ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TZ", new Country("Tanzania", "TZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TH", new Country("Thailand", "TH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TL", new Country("Timor-Leste", "TL"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TG", new Country("Togo", "TG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TK", new Country("Tokelau", "TK"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TO", new Country("Tonga", "TO"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TT", new Country("Trinidad And Tobago", "TT"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TN", new Country("Tunisia", "TN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TR", new Country("Turkey", "TR"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TM", new Country("Turkmenistan", "TM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TC", new Country("Turks And Caicos Islands", "TC"));
|
||||
ServerSeeker.COUNTRY_MAP.put("TV", new Country("Tuvalu", "TV"));
|
||||
ServerSeeker.COUNTRY_MAP.put("UG", new Country("Uganda", "UG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("UA", new Country("Ukraine", "UA"));
|
||||
ServerSeeker.COUNTRY_MAP.put("AE", new Country("United Arab Emirates", "AE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("GB", new Country("United Kingdom", "GB"));
|
||||
ServerSeeker.COUNTRY_MAP.put("US", new Country("United States", "US"));
|
||||
ServerSeeker.COUNTRY_MAP.put("UM", new Country("United States Outlying Islands", "UM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("UY", new Country("Uruguay", "UY"));
|
||||
ServerSeeker.COUNTRY_MAP.put("UZ", new Country("Uzbekistan", "UZ"));
|
||||
ServerSeeker.COUNTRY_MAP.put("VU", new Country("Vanuatu", "VU"));
|
||||
ServerSeeker.COUNTRY_MAP.put("VE", new Country("Venezuela", "VE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("VN", new Country("Vietnam", "VN"));
|
||||
ServerSeeker.COUNTRY_MAP.put("VG", new Country("Virgin Islands, British", "VG"));
|
||||
ServerSeeker.COUNTRY_MAP.put("VI", new Country("Virgin Islands, U.S.", "VI"));
|
||||
ServerSeeker.COUNTRY_MAP.put("WF", new Country("Wallis And Futuna", "WF"));
|
||||
ServerSeeker.COUNTRY_MAP.put("EH", new Country("Western Sahara", "EH"));
|
||||
ServerSeeker.COUNTRY_MAP.put("YE", new Country("Yemen", "YE"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ZM", new Country("Zambia", "ZM"));
|
||||
ServerSeeker.COUNTRY_MAP.put("ZW", new Country("Zimbabwe", "ZW"));
|
||||
}
|
||||
}
|
@@ -1,114 +0,0 @@
|
||||
package de.damcraft.serverseeker.country;
|
||||
|
||||
import meteordevelopment.meteorclient.renderer.Texture;
|
||||
import meteordevelopment.meteorclient.utils.network.MeteorExecutor;
|
||||
import net.minecraft.resource.Resource;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
import static meteordevelopment.meteorclient.MeteorClient.LOG;
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
public class Country implements Comparable<Country> {
|
||||
public final Identifier identifier;
|
||||
public final String name;
|
||||
public final String code;
|
||||
private final TextureData textureData;
|
||||
|
||||
public Country(String name, String code) {
|
||||
this.name = name;
|
||||
this.code = code.toLowerCase(Locale.ENGLISH);
|
||||
this.identifier = Identifier.of("serverseeker", String.format("textures/flags/%s.png", this.code));
|
||||
if (mc.getResourceManager().getResource(this.identifier).isEmpty()) {
|
||||
LOG.error("Could not find flag for country: {}", this.code);
|
||||
this.textureData = new EmptyTextureData();
|
||||
} else this.textureData = new CountryTextureData();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Texture getTexture() {
|
||||
Texture texture = this.textureData.get();
|
||||
if (texture == null) return this == Countries.UN ? null : Countries.UN.getTexture();
|
||||
return texture;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
this.textureData.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull Country o) {
|
||||
return this.name.compareTo(o.name);
|
||||
}
|
||||
|
||||
public sealed interface TextureData {
|
||||
@Nullable
|
||||
default Texture get() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default void dispose() {}
|
||||
}
|
||||
|
||||
public final class CountryTextureData implements TextureData {
|
||||
private Texture texture = null;
|
||||
private State state = State.EMPTY;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Texture get() {
|
||||
if (this.state == State.DONE) return this.texture;
|
||||
else {
|
||||
if (this.state == State.EMPTY) MeteorExecutor.execute(this::load);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (this.state == State.DONE) {
|
||||
this.texture.dispose();
|
||||
this.texture = null;
|
||||
}
|
||||
this.state = State.EMPTY;
|
||||
}
|
||||
|
||||
private void load() {
|
||||
this.state = State.LOADING;
|
||||
Resource textureResource = mc.getResourceManager().getResource(Country.this.identifier).orElseThrow();
|
||||
|
||||
try (InputStream imageStream = textureResource.getInputStream()) {
|
||||
BufferedImage bufferedImage = ImageIO.read(imageStream);
|
||||
|
||||
int[] pixels = bufferedImage.getRGB(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), null, 0, bufferedImage.getWidth());
|
||||
byte[] data = new byte[bufferedImage.getWidth() * bufferedImage.getHeight() * 3];
|
||||
|
||||
for (int i = 0; i < pixels.length; i++) {
|
||||
data[3 * i] = (byte) ((pixels[i] >> 16) & 0xFF); // r
|
||||
data[3 * i + 1] = (byte) ((pixels[i] >> 8) & 0xFF); // g
|
||||
data[3 * i + 2] = (byte) ((pixels[i]) & 0xFF); // b
|
||||
}
|
||||
|
||||
this.texture = new Texture(bufferedImage.getWidth(), bufferedImage.getHeight(), data, Texture.Format.RGB, Texture.Filter.Nearest, Texture.Filter.Nearest);
|
||||
this.state = State.DONE;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public enum State {
|
||||
EMPTY,
|
||||
LOADING,
|
||||
DONE
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptyTextureData implements TextureData {}
|
||||
}
|
@@ -1,93 +0,0 @@
|
||||
package de.damcraft.serverseeker.country;
|
||||
|
||||
import de.damcraft.serverseeker.ServerSeeker;
|
||||
import meteordevelopment.meteorclient.gui.GuiTheme;
|
||||
import meteordevelopment.meteorclient.gui.renderer.GuiRenderer;
|
||||
import meteordevelopment.meteorclient.gui.widgets.WLabel;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import meteordevelopment.meteorclient.settings.IVisible;
|
||||
import meteordevelopment.meteorclient.settings.Setting;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
public class CountrySetting extends Setting<Country> {
|
||||
public final Predicate<Country> filter;
|
||||
|
||||
public CountrySetting(String name, String description, Country defaultValue, Consumer<Country> onChanged, Consumer<Setting<Country>> onModuleActivated, IVisible visible, Predicate<Country> filter) {
|
||||
super(name, description, defaultValue, onChanged, onModuleActivated, visible);
|
||||
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public static void countrySettingW(WTable table, CountrySetting setting, GuiTheme theme) {
|
||||
WHorizontalList list = table.add(theme.horizontalList()).expandX().widget();
|
||||
|
||||
WCountry country = list.add(new WCountry(setting.get())).widget();
|
||||
|
||||
String name = setting.get().name;
|
||||
WLabel nameLabel = list.add(theme.label(name)).widget();
|
||||
|
||||
WButton select = list.add(theme.button("Select")).widget();
|
||||
select.action = () -> {
|
||||
CountrySettingScreen screen = new CountrySettingScreen(theme, setting);
|
||||
screen.onClosed(() -> {
|
||||
country.set(setting.get());
|
||||
nameLabel.set(setting.get().name);
|
||||
});
|
||||
|
||||
mc.setScreen(screen);
|
||||
};
|
||||
|
||||
WButton reset = list.add(theme.button(GuiRenderer.RESET)).expandCellX().right().widget();
|
||||
reset.action = () -> {
|
||||
setting.reset();
|
||||
country.set(ServerSeeker.COUNTRY_MAP.get("UN"));
|
||||
nameLabel.set("Any");
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Country parseImpl(String str) {
|
||||
return ServerSeeker.COUNTRY_MAP.get(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValueValid(Country value) {
|
||||
return value.code != null && ServerSeeker.COUNTRY_MAP.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NbtCompound save(NbtCompound tag) {
|
||||
tag.putString("value", get().code);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Country load(NbtCompound tag) {
|
||||
return ServerSeeker.COUNTRY_MAP.get(tag.getString("value"));
|
||||
}
|
||||
|
||||
public static class Builder extends SettingBuilder<Builder, Country, CountrySetting> {
|
||||
private Predicate<Country> filter;
|
||||
|
||||
public Builder() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
public CountrySetting.Builder filter(Predicate<Country> filter) {
|
||||
this.filter = filter;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CountrySetting build() {
|
||||
return new CountrySetting(name, description, defaultValue, onChanged, onModuleActivated, visible, filter);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,72 +0,0 @@
|
||||
package de.damcraft.serverseeker.country;
|
||||
|
||||
import de.damcraft.serverseeker.ServerSeeker;
|
||||
import meteordevelopment.meteorclient.gui.GuiTheme;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.WLabel;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.input.WTextBox;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import meteordevelopment.meteorclient.utils.render.color.Color;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
public class CountrySettingScreen extends WindowScreen {
|
||||
private final CountrySetting setting;
|
||||
|
||||
private WTable table;
|
||||
|
||||
private WTextBox filter;
|
||||
private String filterText = "";
|
||||
|
||||
public CountrySettingScreen(GuiTheme theme, CountrySetting setting) {
|
||||
super(theme, "Select Country");
|
||||
|
||||
this.setting = setting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
filter = add(theme.textBox("")).minWidth(400).expandX().widget();
|
||||
filter.setFocused(true);
|
||||
filter.action = () -> {
|
||||
filterText = filter.get().trim();
|
||||
|
||||
table.clear();
|
||||
initTable();
|
||||
};
|
||||
|
||||
table = add(theme.table()).expandX().widget();
|
||||
|
||||
initTable();
|
||||
}
|
||||
|
||||
private void initTable() {
|
||||
Collection<Country> countries = ServerSeeker.COUNTRY_MAP.values();
|
||||
// Sort alphabetically. Save to array to avoid concurrent modification.
|
||||
Country[] countryArray = countries.toArray(new Country[0]);
|
||||
Arrays.sort(countryArray);
|
||||
|
||||
for (Country country : countryArray) {
|
||||
if (setting.filter != null && !setting.filter.test(country)) continue;
|
||||
boolean isSelected = country == setting.get();
|
||||
if (!filterText.isEmpty() && (
|
||||
!StringUtils.containsIgnoreCase(country.name, filterText) && !StringUtils.containsIgnoreCase(country.code, filterText)
|
||||
)) continue;
|
||||
table.add(new WCountry(country)).widget();
|
||||
|
||||
WLabel label = table.add(theme.label(country.name)).widget();
|
||||
if (isSelected) label.color = Color.GREEN;
|
||||
|
||||
WButton select = table.add(theme.button("Select")).expandCellX().right().widget();
|
||||
select.action = () -> {
|
||||
setting.set(country);
|
||||
close();
|
||||
};
|
||||
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,10 +0,0 @@
|
||||
package de.damcraft.serverseeker.country;
|
||||
|
||||
/**
|
||||
* Default texture, always loaded, should only be used for UN
|
||||
*/
|
||||
public class DefaultCountry extends Country {
|
||||
public DefaultCountry(String name, String code) {
|
||||
super(name, code);
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
package de.damcraft.serverseeker.country;
|
||||
|
||||
import meteordevelopment.meteorclient.gui.renderer.GuiRenderer;
|
||||
import meteordevelopment.meteorclient.gui.widgets.WWidget;
|
||||
import meteordevelopment.meteorclient.renderer.Texture;
|
||||
|
||||
public class WCountry extends WWidget {
|
||||
|
||||
private Country country;
|
||||
|
||||
public WCountry(Country country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
public void set(Country country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCalculateSize() {
|
||||
double s = theme.scale(32);
|
||||
|
||||
width = s;
|
||||
height = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRender(GuiRenderer renderer, double mouseX, double mouseY, double delta) {
|
||||
Texture texture = this.country.getTexture();
|
||||
if (texture == null) return;
|
||||
|
||||
int wanted_height = (int) (super.width * texture.height / texture.width);
|
||||
|
||||
// Center y
|
||||
int wanted_y = (int) (y + (super.height - wanted_height) / 2);
|
||||
|
||||
if (texture.isValid()) {
|
||||
renderer.texture(x, wanted_y, super.width, wanted_height, 0, texture);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,511 +0,0 @@
|
||||
package de.damcraft.serverseeker.gui;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import de.damcraft.serverseeker.ServerSeeker;
|
||||
import de.damcraft.serverseeker.SmallHttp;
|
||||
import de.damcraft.serverseeker.country.Country;
|
||||
import de.damcraft.serverseeker.country.CountrySetting;
|
||||
import de.damcraft.serverseeker.ssapi.requests.ServersRequest;
|
||||
import de.damcraft.serverseeker.ssapi.responses.ServersResponse;
|
||||
import de.damcraft.serverseeker.utils.MCVersionUtil;
|
||||
import de.damcraft.serverseeker.utils.MultiplayerScreenUtil;
|
||||
import meteordevelopment.meteorclient.gui.GuiThemes;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WContainer;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import meteordevelopment.meteorclient.settings.*;
|
||||
import meteordevelopment.meteorclient.utils.network.MeteorExecutor;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.network.ServerAddress;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
|
||||
public class FindNewServersScreen extends WindowScreen {
|
||||
public static NbtCompound savedSettings;
|
||||
private int timer;
|
||||
public WButton findButton;
|
||||
private boolean threadHasFinished;
|
||||
private String threadError;
|
||||
private List<ServersResponse.Server> threadServers;
|
||||
|
||||
public enum Cracked {
|
||||
Any,
|
||||
Yes,
|
||||
No;
|
||||
|
||||
public Boolean toBoolOrNull() {
|
||||
return switch (this) {
|
||||
case Any -> null;
|
||||
case Yes -> true;
|
||||
case No -> false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum Version {
|
||||
Current,
|
||||
Any,
|
||||
Protocol,
|
||||
VersionString;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return switch (this) {
|
||||
case Current -> "Current";
|
||||
case Any -> "Any";
|
||||
case Protocol -> "Protocol";
|
||||
case VersionString -> "Version String";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum NumRangeType {
|
||||
Any,
|
||||
Equals,
|
||||
AtLeast,
|
||||
AtMost,
|
||||
Between;
|
||||
@Override
|
||||
public String toString() {
|
||||
return switch (this) {
|
||||
case Any -> "Any";
|
||||
case Equals -> "Equal To";
|
||||
case AtLeast -> "At Least";
|
||||
case AtMost -> "At Most";
|
||||
case Between -> "Between";
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't have a better name
|
||||
public enum GeoSearchType {
|
||||
None,
|
||||
ASN,
|
||||
Country
|
||||
}
|
||||
|
||||
private final Settings settings = new Settings();
|
||||
private final SettingGroup sg = settings.getDefaultGroup();
|
||||
WContainer settingsContainer;
|
||||
|
||||
private final Setting<Cracked> crackedSetting = sg.add(new EnumSetting.Builder<Cracked>()
|
||||
.name("cracked")
|
||||
.description("Whether the server should be cracked or not")
|
||||
.defaultValue(Cracked.Any)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<NumRangeType> onlinePlayersNumTypeSetting = sg.add(new EnumSetting.Builder<NumRangeType>()
|
||||
.name("online-players-range")
|
||||
.description("The type of number range for the online players")
|
||||
.defaultValue(NumRangeType.Any)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> equalsOnlinePlayersSetting = sg.add(new IntSetting.Builder()
|
||||
.name("online-players")
|
||||
.description("The amount of online players the server should have")
|
||||
.defaultValue(2)
|
||||
.min(0)
|
||||
.visible(() -> onlinePlayersNumTypeSetting.get().equals(NumRangeType.Equals))
|
||||
.noSlider()
|
||||
.build()
|
||||
);
|
||||
|
||||
|
||||
private final Setting<Integer> atLeastOnlinePlayersSetting = sg.add(new IntSetting.Builder()
|
||||
.name("minimum-online-players")
|
||||
.description("The minimum amount of online players the server should have")
|
||||
.defaultValue(1)
|
||||
.min(0)
|
||||
.visible(() -> onlinePlayersNumTypeSetting.get().equals(NumRangeType.AtLeast) || onlinePlayersNumTypeSetting.get().equals(NumRangeType.Between))
|
||||
.noSlider()
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> atMostOnlinePlayersSetting = sg.add(new IntSetting.Builder()
|
||||
.name("maximum-online-players")
|
||||
.description("The maximum amount of online players the server should have")
|
||||
.defaultValue(20)
|
||||
.min(0)
|
||||
.visible(() -> onlinePlayersNumTypeSetting.get().equals(NumRangeType.AtMost) || onlinePlayersNumTypeSetting.get().equals(NumRangeType.Between))
|
||||
.noSlider()
|
||||
.build()
|
||||
);
|
||||
|
||||
|
||||
private final Setting<NumRangeType> maxPlayersNumTypeSetting = sg.add(new EnumSetting.Builder<NumRangeType>()
|
||||
.name("max-players-range")
|
||||
.description("The type of number range for the max players")
|
||||
.defaultValue(NumRangeType.Any)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> equalsMaxPlayersSetting = sg.add(new IntSetting.Builder()
|
||||
.name("max-players")
|
||||
.description("The amount of max players the server should have")
|
||||
.defaultValue(2)
|
||||
.min(0)
|
||||
.visible(() -> maxPlayersNumTypeSetting.get().equals(NumRangeType.Equals))
|
||||
.noSlider()
|
||||
.build()
|
||||
);
|
||||
|
||||
|
||||
private final Setting<Integer> atLeastMaxPlayersSetting = sg.add(new IntSetting.Builder()
|
||||
.name("minimum-max-players")
|
||||
.description("The minimum amount of max players the server should have")
|
||||
.defaultValue(1)
|
||||
.min(0)
|
||||
.visible(() -> maxPlayersNumTypeSetting.get().equals(NumRangeType.AtLeast) || maxPlayersNumTypeSetting.get().equals(NumRangeType.Between))
|
||||
.noSlider()
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> atMostMaxPlayersSetting = sg.add(new IntSetting.Builder()
|
||||
.name("maximum-max-players")
|
||||
.description("The maximum amount of max players the server should have")
|
||||
.defaultValue(20)
|
||||
.min(0)
|
||||
.visible(() -> maxPlayersNumTypeSetting.get().equals(NumRangeType.AtMost) || maxPlayersNumTypeSetting.get().equals(NumRangeType.Between))
|
||||
.noSlider()
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<String> descriptionSetting = sg.add(new StringSetting.Builder()
|
||||
.name("MOTD")
|
||||
.description("What the MOTD of the server should contain (empty for any)")
|
||||
.defaultValue("")
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<ServersRequest.Software> softwareSetting = sg.add(new EnumSetting.Builder<ServersRequest.Software>()
|
||||
.name("software")
|
||||
.description("The server software the servers should have")
|
||||
.defaultValue(ServersRequest.Software.Any)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Version> versionSetting = sg.add(new EnumSetting.Builder<Version>()
|
||||
.name("version")
|
||||
.description("The protocol version the servers should have")
|
||||
.defaultValue(Version.Current)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> protocolVersionSetting = sg.add(new IntSetting.Builder()
|
||||
.name("protocol")
|
||||
.description("The protocol version the servers should have")
|
||||
.defaultValue(SharedConstants.getProtocolVersion())
|
||||
.visible(() -> versionSetting.get() == Version.Protocol)
|
||||
.min(0)
|
||||
.noSlider()
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<String> versionStringSetting = sg.add(new StringSetting.Builder()
|
||||
.name("version-string")
|
||||
.description("The version string (e.g. 1.19.3) of the protocol version the server should have, results may contain different versions that have the same protocol version. Must be at least 1.7.1")
|
||||
.defaultValue("1.20.2")
|
||||
.visible(() -> versionSetting.get() == Version.VersionString)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Boolean> onlineOnlySetting = sg.add(new BoolSetting.Builder()
|
||||
.name("online-only")
|
||||
.description("Whether to only show servers that are online")
|
||||
.defaultValue(true)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Boolean> ignoreModded = sg.add(new BoolSetting.Builder()
|
||||
.name("ignore-modded")
|
||||
.description("Will not give you servers where mods have been detected")
|
||||
.defaultValue(true)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Boolean> onlyBungeeSpoofable = sg.add(new BoolSetting.Builder()
|
||||
.name("only-bungee-spoofable")
|
||||
.description("Will only give you servers where you can use BungeeSpoof")
|
||||
.defaultValue(false)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<GeoSearchType> geoSearchTypeSetting = sg.add(new EnumSetting.Builder<GeoSearchType>()
|
||||
.name("geo-search-type")
|
||||
.description("Whether to search by ASN or country code")
|
||||
.defaultValue(GeoSearchType.Country)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> asnNumberSetting = sg.add(new IntSetting.Builder()
|
||||
.name("asn")
|
||||
.description("The ASN of the server")
|
||||
.defaultValue(24940)
|
||||
.noSlider()
|
||||
.visible(() -> geoSearchTypeSetting.get() == GeoSearchType.ASN)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Country> countrySetting = sg.add(new CountrySetting.Builder()
|
||||
.name("country")
|
||||
.description("The country the server should be located in")
|
||||
.defaultValue(ServerSeeker.COUNTRY_MAP.get("UN"))
|
||||
.visible(() -> geoSearchTypeSetting.get() == GeoSearchType.Country)
|
||||
.build()
|
||||
);
|
||||
|
||||
|
||||
MultiplayerScreen multiplayerScreen;
|
||||
|
||||
|
||||
public FindNewServersScreen(MultiplayerScreen multiplayerScreen) {
|
||||
super(GuiThemes.get(), "Find new servers");
|
||||
this.multiplayerScreen = multiplayerScreen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
loadSettings();
|
||||
onClosed(this::saveSettings);
|
||||
settingsContainer = add(theme.verticalList()).widget();
|
||||
settingsContainer.add(theme.settings(settings));
|
||||
add(theme.button("Reset all")).expandX().widget().action = this::resetSettings;
|
||||
findButton = add(theme.button("Find")).expandX().widget();
|
||||
findButton.action = () -> {
|
||||
ServersRequest request = new ServersRequest();
|
||||
|
||||
switch (onlinePlayersNumTypeSetting.get()) {
|
||||
// [n, "inf"]
|
||||
case AtLeast -> request.setOnlinePlayers(atLeastOnlinePlayersSetting.get(), -1);
|
||||
|
||||
// [0, n]
|
||||
case AtMost -> request.setOnlinePlayers(0, atMostOnlinePlayersSetting.get());
|
||||
|
||||
// [min, max]
|
||||
case Between -> request.setOnlinePlayers(atLeastOnlinePlayersSetting.get(), atMostOnlinePlayersSetting.get());
|
||||
|
||||
// [n, n]
|
||||
case Equals -> request.setOnlinePlayers(equalsOnlinePlayersSetting.get());
|
||||
}
|
||||
|
||||
switch (maxPlayersNumTypeSetting.get()) {
|
||||
// [n, "inf"]
|
||||
case AtLeast -> request.setMaxPlayers(atLeastMaxPlayersSetting.get(), -1);
|
||||
|
||||
// [0, n]
|
||||
case AtMost -> request.setMaxPlayers(0, atMostMaxPlayersSetting.get());
|
||||
|
||||
// [min, max]
|
||||
case Between -> request.setMaxPlayers(atLeastMaxPlayersSetting.get(), atMostMaxPlayersSetting.get());
|
||||
|
||||
// [n, n]
|
||||
case Equals -> request.setMaxPlayers(equalsMaxPlayersSetting.get());
|
||||
}
|
||||
|
||||
|
||||
switch (geoSearchTypeSetting.get()) {
|
||||
case ASN -> request.setAsn(asnNumberSetting.get());
|
||||
case Country -> {
|
||||
if (countrySetting.get().name.equalsIgnoreCase("any")) break;
|
||||
request.setCountryCode(countrySetting.get().code);
|
||||
}
|
||||
}
|
||||
|
||||
request.setCracked(crackedSetting.get().toBoolOrNull());
|
||||
request.setDescription(descriptionSetting.get());
|
||||
request.setSoftware(softwareSetting.get());
|
||||
|
||||
switch (versionSetting.get()) {
|
||||
case Protocol -> request.setProtocolVersion(protocolVersionSetting.get());
|
||||
case VersionString -> {
|
||||
Integer protocol = MCVersionUtil.versionToProtocol(versionStringSetting.get());
|
||||
if (protocol == null) {
|
||||
clear();
|
||||
add(theme.label("Unknown version string"));
|
||||
return;
|
||||
}
|
||||
request.setProtocolVersion(protocol);
|
||||
}
|
||||
case Current -> request.setProtocolVersion(SharedConstants.getProtocolVersion());
|
||||
}
|
||||
|
||||
if (!onlineOnlySetting.get()) request.setOnlineAfter(0);
|
||||
if (ignoreModded.get()) request.setIgnoreModded(true);
|
||||
if (onlyBungeeSpoofable.get()) request.setOnlyBungeeSpoofable(true);
|
||||
|
||||
|
||||
this.locked = true;
|
||||
|
||||
this.threadHasFinished = false;
|
||||
this.threadError = null;
|
||||
this.threadServers = null;
|
||||
|
||||
|
||||
MeteorExecutor.execute(() -> {
|
||||
String jsonResp = SmallHttp.post("https://api.serverseeker.net/servers", request.json());
|
||||
|
||||
ServersResponse resp = gson.fromJson(jsonResp, ServersResponse.class);
|
||||
|
||||
// Set error message if there is one
|
||||
if (resp.isError()) {
|
||||
this.threadError = resp.error;
|
||||
this.threadHasFinished = true;
|
||||
return;
|
||||
}
|
||||
this.threadServers = resp.data;
|
||||
this.threadHasFinished = true;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
settings.tick(settingsContainer, theme);
|
||||
|
||||
if (threadHasFinished) handleThreadFinish();
|
||||
|
||||
if (locked) {
|
||||
if (timer > 2) {
|
||||
findButton.set(getNext(findButton));
|
||||
timer = 0;
|
||||
}
|
||||
else {
|
||||
timer++;
|
||||
}
|
||||
}
|
||||
|
||||
else if (!findButton.getText().equals("Find")) {
|
||||
findButton.set("Find");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClosed() {
|
||||
ServerSeeker.COUNTRY_MAP.values().forEach(Country::dispose);
|
||||
}
|
||||
|
||||
private String getNext(WButton add) {
|
||||
return switch (add.getText()) {
|
||||
case "Find", "oo0" -> "ooo";
|
||||
case "ooo" -> "0oo";
|
||||
case "0oo" -> "o0o";
|
||||
case "o0o" -> "oo0";
|
||||
default -> "Find";
|
||||
};
|
||||
}
|
||||
|
||||
private void handleThreadFinish() {
|
||||
this.threadHasFinished = false;
|
||||
this.locked = false;
|
||||
if (this.threadError != null) {
|
||||
clear();
|
||||
add(theme.label(this.threadError)).expandX();
|
||||
WButton backButton = add(theme.button("Back")).expandX().widget();
|
||||
backButton.action = this::reload;
|
||||
this.locked = false;
|
||||
return;
|
||||
}
|
||||
clear();
|
||||
List<ServersResponse.Server> servers = this.threadServers;
|
||||
|
||||
if (servers.isEmpty()) {
|
||||
add(theme.label("No servers found")).expandX();
|
||||
WButton backButton = add(theme.button("Back")).expandX().widget();
|
||||
backButton.action = this::reload;
|
||||
this.locked = false;
|
||||
return;
|
||||
}
|
||||
add(theme.label("Found " + servers.size() + " servers")).expandX();
|
||||
WButton addAllButton = add(theme.button("Add all")).expandX().widget();
|
||||
addAllButton.action = () -> {
|
||||
for (ServersResponse.Server server : servers) {
|
||||
String ip = server.server;
|
||||
|
||||
// Add server to list
|
||||
MultiplayerScreenUtil.addNameIpToServerList(multiplayerScreen, "ServerSeeker " + ip, ip, false);
|
||||
}
|
||||
MultiplayerScreenUtil.saveList(multiplayerScreen);
|
||||
|
||||
// Reload widget
|
||||
MultiplayerScreenUtil.reloadServerList(multiplayerScreen);
|
||||
|
||||
// Close screen
|
||||
if (this.client == null) return;
|
||||
client.setScreen(this.multiplayerScreen);
|
||||
};
|
||||
|
||||
WTable table = add(theme.table()).widget();
|
||||
|
||||
table.add(theme.label("Server IP"));
|
||||
table.add(theme.label("Version"));
|
||||
|
||||
|
||||
table.row();
|
||||
|
||||
table.add(theme.horizontalSeparator()).expandX();
|
||||
table.row();
|
||||
|
||||
|
||||
for (ServersResponse.Server server : servers) {
|
||||
final String serverIP = server.server;
|
||||
String serverVersion = server.version;
|
||||
|
||||
table.add(theme.label(serverIP));
|
||||
table.add(theme.label(serverVersion));
|
||||
|
||||
WButton addServerButton = theme.button("Add Server");
|
||||
addServerButton.action = () -> {
|
||||
System.out.println(multiplayerScreen.getServerList() == null);
|
||||
ServerInfo info = new ServerInfo("ServerSeeker " + serverIP, serverIP, ServerInfo.ServerType.OTHER);
|
||||
MultiplayerScreenUtil.addInfoToServerList(multiplayerScreen, info);
|
||||
addServerButton.visible = false;
|
||||
};
|
||||
|
||||
WButton joinServerButton = theme.button("Join Server");
|
||||
HostAndPort hap = HostAndPort.fromString(serverIP);
|
||||
|
||||
joinServerButton.action = ()
|
||||
-> ConnectScreen.connect(new TitleScreen(), MinecraftClient.getInstance(), new ServerAddress(hap.getHost(), hap.getPort()), new ServerInfo("a", hap.toString(), ServerInfo.ServerType.OTHER), false, null);
|
||||
|
||||
WButton serverInfoButton = theme.button("Server Info");
|
||||
serverInfoButton.action = () -> this.client.setScreen(new ServerInfoScreen(serverIP));
|
||||
|
||||
table.add(addServerButton);
|
||||
table.add(joinServerButton);
|
||||
table.add(serverInfoButton);
|
||||
|
||||
table.row();
|
||||
}
|
||||
|
||||
this.locked = false;
|
||||
}
|
||||
|
||||
public void saveSettings() {
|
||||
savedSettings = sg.toTag();
|
||||
}
|
||||
|
||||
public void loadSettings() {
|
||||
if (savedSettings == null) return;
|
||||
sg.fromTag(savedSettings);
|
||||
}
|
||||
|
||||
public void resetSettings() {
|
||||
for (Setting<?> setting : sg) {
|
||||
setting.reset();
|
||||
}
|
||||
saveSettings();
|
||||
reload();
|
||||
}
|
||||
}
|
@@ -1,174 +0,0 @@
|
||||
package de.damcraft.serverseeker.gui;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import de.damcraft.serverseeker.SmallHttp;
|
||||
import de.damcraft.serverseeker.ssapi.requests.WhereisRequest;
|
||||
import de.damcraft.serverseeker.ssapi.responses.WhereisResponse;
|
||||
import de.damcraft.serverseeker.utils.MultiplayerScreenUtil;
|
||||
import meteordevelopment.meteorclient.gui.GuiThemes;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WContainer;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import meteordevelopment.meteorclient.settings.*;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.network.ServerAddress;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.List;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
public class FindPlayerScreen extends WindowScreen {
|
||||
private final MultiplayerScreen multiplayerScreen;
|
||||
|
||||
public enum NameOrUUID {
|
||||
Name,
|
||||
UUID
|
||||
}
|
||||
|
||||
private final Settings settings = new Settings();
|
||||
private final SettingGroup sg = settings.getDefaultGroup();
|
||||
|
||||
private final Setting<NameOrUUID> nameOrUUID = sg.add(new EnumSetting.Builder<NameOrUUID>()
|
||||
.name("name-or-uuid")
|
||||
.description("Whether to search by name or UUID.")
|
||||
.defaultValue(NameOrUUID.Name)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<String> name = sg.add(new StringSetting.Builder()
|
||||
.name("name")
|
||||
.description("The name to search for.")
|
||||
.defaultValue("")
|
||||
.visible(() -> nameOrUUID.get() == NameOrUUID.Name)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<String> uuid = sg.add(new StringSetting.Builder()
|
||||
.name("UUID")
|
||||
.description("The UUID to search for.")
|
||||
.defaultValue("")
|
||||
.visible(() -> nameOrUUID.get() == NameOrUUID.UUID)
|
||||
.build()
|
||||
);
|
||||
|
||||
WContainer settingsContainer;
|
||||
|
||||
public FindPlayerScreen(MultiplayerScreen multiplayerScreen) {
|
||||
super(GuiThemes.get(), "Find Players");
|
||||
this.multiplayerScreen = multiplayerScreen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
WContainer settingsContainer = add(theme.verticalList()).widget();
|
||||
settingsContainer.add(theme.settings(settings)).expandX();
|
||||
|
||||
this.settingsContainer = settingsContainer;
|
||||
|
||||
add(theme.button("Find Player")).expandX().widget().action = () -> {
|
||||
|
||||
WhereisRequest request = new WhereisRequest();
|
||||
|
||||
switch (nameOrUUID.get()) {
|
||||
case Name -> request.setName(name.get());
|
||||
case UUID -> request.setUuid(uuid.get());
|
||||
}
|
||||
|
||||
String jsonResponse = SmallHttp.post("https://api.serverseeker.net/whereis", request.json());
|
||||
|
||||
WhereisResponse resp = gson.fromJson(jsonResponse, WhereisResponse.class);
|
||||
|
||||
// Set error message if there is one
|
||||
if (resp.isError()) {
|
||||
clear();
|
||||
add(theme.label(resp.error)).expandX();
|
||||
return;
|
||||
}
|
||||
clear();
|
||||
|
||||
List<WhereisResponse.Record> data = resp.data;
|
||||
if (data.isEmpty()) {
|
||||
clear();
|
||||
add(theme.label("Not found")).expandX();
|
||||
return;
|
||||
}
|
||||
add(theme.label("Found " + data.size() + " servers:"));
|
||||
WTable table = add(theme.table()).widget();
|
||||
WButton addAllButton = table.add(theme.button("Add all")).expandX().widget();
|
||||
addAllButton.action = () -> addAllServers(data);
|
||||
|
||||
table.row();
|
||||
table.add(theme.label("Server IP"));
|
||||
table.add(theme.label("Player name"));
|
||||
table.add(theme.label("Last seen"));
|
||||
|
||||
table.row();
|
||||
table.add(theme.horizontalSeparator()).expandX();
|
||||
table.row();
|
||||
|
||||
|
||||
for (WhereisResponse.Record server : data) {
|
||||
String serverIP = server.server;
|
||||
String playerName = server.name;
|
||||
long playerLastSeen = server.last_seen; // Unix timestamp
|
||||
|
||||
// Format last seen to human-readable
|
||||
String playerLastSeenFormatted = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
|
||||
.format(Instant.ofEpochSecond(playerLastSeen).atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
int minWidth = (int)(mc.getWindow().getWidth() * 0.2);
|
||||
table.add(theme.label(serverIP)).minWidth(minWidth);
|
||||
table.add(theme.label(playerName)).minWidth(minWidth);
|
||||
table.add(theme.label(playerLastSeenFormatted)).minWidth(minWidth);
|
||||
|
||||
WButton addServerButton = theme.button("Add Server");
|
||||
addServerButton.action = () -> {
|
||||
ServerInfo info = new ServerInfo("ServerSeeker " + serverIP + " (Player: " + playerName + ")", serverIP, ServerInfo.ServerType.OTHER);
|
||||
MultiplayerScreenUtil.addInfoToServerList(multiplayerScreen, info);
|
||||
addServerButton.visible = false;
|
||||
};
|
||||
|
||||
HostAndPort hap = HostAndPort.fromString(serverIP);
|
||||
WButton joinServerButton = theme.button("Join Server");
|
||||
joinServerButton.action = () -> {
|
||||
ConnectScreen.connect(new TitleScreen(), MinecraftClient.getInstance(), new ServerAddress(hap.getHost(), hap.getPort()), new ServerInfo("a", hap.toString(), ServerInfo.ServerType.OTHER), false, null);
|
||||
};
|
||||
|
||||
WButton serverInfoButton = theme.button("Server Info");
|
||||
serverInfoButton.action = () -> this.client.setScreen(new ServerInfoScreen(serverIP));
|
||||
|
||||
table.add(addServerButton);
|
||||
table.add(joinServerButton);
|
||||
table.add(serverInfoButton);
|
||||
table.row();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void addAllServers(List<WhereisResponse.Record> records) {
|
||||
for (WhereisResponse.Record record : records) {
|
||||
String serverIP = record.server;
|
||||
String playerName = record.name;
|
||||
ServerInfo info = new ServerInfo("ServerSeeker " + serverIP + " (Player: " + playerName + ")", serverIP, ServerInfo.ServerType.OTHER);
|
||||
MultiplayerScreenUtil.addInfoToServerList(multiplayerScreen, info, false);
|
||||
}
|
||||
MultiplayerScreenUtil.saveList(multiplayerScreen);
|
||||
if (client == null) return;
|
||||
client.setScreen(this.multiplayerScreen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
settings.tick(settingsContainer, theme);
|
||||
}
|
||||
}
|
@@ -1,186 +0,0 @@
|
||||
package de.damcraft.serverseeker.gui;
|
||||
|
||||
import de.damcraft.serverseeker.ServerSeekerSystem;
|
||||
import de.damcraft.serverseeker.SmallHttp;
|
||||
import de.damcraft.serverseeker.ssapi.requests.ServerInfoRequest;
|
||||
import de.damcraft.serverseeker.ssapi.responses.ServerInfoResponse;
|
||||
import meteordevelopment.meteorclient.gui.GuiThemes;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import meteordevelopment.meteorclient.systems.accounts.Account;
|
||||
import meteordevelopment.meteorclient.systems.accounts.Accounts;
|
||||
import meteordevelopment.meteorclient.systems.accounts.types.CrackedAccount;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.List;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
public class GetInfoScreen extends WindowScreen {
|
||||
MultiplayerServerListWidget.Entry entry;
|
||||
|
||||
private boolean waitingForAuth = false;
|
||||
|
||||
public GetInfoScreen(MultiplayerScreen multiplayerScreen, MultiplayerServerListWidget.Entry entry) {
|
||||
super(GuiThemes.get(), "Get players");
|
||||
this.parent = multiplayerScreen;
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
if (entry == null) {
|
||||
add(theme.label("No server selected"));
|
||||
return;
|
||||
}
|
||||
|
||||
String apiKey = ServerSeekerSystem.get().apiKey;
|
||||
if (apiKey.isEmpty()) {
|
||||
WHorizontalList widgetList = add(theme.horizontalList()).expandX().widget();
|
||||
widgetList.add(theme.label("Please authenticate with Discord. "));
|
||||
waitingForAuth = true;
|
||||
WButton loginButton = widgetList.add(theme.button("Login")).widget();
|
||||
loginButton.action = () -> {
|
||||
if (this.client == null) return;
|
||||
this.client.setScreen(new LoginWithDiscordScreen(this));
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
// Get info about the server
|
||||
if (!(entry instanceof MultiplayerServerListWidget.ServerEntry)) {
|
||||
add(theme.label("No server selected"));
|
||||
return;
|
||||
}
|
||||
ServerInfo serverInfo = ((MultiplayerServerListWidget.ServerEntry) entry).getServer();
|
||||
String address = serverInfo.address;
|
||||
|
||||
// Check if the server matches the regex for ip(:port)
|
||||
if (!address.matches("^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}(?::[0-9]{1,5})?$")) {
|
||||
add(theme.label("You can only get player info for servers with an IP address"));
|
||||
return;
|
||||
}
|
||||
String ip = address.split(":")[0];
|
||||
int port = address.split(":").length > 1 ? Integer.parseInt(address.split(":")[1]) : 25565;
|
||||
|
||||
// Get the players using the API
|
||||
/* {
|
||||
"api_key": "...", // Your api_key
|
||||
"ip": "109.123.240.84", // The ip of the server
|
||||
"port": 25565 // The port of the server (defaults to 25565)
|
||||
} */
|
||||
ServerInfoRequest request = new ServerInfoRequest();
|
||||
|
||||
request.setIpPort(ip, port);
|
||||
|
||||
String jsonResp = SmallHttp.post("https://api.serverseeker.net/server_info", request.json());
|
||||
|
||||
ServerInfoResponse resp = gson.fromJson(jsonResp, ServerInfoResponse.class);
|
||||
|
||||
// Set error message if there is one
|
||||
if (resp.isError()) {
|
||||
clear();
|
||||
add(theme.label(resp.error)).expandX();
|
||||
return;
|
||||
}
|
||||
|
||||
clear();
|
||||
List<ServerInfoResponse.Player> players = resp.players;
|
||||
if (players.isEmpty()) {
|
||||
clear();
|
||||
add(theme.label("No records of players found.")).expandX();
|
||||
return;
|
||||
}
|
||||
/* "players": [ // An array of when which players were seen on the server. Limited to 1000
|
||||
{
|
||||
"last_seen": 1683790506, // The last time the player was seen on the server (unix timestamp)
|
||||
"name": "DAMcraft", // The name of the player
|
||||
"uuid": "68af4d98-24a2-41b6-96bc-a9c2ef9b397b" // The uuid of the player
|
||||
}, ...
|
||||
] */
|
||||
boolean cracked = false;
|
||||
if (resp.cracked != null) {
|
||||
cracked = resp.cracked;
|
||||
}
|
||||
|
||||
if (!cracked) {
|
||||
add(theme.label("Attention: The server is NOT cracked!")).expandX();
|
||||
add(theme.label("")).expandX();
|
||||
}
|
||||
String playersLabel = players.size() == 1 ? " player:" : " players:";
|
||||
add(theme.label("Found " + players.size() + playersLabel));
|
||||
|
||||
WTable table = add(theme.table()).widget();
|
||||
|
||||
table.add(theme.label("Name "));
|
||||
table.add(theme.label("Last seen "));
|
||||
table.add(theme.label("Login (cracked)"));
|
||||
table.row();
|
||||
|
||||
table.add(theme.horizontalSeparator()).expandX();
|
||||
table.row();
|
||||
|
||||
for (ServerInfoResponse.Player player : players) {
|
||||
String name = player.name;
|
||||
long lastSeen = player.last_seen;
|
||||
String lastSeenFormatted = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
|
||||
.format(Instant.ofEpochSecond(lastSeen).atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
|
||||
table.add(theme.label(name + " "));
|
||||
table.add(theme.label(lastSeenFormatted + " "));
|
||||
|
||||
if (mc.getSession().getUsername().equals(name)) {
|
||||
table.add(theme.label("Logged in")).expandCellX();
|
||||
} else {
|
||||
|
||||
WButton loginButton = table.add(theme.button("Login")).widget();
|
||||
// Check if the user is currently logged in
|
||||
if (mc.getSession().getUsername().equals(name)) {
|
||||
loginButton.visible = false;
|
||||
}
|
||||
|
||||
// Log in the user
|
||||
loginButton.action = () -> {
|
||||
loginButton.visible = false;
|
||||
if (this.client == null) return;
|
||||
// Check if the account already exists
|
||||
boolean exists = false;
|
||||
for (Account<?> account : Accounts.get()) {
|
||||
if (account instanceof CrackedAccount && account.getUsername().equals(name)) {
|
||||
account.login();
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!exists) {
|
||||
CrackedAccount account = new CrackedAccount(name);
|
||||
account.login();
|
||||
Accounts.get().add(account);
|
||||
}
|
||||
close();
|
||||
};
|
||||
}
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (waitingForAuth) {
|
||||
String authToken = ServerSeekerSystem.get().apiKey;
|
||||
if (!authToken.isEmpty()) {
|
||||
this.reload();
|
||||
this.waitingForAuth = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,132 +0,0 @@
|
||||
package de.damcraft.serverseeker.gui;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import de.damcraft.serverseeker.SmallHttp;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.gui.DrawContext;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.client.gui.widget.TextWidget;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.file.*;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class InstallMeteorScreen extends Screen {
|
||||
public InstallMeteorScreen() {
|
||||
super(Text.of("Meteor Client is not installed!"));
|
||||
}
|
||||
|
||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||
super.render(context, mouseX, mouseY, delta);
|
||||
context.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, this.height / 4 - 60 + 20, -1);
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
super.init();
|
||||
ButtonWidget quitButton = this.addDrawableChild(ButtonWidget.builder(Text.translatable("menu.quit"), (button) -> {
|
||||
this.client.scheduleStop();
|
||||
}).dimensions(this.width / 2 + 2, this.height / 4 + 100 + 25, 148, 20).build());
|
||||
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.of("Automatically install Meteor (§arecommended§r)"), (button) -> {
|
||||
quitButton.active = false;
|
||||
CompletableFuture.runAsync(() -> {
|
||||
install();
|
||||
quitButton.active = true;
|
||||
});
|
||||
}).dimensions(this.width / 2 - 150, this.height / 4 + 100, 300, 20).build());
|
||||
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.of("Manual installation"), (button) -> {
|
||||
Util.getOperatingSystem().open("https://meteorclient.com/faq/installation");
|
||||
}).dimensions(this.width / 2 - 150, this.height / 4 + 100 + 25, 148, 20).build());
|
||||
}
|
||||
|
||||
private void install() {
|
||||
String result = SmallHttp.get("https://meteorclient.com/api/stats");
|
||||
if (result == null) {
|
||||
this.displayError("Failed to get install meteor automatically! Please install it manually.");
|
||||
return;
|
||||
}
|
||||
|
||||
Gson gson = new Gson();
|
||||
JsonObject json = gson.fromJson(result, JsonObject.class);
|
||||
String currentVersion = SharedConstants.getGameVersion().getName();
|
||||
String stableVersion = json.get("mc_version").getAsString();
|
||||
String devBuildVersion = json.get("dev_build_mc_version").getAsString();
|
||||
String url;
|
||||
if (currentVersion.equals(stableVersion)) {
|
||||
url = "https://meteorclient.com/api/download";
|
||||
} else if (currentVersion.equals(devBuildVersion)) {
|
||||
url = "https://meteorclient.com/api/download?devBuild=latest";
|
||||
} else {
|
||||
this.displayError("Failed to find Meteor for your current version.");
|
||||
return;
|
||||
}
|
||||
HttpResponse<InputStream> file = SmallHttp.download(url);
|
||||
if (file == null) {
|
||||
this.displayError("Failed to download Meteor! Please install it manually.");
|
||||
return;
|
||||
}
|
||||
Optional<String> filenameT = file.headers().firstValue("Content-Disposition");
|
||||
String filename = "meteor-client.jar";
|
||||
if (filenameT.isPresent()) {
|
||||
String[] parts = filenameT.get().split("; ");
|
||||
for (String part : parts) {
|
||||
if (part.startsWith("filename=")) {
|
||||
filename = part.substring(9);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filename.startsWith("\"") && filename.endsWith("\"")) {
|
||||
filename = filename.substring(1, filename.length() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the mods folder
|
||||
Path modsFolder = FabricLoader.getInstance().getGameDir().resolve("mods");
|
||||
if (!Files.exists(modsFolder)) {
|
||||
this.displayError("Failed to find mods folder! Please install Meteor manually.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the file
|
||||
try {
|
||||
Files.copy(file.body(), modsFolder.resolve(filename));
|
||||
} catch (IOException | SecurityException | InvalidPathException e) {
|
||||
this.displayError("Failed to save Meteor! Please install it manually.");
|
||||
LogUtils.getLogger().error(e.toString()); // we can't import without causing errors (no meteor)
|
||||
return;
|
||||
}
|
||||
|
||||
// Success message
|
||||
this.displayNotice("Successfully installed Meteor! Please restart your game.");
|
||||
}
|
||||
|
||||
private void displayError(String errorMessage) {
|
||||
this.displayNotice(errorMessage);
|
||||
|
||||
this.addDrawableChild(ButtonWidget.builder(Text.of("Open install FAQ"), (button2) -> {
|
||||
Util.getOperatingSystem().open("https://meteorclient.com/faq/installation");
|
||||
}).dimensions(this.width / 2 - 150, this.height / 4 + 100, 300, 20).build());
|
||||
}
|
||||
|
||||
private void displayNotice(String noticeMessage) {
|
||||
this.clearChildren();
|
||||
this.addDrawableChild(new TextWidget(
|
||||
this.width / 2 - 250,
|
||||
this.height / 4,
|
||||
500,
|
||||
20,
|
||||
Text.of(noticeMessage),
|
||||
this.textRenderer
|
||||
));
|
||||
}
|
||||
}
|
@@ -1,61 +0,0 @@
|
||||
package de.damcraft.serverseeker.gui;
|
||||
|
||||
import de.damcraft.serverseeker.DiscordAuth;
|
||||
import meteordevelopment.meteorclient.gui.GuiThemes;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
public class LoginWithDiscordScreen extends WindowScreen {
|
||||
|
||||
private boolean canClose = false;
|
||||
|
||||
WindowScreen parent;
|
||||
|
||||
public LoginWithDiscordScreen(WindowScreen parent) {
|
||||
super(GuiThemes.get(), "Login with Discord");
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
DiscordAuth.auth((apiKey, error) -> {
|
||||
if (error != null) {
|
||||
this.canClose = true;
|
||||
clear();
|
||||
add(theme.label("Failed to authenticate with Discord. Reason: " + error));
|
||||
return;
|
||||
}
|
||||
if (apiKey == null) {
|
||||
this.canClose = true;
|
||||
clear();
|
||||
add(theme.label("Failed to authenticate with Discord."));
|
||||
return;
|
||||
}
|
||||
close();
|
||||
});
|
||||
add(theme.label("Please authenticate with Discord in your browser."));
|
||||
|
||||
add(theme.label("The browser didn't open? Click below to copy the link and open it manually")).expandX();
|
||||
WButton copy = add(theme.button("Copy")).expandX().widget();
|
||||
copy.action = () -> {
|
||||
String url = DiscordAuth.url;
|
||||
mc.keyboard.setClipboard(url);
|
||||
};
|
||||
|
||||
WButton cancel = add(theme.button("Cancel")).expandX().widget();
|
||||
cancel.action = () -> {
|
||||
DiscordAuth.stopServer();
|
||||
close();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {}
|
||||
|
||||
@Override
|
||||
public boolean shouldCloseOnEsc() {
|
||||
return this.canClose;
|
||||
}
|
||||
}
|
@@ -1,115 +0,0 @@
|
||||
package de.damcraft.serverseeker.gui;
|
||||
|
||||
import com.google.common.net.HostAndPort;
|
||||
import de.damcraft.serverseeker.SmallHttp;
|
||||
import de.damcraft.serverseeker.ssapi.requests.ServerInfoRequest;
|
||||
import de.damcraft.serverseeker.ssapi.responses.ServerInfoResponse;
|
||||
import meteordevelopment.meteorclient.gui.GuiThemes;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.ConnectScreen;
|
||||
import net.minecraft.client.network.ServerAddress;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.List;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
public class ServerInfoScreen extends WindowScreen {
|
||||
private final String serverIp;
|
||||
|
||||
public ServerInfoScreen(String serverIp) {
|
||||
super(GuiThemes.get(), "Server Info: " + serverIp);
|
||||
this.serverIp = serverIp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
add(theme.label("Fetching server info..."));
|
||||
ServerInfoRequest request = new ServerInfoRequest();
|
||||
HostAndPort hap = HostAndPort.fromString(serverIp);
|
||||
request.setIpPort(hap.getHost(), hap.getPort());
|
||||
String jsonResp = SmallHttp.post("https://api.serverseeker.net/server_info", request.json());
|
||||
ServerInfoResponse resp = gson.fromJson(jsonResp, ServerInfoResponse.class);
|
||||
if (resp.isError()) {
|
||||
clear();
|
||||
add(theme.label(resp.error)).expandX();
|
||||
return;
|
||||
}
|
||||
clear();
|
||||
|
||||
Boolean cracked = resp.cracked;
|
||||
String description = resp.description;
|
||||
int onlinePlayers = resp.online_players;
|
||||
int maxPlayers = resp.max_players;
|
||||
int protocol = resp.protocol;
|
||||
int lastSeen = resp.last_seen;
|
||||
String version = resp.version;
|
||||
List<ServerInfoResponse.Player> players = resp.players;
|
||||
|
||||
WTable dataTable = add(theme.table()).widget();
|
||||
WTable playersTable = add(theme.table()).expandX().widget();
|
||||
|
||||
dataTable.add(theme.label("Cracked: "));
|
||||
dataTable.add(theme.label(cracked == null ? "Unknown" : cracked.toString()));
|
||||
dataTable.row();
|
||||
|
||||
dataTable.add(theme.label("Description: "));
|
||||
if (description.length() > 100) description = description.substring(0, 100) + "...";
|
||||
description = description.replace("\n", "\\n");
|
||||
description = description.replace("§r", "");
|
||||
dataTable.add(theme.label(description));
|
||||
dataTable.row();
|
||||
|
||||
dataTable.add(theme.label("Online Players (last scan): "));
|
||||
dataTable.add(theme.label(String.valueOf(onlinePlayers)));
|
||||
dataTable.row();
|
||||
|
||||
dataTable.add(theme.label("Max Players: "));
|
||||
dataTable.add(theme.label(String.valueOf(maxPlayers)));
|
||||
dataTable.row();
|
||||
|
||||
dataTable.add(theme.label("Last Seen: "));
|
||||
String lastSeenDate = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
|
||||
.format(Instant.ofEpochSecond(lastSeen).atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
dataTable.add(theme.label(lastSeenDate));
|
||||
dataTable.row();
|
||||
|
||||
dataTable.add(theme.label("Version: "));
|
||||
dataTable.add(theme.label(version + " (" + protocol + ")"));
|
||||
|
||||
playersTable.add(theme.label(""));
|
||||
playersTable.row();
|
||||
playersTable.add(theme.label("Players:"));
|
||||
playersTable.row();
|
||||
|
||||
|
||||
playersTable.add(theme.label("Name ")).expandX();
|
||||
playersTable.add(theme.label("Last seen ")).expandX();
|
||||
playersTable.row();
|
||||
|
||||
|
||||
playersTable.add(theme.horizontalSeparator()).expandX();
|
||||
playersTable.row();
|
||||
|
||||
for (ServerInfoResponse.Player player : players) {
|
||||
String name = player.name;
|
||||
long playerLastSeen = player.last_seen;
|
||||
String lastSeenFormatted = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
|
||||
.format(Instant.ofEpochSecond(playerLastSeen).atZone(ZoneId.systemDefault()).toLocalDateTime());
|
||||
|
||||
playersTable.add(theme.label(name + " ")).expandX();
|
||||
playersTable.add(theme.label(lastSeenFormatted + " ")).expandX();
|
||||
playersTable.row();
|
||||
}
|
||||
WButton joinServerButton = add(theme.button("Join this Server")).expandX().widget();
|
||||
joinServerButton.action = ()
|
||||
-> ConnectScreen.connect(new TitleScreen(), MinecraftClient.getInstance(), new ServerAddress(hap.getHost(), hap.getPort()), new ServerInfo("a", hap.toString(), ServerInfo.ServerType.OTHER), false, null);
|
||||
}
|
||||
}
|
@@ -1,142 +0,0 @@
|
||||
package de.damcraft.serverseeker.gui;
|
||||
|
||||
import de.damcraft.serverseeker.DiscordAvatar;
|
||||
import de.damcraft.serverseeker.ServerSeekerSystem;
|
||||
import de.damcraft.serverseeker.SmallHttp;
|
||||
import de.damcraft.serverseeker.ssapi.responses.UserInfoResponse;
|
||||
import de.damcraft.serverseeker.utils.MultiplayerScreenUtil;
|
||||
import meteordevelopment.meteorclient.gui.GuiThemes;
|
||||
import meteordevelopment.meteorclient.gui.WindowScreen;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WHorizontalList;
|
||||
import meteordevelopment.meteorclient.gui.widgets.containers.WTable;
|
||||
import meteordevelopment.meteorclient.gui.widgets.pressable.WButton;
|
||||
import meteordevelopment.meteorclient.utils.render.color.Color;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
|
||||
public class ServerSeekerScreen extends WindowScreen {
|
||||
private final MultiplayerScreen multiplayerScreen;
|
||||
|
||||
public ServerSeekerScreen(MultiplayerScreen multiplayerScreen) {
|
||||
super(GuiThemes.get(), "ServerSeeker");
|
||||
this.multiplayerScreen = multiplayerScreen;
|
||||
}
|
||||
private boolean waitingForAuth = false;
|
||||
|
||||
@Override
|
||||
public void initWidgets() {
|
||||
String authToken = ServerSeekerSystem.get().apiKey;
|
||||
|
||||
if (authToken.isEmpty()) {
|
||||
WHorizontalList widgetList = add(theme.horizontalList()).expandX().widget();
|
||||
widgetList.add(theme.label("Please authenticate with Discord. "));
|
||||
waitingForAuth = true;
|
||||
WButton loginButton = widgetList.add(theme.button("Login")).widget();
|
||||
loginButton.action = () -> {
|
||||
if (this.client == null) return;
|
||||
this.client.setScreen(new LoginWithDiscordScreen(this));
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
WHorizontalList accountList = add(theme.horizontalList()).expandX().widget();
|
||||
// Add an image of the user's avatar
|
||||
String avatarUrl = ServerSeekerSystem.get().discordAvatarUrl;
|
||||
if (avatarUrl != null && !avatarUrl.isEmpty()) {
|
||||
accountList.add(theme.texture(32, 32, 0, new DiscordAvatar(ServerSeekerSystem.get().discordAvatarUrl + "?size=32")));
|
||||
}
|
||||
accountList.add(theme.label(ServerSeekerSystem.get().discordUsername)).expandX();
|
||||
WButton logoutButton = accountList.add(theme.button("Logout")).widget();
|
||||
logoutButton.action = () -> {
|
||||
ServerSeekerSystem.get().apiKey = "";
|
||||
ServerSeekerSystem.get().discordId = "";
|
||||
ServerSeekerSystem.get().discordUsername = "";
|
||||
ServerSeekerSystem.get().discordAvatarUrl = "";
|
||||
ServerSeekerSystem.get().save();
|
||||
reload();
|
||||
};
|
||||
WTable userInfoList = add(theme.table()).widget();
|
||||
userInfoList.add(theme.label("Loading..."));
|
||||
|
||||
new Thread(() -> {
|
||||
String reqBody = "{\"api_key\":\"" + authToken + "\"}";
|
||||
String userInfoJson = SmallHttp.post("https://api.serverseeker.net/user_info", reqBody);
|
||||
UserInfoResponse userInfo = gson.fromJson(userInfoJson, UserInfoResponse.class);
|
||||
|
||||
userInfoList.clear();
|
||||
|
||||
userInfoList.add(theme.label("Requests made:"));
|
||||
userInfoList.row();
|
||||
|
||||
int whereisRequestsMade = userInfo.requests_made_whereis;
|
||||
int whereisRequestsTotal = userInfo.requests_per_day_whereis;
|
||||
userInfoList.add(theme.label("Whereis: "));
|
||||
userInfoList.add(theme.label(whereisRequestsMade + "/" + whereisRequestsTotal)).widget().color(whereisRequestsTotal == whereisRequestsMade ? Color.RED : Color.WHITE);
|
||||
userInfoList.row();
|
||||
|
||||
int serversRequestsMade = userInfo.requests_made_servers;
|
||||
int serversRequestsTotal = userInfo.requests_per_day_servers;
|
||||
userInfoList.add(theme.label("Servers: "));
|
||||
userInfoList.add(theme.label(serversRequestsMade + "/" + serversRequestsTotal)).widget().color(serversRequestsTotal == serversRequestsMade ? Color.RED : Color.WHITE);
|
||||
userInfoList.row();
|
||||
|
||||
int serverInfoRequestsMade = userInfo.requests_made_server_info;
|
||||
int serverInfoRequestsTotal = userInfo.requests_per_day_server_info;
|
||||
userInfoList.add(theme.label("Server Info: "));
|
||||
userInfoList.add(theme.label(serverInfoRequestsMade + "/" + serverInfoRequestsTotal)).widget().color(serverInfoRequestsTotal == serverInfoRequestsMade ? Color.RED : Color.WHITE);
|
||||
}).start();
|
||||
|
||||
|
||||
WHorizontalList widgetList = add(theme.horizontalList()).expandX().widget();
|
||||
WButton newServersButton = widgetList.add(this.theme.button("Find new servers")).expandX().widget();
|
||||
WButton findPlayersButton = widgetList.add(this.theme.button("Search players")).expandX().widget();
|
||||
WButton cleanUpServersButton = widgetList.add(this.theme.button("Clean up")).expandX().widget();
|
||||
newServersButton.action = () -> {
|
||||
if (this.client == null) return;
|
||||
this.client.setScreen(new FindNewServersScreen(this.multiplayerScreen));
|
||||
};
|
||||
findPlayersButton.action = () -> {
|
||||
if (this.client == null) return;
|
||||
this.client.setScreen(new FindPlayerScreen(this.multiplayerScreen));
|
||||
};
|
||||
cleanUpServersButton.action = () -> {
|
||||
if (this.client == null) return;
|
||||
clear();
|
||||
add(theme.label("Are you sure you want to clean up your server list?"));
|
||||
add(theme.label("This will remove all servers that start with \"ServerSeeker\""));
|
||||
WHorizontalList buttonList = add(theme.horizontalList()).expandX().widget();
|
||||
WButton backButton = buttonList.add(theme.button("Back")).expandX().widget();
|
||||
backButton.action = this::reload;
|
||||
WButton confirmButton = buttonList.add(theme.button("Confirm")).expandX().widget();
|
||||
confirmButton.action = this::cleanUpServers;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
if (waitingForAuth) {
|
||||
String authToken = ServerSeekerSystem.get().apiKey;
|
||||
if (!authToken.isEmpty()) {
|
||||
this.reload();
|
||||
this.waitingForAuth = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanUpServers() {
|
||||
if (this.client == null) return;
|
||||
|
||||
for (int i = 0; i < this.multiplayerScreen.getServerList().size(); i++) {
|
||||
if (this.multiplayerScreen.getServerList().get(i).name.startsWith("ServerSeeker")) {
|
||||
this.multiplayerScreen.getServerList().remove(this.multiplayerScreen.getServerList().get(i));
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
MultiplayerScreenUtil.saveList(multiplayerScreen);
|
||||
MultiplayerScreenUtil.reloadServerList(multiplayerScreen);
|
||||
|
||||
client.setScreen(this.multiplayerScreen);
|
||||
}
|
||||
}
|
@@ -1,189 +0,0 @@
|
||||
package de.damcraft.serverseeker.hud;
|
||||
|
||||
import de.damcraft.serverseeker.ssapi.responses.ServerInfoResponse;
|
||||
import de.damcraft.serverseeker.utils.HistoricPlayersUpdater;
|
||||
import meteordevelopment.meteorclient.gui.GuiThemes;
|
||||
import meteordevelopment.meteorclient.settings.*;
|
||||
import meteordevelopment.meteorclient.systems.hud.*;
|
||||
import meteordevelopment.meteorclient.utils.render.color.SettingColor;
|
||||
import net.minecraft.client.network.PlayerListEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
public class HistoricPlayersHud extends HudElement {
|
||||
public List<ServerInfoResponse.Player> players = List.of();
|
||||
public Boolean isCracked = false;
|
||||
|
||||
public final static HudElementInfo<HistoricPlayersHud> INFO = new HudElementInfo<>(Hud.GROUP, "historic-players", "Displays players that were on this server in the past.", HistoricPlayersHud::new);
|
||||
private final SettingGroup sgGeneral = settings.getDefaultGroup();
|
||||
|
||||
public HistoricPlayersHud() {
|
||||
super(INFO);
|
||||
new Thread(HistoricPlayersUpdater::update).start();
|
||||
}
|
||||
|
||||
private final Setting<Boolean> showCrackedText = sgGeneral.add(new BoolSetting.Builder()
|
||||
.name("show-cracked-text")
|
||||
.description("Shows the cracked text.")
|
||||
.defaultValue(true)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Boolean> showCurrentPlayers = sgGeneral.add(new BoolSetting.Builder()
|
||||
.name("show-current-players")
|
||||
.description("Shows players that are currently on the server.")
|
||||
.defaultValue(true)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Boolean> showWhenEmpty = sgGeneral.add(new BoolSetting.Builder()
|
||||
.name("show-when-empty")
|
||||
.description("Shows the hud even when there are no historic players.")
|
||||
.defaultValue(true)
|
||||
.visible(() -> !showCurrentPlayers.get())
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<SettingColor> currentPlayersColor = sgGeneral.add(new ColorSetting.Builder()
|
||||
.name("current-players-color")
|
||||
.description("The color of the current players text.")
|
||||
.defaultValue(new SettingColor(255, 255, 255))
|
||||
.visible(showCurrentPlayers::get)
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<SettingColor> historicPlayersColor = sgGeneral.add(new ColorSetting.Builder()
|
||||
.name("historic-players-name-color")
|
||||
.description("The color of the historic players text.")
|
||||
.defaultValue(new SettingColor(255, 255, 255))
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<SettingColor> historicPlayersLastSeenColor = sgGeneral.add(new ColorSetting.Builder()
|
||||
.name("last-seen-color")
|
||||
.description("The color of the historic players last seen text.")
|
||||
.defaultValue(new SettingColor(175, 175, 175))
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Integer> limit = sgGeneral.add(new IntSetting.Builder()
|
||||
.name("limit")
|
||||
.description("The maximum amount of players to display.")
|
||||
.defaultValue(10)
|
||||
.min(1)
|
||||
.max(1000)
|
||||
.noSlider()
|
||||
.build()
|
||||
);
|
||||
|
||||
private final Setting<Alignment> alignment = sgGeneral.add(new EnumSetting.Builder<Alignment>()
|
||||
.name("alignment")
|
||||
.description("Horizontal alignment.")
|
||||
.defaultValue(Alignment.Auto)
|
||||
.build()
|
||||
);
|
||||
|
||||
@Override
|
||||
public void render(HudRenderer renderer) {
|
||||
super.render(renderer);
|
||||
int line = 0;
|
||||
int more = 0;
|
||||
if (players.isEmpty() && !showWhenEmpty.get()) return;
|
||||
|
||||
String playersText = "Players:";
|
||||
double playerOffset = alignX(renderer.textWidth(playersText), alignment.get());
|
||||
renderer.text(playersText, x + playerOffset, y + line * renderer.textHeight(), GuiThemes.get().textColor(), true);
|
||||
double longestLine = renderer.textWidth(playersText);
|
||||
|
||||
line++;
|
||||
List<String> alreadyDisplayed = new ArrayList<>();
|
||||
if (showCurrentPlayers.get() && mc.player != null) {
|
||||
for (PlayerListEntry player : mc.player.networkHandler.getListedPlayerListEntries()) {
|
||||
if (line >= limit.get()) {
|
||||
more++;
|
||||
continue;
|
||||
}
|
||||
alreadyDisplayed.add(String.valueOf(player.getProfile().getId()));
|
||||
String name = player.getProfile().getName();
|
||||
double offset = alignX(renderer.textWidth(name), alignment.get());
|
||||
renderer.text(name, x + offset, y + line * renderer.textHeight(), currentPlayersColor.get(), true);
|
||||
line++;
|
||||
|
||||
if (renderer.textWidth(name) > longestLine) longestLine = renderer.textWidth(name);
|
||||
}
|
||||
}
|
||||
// Sort players by join time (newest first)
|
||||
List<ServerInfoResponse.Player> players = new ArrayList<>(this.players);
|
||||
players.sort((b, a) -> a.last_seen.compareTo(b.last_seen));
|
||||
for (ServerInfoResponse.Player player : players) {
|
||||
if (alreadyDisplayed.contains(player.uuid)) continue;
|
||||
if (line >= limit.get()) {
|
||||
more++;
|
||||
continue;
|
||||
}
|
||||
// Convert last_seen to a human-readable format
|
||||
String unit = "s";
|
||||
double last_seen = (int) (System.currentTimeMillis() / 1000 - player.last_seen);
|
||||
if (last_seen >= 60) {
|
||||
last_seen /= 60;
|
||||
unit = "min";
|
||||
}
|
||||
if (last_seen >= 60 && unit.equals("min")) {
|
||||
last_seen /= 60;
|
||||
unit = "h";
|
||||
}
|
||||
if (last_seen >= 24 && unit.equals("h")) {
|
||||
last_seen /= 24;
|
||||
unit = last_seen == 1 ? " day" : " days";
|
||||
}
|
||||
if (last_seen >= 30 && unit.equals(" days")) {
|
||||
last_seen /= 30;
|
||||
unit = last_seen == 1 ? " month" : " months";
|
||||
}
|
||||
if (last_seen >= 12 && (unit.equals(" months"))) {
|
||||
last_seen /= 12;
|
||||
unit = last_seen == 1 ? " year" : " years";
|
||||
}
|
||||
// Round to 1 decimal place
|
||||
last_seen = Math.round(last_seen * 10) / 10.0;
|
||||
|
||||
double width = renderer.textWidth(player.name) + renderer.textWidth(" (" + last_seen + unit + ")");
|
||||
double offset = alignX(width, alignment.get());
|
||||
|
||||
renderer.text(player.name, x + offset, y + line * renderer.textHeight(), historicPlayersColor.get(), true);
|
||||
renderer.text(" (" + last_seen + unit + ")", x + offset + renderer.textWidth(player.name), y + line * renderer.textHeight(), historicPlayersLastSeenColor.get(), true);
|
||||
line++;
|
||||
|
||||
if (width > longestLine) longestLine = width;
|
||||
}
|
||||
|
||||
if (line == 1) {
|
||||
String text = "No players found.";
|
||||
double offset = alignX(renderer.textWidth(text), alignment.get());
|
||||
renderer.text(text, x + offset, y + line * renderer.textHeight(), GuiThemes.get().textColor(), true);
|
||||
line++;
|
||||
if (renderer.textWidth(text) > longestLine) longestLine = renderer.textWidth("No players found.");
|
||||
}
|
||||
|
||||
if (more > 0) {
|
||||
String text = "... and " + more + " more";
|
||||
double offset = alignX(renderer.textWidth(text), alignment.get());
|
||||
renderer.text(text, x + offset, y + line * renderer.textHeight(), GuiThemes.get().textColor(), true);
|
||||
line++;
|
||||
if (renderer.textWidth(text) > longestLine) longestLine = renderer.textWidth(text);
|
||||
}
|
||||
|
||||
if (showCrackedText.get() && isCracked) {
|
||||
String text = "Server is cracked";
|
||||
double offset = alignX(renderer.textWidth(text), alignment.get());
|
||||
renderer.text(text, x + offset, y + line * renderer.textHeight(), GuiThemes.get().textColor(), true);
|
||||
line++;
|
||||
if (renderer.textWidth(text) > longestLine) longestLine = renderer.textWidth(text);
|
||||
}
|
||||
|
||||
box.setSize(longestLine, line * renderer.textHeight());
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
package de.damcraft.serverseeker.mixin;
|
||||
|
||||
import net.minecraft.network.packet.c2s.handshake.ConnectionIntent;
|
||||
import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(HandshakeC2SPacket.class)
|
||||
public interface HandshakeC2SAccessor {
|
||||
@Mutable
|
||||
@Accessor
|
||||
void setAddress(String address);
|
||||
|
||||
@Accessor("intendedState")
|
||||
ConnectionIntent getNetworkState();
|
||||
|
||||
@Accessor("address")
|
||||
String getAddress();
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
package de.damcraft.serverseeker.mixin;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import de.damcraft.serverseeker.ServerSeeker;
|
||||
import de.damcraft.serverseeker.modules.BungeeSpoofModule;
|
||||
import meteordevelopment.meteorclient.systems.modules.Modules;
|
||||
import meteordevelopment.meteorclient.utils.network.Http;
|
||||
import net.minecraft.network.packet.c2s.handshake.ConnectionIntent;
|
||||
import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Mutable;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
@Mixin(HandshakeC2SPacket.class)
|
||||
public abstract class HandshakeC2SMixin {
|
||||
|
||||
@Mutable
|
||||
@Shadow
|
||||
@Final
|
||||
private String address;
|
||||
|
||||
@Shadow
|
||||
public abstract ConnectionIntent intendedState();
|
||||
|
||||
@Inject(method = "<init>(ILjava/lang/String;ILnet/minecraft/network/packet/c2s/handshake/ConnectionIntent;)V", at = @At("RETURN"))
|
||||
private void onHandshakeC2SPacket(int i, String string, int j, ConnectionIntent connectionIntent, CallbackInfo ci) {
|
||||
BungeeSpoofModule bungeeSpoofModule = Modules.get().get(BungeeSpoofModule.class);
|
||||
if (!bungeeSpoofModule.isActive()) return;
|
||||
if (this.intendedState() != ConnectionIntent.LOGIN) return;
|
||||
ServerSeeker.LOG.info("Spoofing bungeecord handshake packet");
|
||||
String spoofedUUID = mc.getSession().getUuidOrNull().toString();
|
||||
|
||||
String URL = "https://api.mojang.com/users/profiles/minecraft/" + mc.getSession().getUsername();
|
||||
|
||||
Http.Request request = Http.get(URL);
|
||||
String response = request.sendString();
|
||||
if (response != null) {
|
||||
JsonObject jsonObject = gson.fromJson(response, JsonObject.class);
|
||||
|
||||
if (jsonObject != null && jsonObject.has("id")) {
|
||||
spoofedUUID = jsonObject.get("id").getAsString();
|
||||
}
|
||||
}
|
||||
|
||||
this.address += "\u0000" + bungeeSpoofModule.spoofedAddress.get() + "\u0000" + spoofedUUID;
|
||||
}
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
package de.damcraft.serverseeker.mixin;
|
||||
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(MultiplayerScreen.class)
|
||||
public interface MultiplayerScreenAccessor {
|
||||
@Accessor("serverListWidget")
|
||||
MultiplayerServerListWidget getServerListWidget();
|
||||
}
|
@@ -1,71 +0,0 @@
|
||||
package de.damcraft.serverseeker.mixin;
|
||||
|
||||
import de.damcraft.serverseeker.gui.GetInfoScreen;
|
||||
import de.damcraft.serverseeker.gui.ServerSeekerScreen;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget;
|
||||
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
|
||||
@Mixin(MultiplayerScreen.class)
|
||||
public abstract class MultiplayerScreenMixin extends Screen {
|
||||
@Shadow
|
||||
protected MultiplayerServerListWidget serverListWidget;
|
||||
|
||||
@Unique
|
||||
private ButtonWidget getInfoButton;
|
||||
|
||||
protected MultiplayerScreenMixin() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Inject(method = "init", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerScreen;updateButtonActivationStates()V"))
|
||||
private void onInit(CallbackInfo info) {
|
||||
// Add a button which sets the current screen to the ServerSeekerScreen
|
||||
this.addDrawableChild(
|
||||
new ButtonWidget.Builder(
|
||||
Text.literal("ServerSeeker"),
|
||||
onPress -> {
|
||||
if (this.client == null) return;
|
||||
this.client.setScreen(new ServerSeekerScreen((MultiplayerScreen) (Object) this));
|
||||
}
|
||||
)
|
||||
.position(150, 3)
|
||||
.width(80)
|
||||
.build()
|
||||
);
|
||||
|
||||
// Add a button to get the info of the selected server
|
||||
this.getInfoButton = this.addDrawableChild(
|
||||
new ButtonWidget.Builder(
|
||||
Text.literal("Get players"),
|
||||
onPress -> {
|
||||
if (this.client == null) return;
|
||||
MultiplayerServerListWidget.Entry entry = this.serverListWidget.getSelectedOrNull();
|
||||
if (entry != null) {
|
||||
if (this.client == null) return;
|
||||
this.client.setScreen(new GetInfoScreen((MultiplayerScreen) (Object) this, entry));
|
||||
}
|
||||
}
|
||||
)
|
||||
.position(150 + 80 + 5, 3)
|
||||
.width(80)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Inject(method = "updateButtonActivationStates", at = @At("TAIL"))
|
||||
private void onUpdateButtonActivationStates(CallbackInfo info) {
|
||||
// Enable the button if a server is selected
|
||||
MultiplayerServerListWidget.Entry entry = this.serverListWidget.getSelectedOrNull();
|
||||
this.getInfoButton.active = entry != null && !(entry instanceof MultiplayerServerListWidget.ScanningEntry);
|
||||
}
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
package de.damcraft.serverseeker.mixin;
|
||||
|
||||
import de.damcraft.serverseeker.ServerSeekerSystem;
|
||||
import meteordevelopment.meteorclient.systems.System;
|
||||
import meteordevelopment.meteorclient.systems.Systems;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(value = Systems.class, remap = false)
|
||||
public abstract class SystemsMixin {
|
||||
@Shadow
|
||||
private static System<?> add(System<?> system) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Inject(method = "init", at = @At("HEAD"))
|
||||
private static void onInit(CallbackInfo ci) {
|
||||
add(new ServerSeekerSystem());
|
||||
}
|
||||
}
|
@@ -1,22 +0,0 @@
|
||||
package de.damcraft.serverseeker.mixin;
|
||||
|
||||
import de.damcraft.serverseeker.gui.InstallMeteorScreen;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.TitleScreen;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(TitleScreen.class)
|
||||
public class TitleScreenMixin {
|
||||
@Inject(at = @At("HEAD"), method = "init()V", cancellable = true)
|
||||
private void init(CallbackInfo info) {
|
||||
// Check if meteor-client is installed
|
||||
if (!FabricLoader.getInstance().isModLoaded("meteor-client")) {
|
||||
info.cancel();
|
||||
MinecraftClient.getInstance().setScreen(new InstallMeteorScreen());
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,23 +0,0 @@
|
||||
package de.damcraft.serverseeker.modules;
|
||||
|
||||
import de.damcraft.serverseeker.ServerSeeker;
|
||||
import meteordevelopment.meteorclient.settings.Setting;
|
||||
import meteordevelopment.meteorclient.settings.SettingGroup;
|
||||
import meteordevelopment.meteorclient.settings.StringSetting;
|
||||
import meteordevelopment.meteorclient.systems.modules.Module;
|
||||
|
||||
public class BungeeSpoofModule extends Module {
|
||||
SettingGroup sgGeneral = settings.getDefaultGroup();
|
||||
|
||||
public Setting<String> spoofedAddress = sgGeneral.add(new StringSetting.Builder()
|
||||
.name("spoofed-address")
|
||||
.description("The spoofed IP address that will be sent to the server.")
|
||||
.defaultValue("127.0.0.1")
|
||||
.filter((text, c) -> (text + c).matches("^[0-9a-f\\\\.:]{0,45}$"))
|
||||
.build()
|
||||
);
|
||||
|
||||
public BungeeSpoofModule() {
|
||||
super(ServerSeeker.CATEGORY, "BungeeSpoof", "Allows you to join servers with an exposed bungeecord backend. ONLY ENABLE THIS IF YOU ACTUALLY WANT TO JOIN A BUNGEESPOOFABLE SERVER!");
|
||||
}
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
package de.damcraft.serverseeker.ssapi.requests;
|
||||
|
||||
import de.damcraft.serverseeker.ServerSeekerSystem;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
|
||||
public class ServerInfoRequest {
|
||||
private final String api_key = ServerSeekerSystem.get().apiKey;
|
||||
|
||||
private String ip;
|
||||
private Integer port;
|
||||
|
||||
public void setIpPort(String ip, Integer port) {
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String json() {
|
||||
return gson.toJson(this);
|
||||
}
|
||||
}
|
@@ -1,103 +0,0 @@
|
||||
package de.damcraft.serverseeker.ssapi.requests;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import de.damcraft.serverseeker.ServerSeekerSystem;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
|
||||
public class ServersRequest {
|
||||
private final String api_key = ServerSeekerSystem.get().apiKey;
|
||||
private Integer asn;
|
||||
private String country_code;
|
||||
private Boolean cracked;
|
||||
private String description;
|
||||
private JsonArray max_players;
|
||||
private Integer online_after;
|
||||
private JsonArray online_players;
|
||||
private Integer protocol;
|
||||
private Boolean ignore_modded;
|
||||
private Boolean only_bungeespoofable;
|
||||
|
||||
public enum Software {
|
||||
Any,
|
||||
Bukkit,
|
||||
Spigot,
|
||||
Paper,
|
||||
Vanilla
|
||||
}
|
||||
private Software software;
|
||||
|
||||
public void setAsn(Integer asn) {
|
||||
this.asn = asn;
|
||||
}
|
||||
|
||||
public void setCountryCode(String cc) {
|
||||
this.country_code = cc;
|
||||
}
|
||||
|
||||
public void setCracked(Boolean cracked) {
|
||||
this.cracked = cracked;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public void setMaxPlayers(Integer exact) {
|
||||
this.max_players = new JsonArray();
|
||||
this.max_players.add(exact);
|
||||
this.max_players.add(exact);
|
||||
}
|
||||
|
||||
public void setMaxPlayers(Integer min, Integer max) {
|
||||
this.max_players = new JsonArray();
|
||||
this.max_players.add(min);
|
||||
if (max == -1) {
|
||||
max_players.add("inf");
|
||||
}
|
||||
else {
|
||||
this.max_players.add(max);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnlineAfter(Integer unix_timestamp) {
|
||||
this.online_after = unix_timestamp;
|
||||
}
|
||||
|
||||
public void setOnlinePlayers(Integer exact) {
|
||||
this.online_players = new JsonArray();
|
||||
this.online_players.add(exact);
|
||||
this.online_players.add(exact);
|
||||
}
|
||||
|
||||
public void setOnlinePlayers(Integer min, Integer max) {
|
||||
this.online_players = new JsonArray();
|
||||
this.online_players.add(min);
|
||||
if (max == -1) {
|
||||
this.online_players.add("inf");
|
||||
}
|
||||
else {
|
||||
this.online_players.add(max);
|
||||
}
|
||||
}
|
||||
|
||||
public void setProtocolVersion(Integer version) {
|
||||
this.protocol = version;
|
||||
}
|
||||
|
||||
public void setSoftware(Software software) {
|
||||
this.software = software;
|
||||
}
|
||||
|
||||
public void setIgnoreModded(Boolean ignore) {
|
||||
this.ignore_modded = ignore;
|
||||
}
|
||||
|
||||
public void setOnlyBungeeSpoofable(Boolean only) {
|
||||
this.only_bungeespoofable = only;
|
||||
}
|
||||
|
||||
public String json() {
|
||||
return gson.toJson(this);
|
||||
}
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
package de.damcraft.serverseeker.ssapi.requests;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import de.damcraft.serverseeker.ServerSeekerSystem;
|
||||
|
||||
public class WhereisRequest {
|
||||
private final String api_key = ServerSeekerSystem.get().apiKey;
|
||||
private enum PlayerSearchType {
|
||||
Name,
|
||||
Uuid
|
||||
}
|
||||
private PlayerSearchType playerSearchType;
|
||||
private String playerSearchValue;
|
||||
public WhereisRequest() {
|
||||
|
||||
}
|
||||
public void setName(String name) {
|
||||
playerSearchType = PlayerSearchType.Name;
|
||||
playerSearchValue = name;
|
||||
}
|
||||
|
||||
public void setUuid(String uuid) {
|
||||
playerSearchType = PlayerSearchType.Uuid;
|
||||
playerSearchValue = uuid;
|
||||
}
|
||||
|
||||
public String json() {
|
||||
JsonObject jo = new JsonObject();
|
||||
jo.addProperty(playerSearchType.name().toLowerCase(), playerSearchValue);
|
||||
jo.addProperty("api_key", api_key);
|
||||
return jo.toString();
|
||||
}
|
||||
}
|
@@ -1,26 +0,0 @@
|
||||
package de.damcraft.serverseeker.ssapi.responses;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ServerInfoResponse {
|
||||
public String error;
|
||||
|
||||
public Boolean cracked;
|
||||
public String description;
|
||||
public Integer last_seen;
|
||||
public Integer max_players;
|
||||
public Integer online_players;
|
||||
public Integer protocol;
|
||||
public String version;
|
||||
public static class Player {
|
||||
public String name;
|
||||
public String uuid;
|
||||
public Integer last_seen;
|
||||
}
|
||||
|
||||
public List<Player> players;
|
||||
|
||||
public boolean isError() {
|
||||
return error != null;
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
package de.damcraft.serverseeker.ssapi.responses;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ServersResponse {
|
||||
public String error;
|
||||
|
||||
public static class Server {
|
||||
public String server;
|
||||
public Boolean cracked;
|
||||
public String description;
|
||||
public Integer last_seen;
|
||||
public Integer max_players;
|
||||
public Integer online_players;
|
||||
public Integer protocol;
|
||||
public String version;
|
||||
}
|
||||
|
||||
public List<Server> data;
|
||||
|
||||
public boolean isError() {
|
||||
return error != null;
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
package de.damcraft.serverseeker.ssapi.responses;
|
||||
|
||||
public class UserInfoResponse {
|
||||
public String error;
|
||||
public String discord_id;
|
||||
public String discord_username;
|
||||
public String discord_avatar_url;
|
||||
public Integer requests_per_day_server_info;
|
||||
public Integer requests_per_day_servers;
|
||||
public Integer requests_per_day_whereis;
|
||||
public Integer requests_made_server_info;
|
||||
public Integer requests_made_servers;
|
||||
public Integer requests_made_whereis;
|
||||
|
||||
public boolean isError() {
|
||||
return error != null;
|
||||
}
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
package de.damcraft.serverseeker.ssapi.responses;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class WhereisResponse {
|
||||
public String error;
|
||||
|
||||
public static class Record {
|
||||
public String server;
|
||||
public String uuid;
|
||||
public String name;
|
||||
public Integer last_seen;
|
||||
}
|
||||
|
||||
public List<Record> data;
|
||||
|
||||
public boolean isError() {
|
||||
return error != null;
|
||||
}
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
package de.damcraft.serverseeker.utils;
|
||||
|
||||
import de.damcraft.serverseeker.SmallHttp;
|
||||
import de.damcraft.serverseeker.hud.HistoricPlayersHud;
|
||||
import de.damcraft.serverseeker.ssapi.requests.ServerInfoRequest;
|
||||
import de.damcraft.serverseeker.ssapi.responses.ServerInfoResponse;
|
||||
import meteordevelopment.meteorclient.events.game.GameJoinedEvent;
|
||||
import meteordevelopment.meteorclient.systems.hud.Hud;
|
||||
import meteordevelopment.meteorclient.systems.hud.HudElement;
|
||||
import meteordevelopment.orbit.EventHandler;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static de.damcraft.serverseeker.ServerSeeker.gson;
|
||||
import static meteordevelopment.meteorclient.MeteorClient.mc;
|
||||
|
||||
public class HistoricPlayersUpdater {
|
||||
@EventHandler
|
||||
private static void onGameJoinEvent(GameJoinedEvent ignoredEvent) {
|
||||
// Run in a new thread
|
||||
new Thread(HistoricPlayersUpdater::update).start();
|
||||
}
|
||||
|
||||
public static void update() {
|
||||
// If the Hud contains the HistoricPlayersHud, update the players
|
||||
List<HistoricPlayersHud> huds = new ArrayList<>();
|
||||
for (HudElement hudElement : Hud.get()) {
|
||||
if (hudElement instanceof HistoricPlayersHud && hudElement.isActive()) {
|
||||
huds.add((HistoricPlayersHud) hudElement);
|
||||
}
|
||||
}
|
||||
if (huds.isEmpty()) return;
|
||||
|
||||
ClientPlayNetworkHandler networkHandler = mc.getNetworkHandler();
|
||||
if (networkHandler == null) return;
|
||||
|
||||
String address = networkHandler.getConnection().getAddress().toString();
|
||||
// Split it at "/" and take the second part
|
||||
String[] addressParts = address.split("/");
|
||||
if (addressParts.length < 2) return;
|
||||
|
||||
String ip = addressParts[1].split(":")[0];
|
||||
Integer port = Integer.valueOf(addressParts[1].split(":")[1]);
|
||||
|
||||
ServerInfoRequest request = new ServerInfoRequest();
|
||||
request.setIpPort(ip, port);
|
||||
|
||||
String jsonResp = SmallHttp.post("https://api.serverseeker.net/server_info", request.json());
|
||||
|
||||
ServerInfoResponse resp = gson.fromJson(jsonResp, ServerInfoResponse.class);
|
||||
|
||||
for (HistoricPlayersHud hud : huds) {
|
||||
hud.players = Objects.requireNonNullElseGet(resp.players, List::of);
|
||||
hud.isCracked = resp.cracked != null && resp.cracked;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,94 +0,0 @@
|
||||
package de.damcraft.serverseeker.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class MCVersionUtil {
|
||||
private static final HashMap<String, Integer> versions = new HashMap<>() {
|
||||
{
|
||||
put("1.20.6", 766);
|
||||
put("1.20.5", 766);
|
||||
put("1.20.4", 765);
|
||||
put("1.20.3", 765);
|
||||
put("1.20.2", 764);
|
||||
put("1.20.1", 763);
|
||||
put("1.20", 763);
|
||||
|
||||
put("1.19.4", 762);
|
||||
put("1.19.3", 761);
|
||||
put("1.19.2", 760);
|
||||
put("1.19.1", 760);
|
||||
put("1.19", 759);
|
||||
|
||||
put("1.18.2", 758);
|
||||
put("1.18.1", 757);
|
||||
put("1.18", 757);
|
||||
|
||||
put("1.17.1", 756);
|
||||
put("1.17", 755);
|
||||
|
||||
put("1.16.5", 754);
|
||||
put("1.16.4", 754);
|
||||
put("1.16.3", 753);
|
||||
put("1.16.2", 751);
|
||||
put("1.16.1", 736);
|
||||
put("1.16", 735);
|
||||
|
||||
put("1.15.2", 578);
|
||||
put("1.15.1", 575);
|
||||
put("1.15", 753);
|
||||
|
||||
put("1.14.4", 498);
|
||||
put("1.14.3", 490);
|
||||
put("1.14.2", 485);
|
||||
put("1.14.1", 480);
|
||||
put("1.14", 477);
|
||||
|
||||
put("1.13.2", 404);
|
||||
put("1.13.1", 401);
|
||||
put("1.13", 393);
|
||||
|
||||
put("1.12.2", 340);
|
||||
put("1.12.1", 338);
|
||||
put("1.12", 335);
|
||||
|
||||
put("1.11.2", 316);
|
||||
put("1.11.1", 316);
|
||||
put("1.11", 316);
|
||||
|
||||
put("1.10.2", 210);
|
||||
put("1.10.1", 210);
|
||||
put("1.10", 210);
|
||||
|
||||
put("1.9.4", 110);
|
||||
put("1.9.3", 110);
|
||||
put("1.9.2", 109);
|
||||
put("1.9.1", 108);
|
||||
|
||||
put("1.9", 107);
|
||||
put("1.8.9", 47);
|
||||
put("1.8.8", 47);
|
||||
put("1.8.7", 47);
|
||||
put("1.8.6", 47);
|
||||
put("1.8.5", 47);
|
||||
put("1.8.4", 47);
|
||||
put("1.8.3", 47);
|
||||
put("1.8.2", 47);
|
||||
put("1.8.1", 47);
|
||||
put("1.8", 47);
|
||||
|
||||
put("1.7.10", 5);
|
||||
put("1.7.9", 5);
|
||||
put("1.7.8", 5);
|
||||
put("1.7.7", 5);
|
||||
put("1.7.6", 5);
|
||||
put("1.7.5", 4);
|
||||
put("1.7.4", 4);
|
||||
put("1.7.2", 3);
|
||||
put("1.7.1", 3);
|
||||
}
|
||||
};
|
||||
|
||||
public static Integer versionToProtocol(String versionString) {
|
||||
return versions.get(versionString);
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
package de.damcraft.serverseeker.utils;
|
||||
|
||||
import de.damcraft.serverseeker.mixin.MultiplayerScreenAccessor;
|
||||
import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen;
|
||||
import net.minecraft.client.network.ServerInfo;
|
||||
|
||||
public class MultiplayerScreenUtil {
|
||||
|
||||
public static void addInfoToServerList(MultiplayerScreen mps, ServerInfo info) {
|
||||
MultiplayerScreenAccessor mpsAccessor = (MultiplayerScreenAccessor) mps;
|
||||
mps.getServerList().add(info, false);
|
||||
mps.getServerList().saveFile();
|
||||
mpsAccessor.getServerListWidget().setServers(mps.getServerList());
|
||||
}
|
||||
public static void addInfoToServerList(MultiplayerScreen mps, ServerInfo info, boolean reload) {
|
||||
MultiplayerScreenAccessor mpsAccessor = (MultiplayerScreenAccessor) mps;
|
||||
mps.getServerList().add(info, false);
|
||||
if (reload) mpsAccessor.getServerListWidget().setServers(mps.getServerList());
|
||||
}
|
||||
|
||||
public static void addNameIpToServerList(MultiplayerScreen mps, String name, String ip) {
|
||||
MultiplayerScreenAccessor mpsAccessor = (MultiplayerScreenAccessor) mps;
|
||||
ServerInfo info = new ServerInfo(name, ip, ServerInfo.ServerType.OTHER);
|
||||
mps.getServerList().add(info, false);
|
||||
mpsAccessor.getServerListWidget().setServers(mps.getServerList());
|
||||
mps.getServerList().saveFile();
|
||||
}
|
||||
public static void addNameIpToServerList(MultiplayerScreen mps, String name, String ip, boolean reload) {
|
||||
MultiplayerScreenAccessor mpsAccessor = (MultiplayerScreenAccessor) mps;
|
||||
ServerInfo info = new ServerInfo(name, ip, ServerInfo.ServerType.OTHER);
|
||||
mps.getServerList().add(info, false);
|
||||
if (reload) mpsAccessor.getServerListWidget().setServers(mps.getServerList());
|
||||
}
|
||||
|
||||
public static void reloadServerList(MultiplayerScreen mps) {
|
||||
MultiplayerScreenAccessor mpsAccessor = (MultiplayerScreenAccessor) mps;
|
||||
mpsAccessor.getServerListWidget().setServers(mps.getServerList());
|
||||
}
|
||||
|
||||
public static void saveList(MultiplayerScreen mps) {
|
||||
mps.getServerList().saveFile();
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 136 B |
Before Width: | Height: | Size: 982 B |
Before Width: | Height: | Size: 941 B |
Before Width: | Height: | Size: 714 B |
Before Width: | Height: | Size: 581 B |
Before Width: | Height: | Size: 126 B |
Before Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 502 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 157 B |
Before Width: | Height: | Size: 536 B |
Before Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 240 B |
Before Width: | Height: | Size: 270 B |
Before Width: | Height: | Size: 266 B |
Before Width: | Height: | Size: 331 B |
Before Width: | Height: | Size: 310 B |
Before Width: | Height: | Size: 146 B |
Before Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 169 B |
Before Width: | Height: | Size: 523 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 182 B |
Before Width: | Height: | Size: 146 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 989 B |
Before Width: | Height: | Size: 176 B |
Before Width: | Height: | Size: 954 B |
Before Width: | Height: | Size: 365 B |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 171 B |
Before Width: | Height: | Size: 548 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 338 B |
Before Width: | Height: | Size: 525 B |
Before Width: | Height: | Size: 779 B |
Before Width: | Height: | Size: 407 B |
Before Width: | Height: | Size: 331 B |
Before Width: | Height: | Size: 114 B |
Before Width: | Height: | Size: 146 B |
Before Width: | Height: | Size: 726 B |
Before Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 329 B |
Before Width: | Height: | Size: 319 B |
Before Width: | Height: | Size: 176 B |