Compare commits

...

124 commits

Author SHA1 Message Date
YHDiamond
fb283fcce8
Add advancements GUI (#1579)
Using /geyser advancements, Bedrock clients can get a visual on their progress.

Co-authored-by: yehudahrrs <47502993+yehudahrrs@users.noreply.github.com>
Co-authored-by: Olivia <chew@chew.pw>
Co-authored-by: rtm516 <rtm516@users.noreply.github.com>
Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
Co-authored-by: rtm516 <ryantmilner@hotmail.co.uk>
Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com>
2021-01-11 21:23:09 -05:00
rtm516
1c0cc4622a
Microsoft account authentication (#1808)
Microsoft accounts can now use Geyser, while maintaining full backwards compatibility with Mojang accounts.

Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com>
2021-01-11 15:52:02 -05:00
Camotoy
6aa74a2322
Allow server pong to appear if MOTDs are too long (#1445)
* Prevent server pong from appearing if MOTDs are too long

If the server MOTDs are 340 characters or longer, they will not appear. If this is the case, we trim each.

* Implement a more exact fix
2021-01-11 15:37:37 -05:00
Camotoy
2cc8726c12
Shade in the entire net.kyori package (#1826) 2021-01-11 14:11:21 -05:00
Camotoy
999fa7298a
Clarify proxy protocol config message (#1824) 2021-01-10 20:01:04 -05:00
Camotoy
d6461e71fb
Add message if Geyser thinks the English locale is missing (#1825) 2021-01-10 20:00:48 -05:00
David Choo
9232c5565f
Add Ender Dragon effects and sounds (#1781)
* Add Ender Dragon effects and sounds

* Add proper death effect and clean up

* Add Ender Dragon respawn sound

* Possibly fix dragon breath direction?

* Update mappings

* Fix death animation triggering at low health

* Trigger death event when health is 0 and add explosions back

* Add comment
2021-01-09 20:43:03 -05:00
Camotoy
ade4c14911
Block breaking refactors (#1336)
Client-side block animations and reach checks are now added.

This commit also includes cleanup in BlockChangeTranslator as well as proper Netherite tool support for calculating block breaking.

Co-authored-by: rtm516 <rtm516@users.noreply.github.com>
2021-01-07 22:43:36 -05:00
Camotoy
fe23c79053
Implement book editing (#1117)
* Implement book editing

Updates the PR created by @ForceUpdate1 for 1.16 support. Seems to work fine now that hand support is in MCProtocolLib.

Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com>

* Remove debug line

* Simplify code

Currently still borked for creative mode.

* Fix books on creative

* Bug fixes

* Fix NPE?

* Blind fixes

* Send Book update before any player actions

* Remove debug prints

* Fix out of bounds for page replace and add

* Fix editing desync and remove empty pages from the end

* Send edit packet after signing

* Refactor

* Clean up and fix creative

* Apply suggestions from code review

Co-authored-by: rtm516 <rtm516@users.noreply.github.com>

Co-authored-by: ForceUpdate1 <mneuhaus44@gmail.com>
Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com>
Co-authored-by: David Choo <davchoo3@gmail.com>
Co-authored-by: rtm516 <rtm516@users.noreply.github.com>
2021-01-07 19:40:34 -05:00
Camotoy
7cefb5713e
Clarify that enabling Xbox achievements blocks all commands (#1810) 2021-01-07 16:50:57 -05:00
SupremeMortal
dc46905e50
Use Artifactory Jenkins plugin for deployment (#1818)
* Use artifactory jenkins plugin

* Bump version to 1.2.0-SNAPSHOT
2021-01-07 19:51:40 +00:00
rtm516
bbbb7034f6
Trigger builds of Geyser-Fabric and GeyserAndroid after a build success (#1815)
* Trigger builds of Geyser-Fabric and GeyserAndroid after a build success

* Enable GeyserAndroid and fix paths

* Only build for master

* Disable propagation of build results

* Don't wait for sequential builds
2021-01-07 12:21:35 +00:00
Camotoy
92c86cf15b
Null check tick thread (#1812) 2021-01-05 23:28:31 -05:00
Camotoy
0641800be7
Add Tickable interface (#1790)
* Add Tickable interface

By having a tickable interface, we're only dedicating one thread to ticking entities and running tasks as opposed to several. This will also help with implementing world border support.

* removeEntity already clears tickableEntities for us

* Only tick the entity if it's not being ticked
2021-01-05 18:41:20 -05:00
AJ Ferguson
b6389317f0
Fix minor bug in auth form (#1806) 2021-01-05 13:45:01 -05:00
Nickg two
29e47cf636
[ci skip] changed a 2020 to 2021 (#1801)
lol imagine being in 2020
2021-01-04 21:24:07 -05:00
Camotoy
69dc4a9644
[ci-skip] Improve README for better information (#1702) 2021-01-04 15:54:52 -05:00
D3ATHBRINGER13
446f16bc33
Update LICENSE to 2021 (#1799) 2021-01-04 14:14:55 -05:00
Camotoy
50b80a64d3
Dimension switching cleanup (#1694)
* Dimension switching cleanup

Cleans up dimension switching logic that should no longer be needed. Also fixes above Nether Bedrock building dimension switching.

* Clear thunder on dimension switch too

* Clarify fake dimension switch function name

* Javadoc that
2021-01-03 19:06:20 -05:00
Kooldude183
3f7d669676
Update README.md (#1774)
* Update README.md

Add v1.16.201 in list of supported Bedrock versions

* Update README.md

Change to `v1.16.100 - v1.16.201`
2021-01-03 12:54:07 -05:00
Camotoy
1c7567d79d
Various resource pack fixes (#1769)
- Fixes an instance where an invalid pack_manifest file could be present
- Fixes instances where JSON files were not read as UTF-8
2021-01-03 12:53:26 -05:00
YHDiamond
1a08e1104d
Fix stopsound bug (#1771)
* Fix stopsound not working bug

* removed extra imports

* Update JavaPlayerStopSoundTranslator.java

* Update JavaPlayerStopSoundTranslator.java

* Update JavaPlayerStopSoundTranslator.java

* Fix packet names and fix specific sounds not stopping

Co-authored-by: YHDiamond <47502993+yehudahrrs@users.noreply.github.com>
Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com>
2021-01-02 18:51:41 -05:00
Camotoy
396d1b6b61
Fix items on campfires (#1779) 2021-01-01 18:33:21 -05:00
Camotoy
eccb48844e
Allow enderman to make provoked sound when angry (#1763) 2021-01-01 16:55:04 -05:00
Camotoy
186d94917a
Update copyright to 2021 (#1772)
* Update copyright to 2021

Free commit!

* These don't need a copyright

* Don't downgrade the mappings
2021-01-01 10:10:36 -05:00
Camotoy
77153e6d4a
Work around there being a void floor in Bedrock (#1405)
* Work around there being a void floor in Bedrock

If the player's Y coordinate is -38 or below, we teleport the player below the void floor and they can safely die. :)

* Don't teleport if below Y -40

* sigh

* Have floorY be its own variable

* Add more comment

* More comments

* Finish my thought
2020-12-31 20:05:00 -05:00
Camotoy
a17f2203a8
Fix oddities in chunk sections with older Spigot versions (#1758) 2020-12-29 21:49:36 -05:00
AJ Ferguson
e3b94bc859
Thrown potion entity color (#1756)
* Fix thrown potion color

* Prevent area effect cloud from appearing to catch on fire

* Don't set ENCHANTED flag on all potions
2020-12-29 18:58:02 -05:00
David Choo
fe63a7f7ab
Fix pick block (#1753)
* Use pick_item mappings

* Update mappings

* Update mappings and fix wording
2020-12-29 18:09:42 -05:00
Camotoy
d1c571d710
Fix anvil renaming (#1744)
Turns out it *was* our fault. Oops.
2020-12-26 19:51:11 -05:00
Tim203
77de991bcf
Change Jenkins url and name to Open Collaboration (#1732) 2020-12-26 21:40:49 +01:00
Camotoy
eb5e4d79bb
Add visual damage support with thorns (#1728) 2020-12-26 15:39:46 -05:00
Camotoy
9fc6228fc0
GeyserSession: remove 32 render distance cap (#1546)
Having an incongruency between the server render distance and the client render distance appears to cause issues, and I have not been able to encounter such a crash.
2020-12-24 13:40:57 -05:00
Mark
eca626aad6
Add missing netty-codec-haproxy dependency (#1731) 2020-12-24 00:31:23 -05:00
Mark
c67d91943c
HAProxy PROXY protocol support for downstream connections (#1688)
* Implement downstream PROXY protocol support

* Clarify the configuration version updating procedure

* Bump netty-resolver-dns to 4.1.56.Final

* Update Netty to .56

* Don't increase jar size by 2MB

Co-authored-by: Camotoy <20743703+Camotoy@users.noreply.github.com>
2020-12-23 20:47:29 -05:00
Camotoy
dbfdae63f1
Add precautions to prevent stack traces on incomplete/unknown place sounds (#1717) 2020-12-20 20:42:14 -05:00
Camotoy
f5c0c549ef
Improve doDaylightCycle translation (#1711)
Previously, we wouldn't send the time if the server was sending the same time with doDaylightCycle on. However, this isn't vanilla behavior (for Bedrock nor Java) and can occasionally cause irregularities. The time is now always sent to Bedrock clients, and a daylightCycle field is added to GeyserSession to keep track of the doDaylightCycle gamerule we need to send to Bedrock. Removing the map we used to store the time may also improve memory usage since this was never cleaned up.
2020-12-20 20:41:28 -05:00
Camotoy
b490dcfcbb
Improve doDaylightCycle translation (#1711)
Previously, we wouldn't send the time if the server was sending the same time with doDaylightCycle on. However, this isn't vanilla behavior (for Bedrock nor Java) and can occasionally cause irregularities. The time is now always sent to Bedrock clients, and a daylightCycle field is added to GeyserSession to keep track of the doDaylightCycle gamerule we need to send to Bedrock. Removing the map we used to store the time may also improve memory usage since this was never cleaned up.
2020-12-20 20:41:07 -05:00
Camotoy
d69896b381
Fix NPE when no item can be found from a block (#1718)
This commit also removes an old map previously used for block entity translators
2020-12-20 20:40:21 -05:00
Camotoy
c92150013f
Allow /help to work even if command suggestions are disabled (#1703)
* Allow /help to work even if command suggestions are disabled

This sends a minimal available commands packet to permit /help sending to the server.

* Fix whitespace

* Just send an empty packet

* Change variable name
2020-12-17 14:10:58 -05:00
rtm516
ce9cd92b2e
Update GeyserConnector.java to fix JavaDoc (#1701) 2020-12-17 17:25:38 +00:00
qlow
9f6182f8df
Added a simple way to get a player by their xuid (#1642)
* Added IGeyserPingPassthrough#getPingInformation(InetSocketAddress) to make logging of the pinging IPs possible

* Added GeyserConnector#getPlayerByXboxUuid

* Added GeyserConnector#getPlayerByUuid and added some javadocs

* Update connector/src/main/java/org/geysermc/connector/GeyserConnector.java

Co-authored-by: rtm516 <rtm516@users.noreply.github.com>

* Update connector/src/main/java/org/geysermc/connector/GeyserConnector.java

Co-authored-by: rtm516 <rtm516@users.noreply.github.com>

* Update GeyserConnector.java

* Update SkinManager.java

* Update SkinProvider.java

* Renamed getPlayerByXboxUuid to getPlayerByXuid

Co-authored-by: qlow <info@qlow.eu>
Co-authored-by: rtm516 <rtm516@users.noreply.github.com>
2020-12-17 11:58:49 -05:00
Kooldude183
02d99380d3
Add info about clickable links in "What can't be fixed" (#1687)
* Add info about clickable links in "What can't be fixed"

* Add "Glowing effect"
2020-12-17 11:58:25 -05:00
Camotoy
82179797ab
Add proper ominous banner translation (#1692)
The ominous banner is a separate banner type in Bedrock. If we detect the ominous banner pattern, then we set the ominous banner type in NBT. This process is also checked vice-versa, allowing the ominous banner to be pulled from the Bedrock creative menu.
2020-12-16 12:50:16 -05:00
Camotoy
988fd66a85
Fix boat movement on land (#1668)
* Fix boat movement on land

1.16.100 appears to now take advantage of two newer entity metadata properties, IS_BUOYANT and BUOYANCY_DATA. Without the former, moving on land will not work properly. With the former and without the latter, moving in water no longer works.

* Use offset kind of
2020-12-15 13:09:40 -05:00
Camotoy
aed1eef6e1
Update Adventure and fix some legacy hover events (#1681) 2020-12-15 11:24:02 -05:00
Camotoy
55cf7d1c54
Fix more scoreboard crashing and oddities (#1665)
* Various fixes

* Apply updateType fix as well

* Slight optimization
2020-12-14 18:22:31 -05:00
EasyClifton
feaaf9edec
Add What can't be fixed and info about player heads (#1680)
* Add What can't be fixed and info about player heads

* Update README.md
2020-12-14 18:22:18 -05:00
Camotoy
8b5ef7478c
Fix PS4 behavior with NetworkStackLatencyTranslator (#1678) 2020-12-14 15:47:17 -05:00
Camotoy
799f6341c8
Fix Netty dependency usage on Velocity (#1672) 2020-12-13 23:03:11 -05:00
RednedEpic
41cb593dc4 Update langauges submodule 2020-12-12 01:48:12 -06:00
RednedEpic
655e218115 Add settings command for settings menu as it broke in the settings screen in 1.16.100 2020-12-12 01:45:54 -06:00
RednedEpic
31209be79e Ensure spawn radius is always 0 on the client's end
Fixes #1496 to the best of my knowledge. Any issue regarding the spawnpoint being off in terms of radius is up to the server at this point - would not be an us situation here.
2020-12-12 01:23:30 -06:00
jackson-57
50662bc65c
Update todo list in README.md (#1656) 2020-12-12 00:46:29 -06:00
RednedEpic
70031c65e7 Handle keepalives better (Closes #965)
Bedrock cuts off the last 3 digits consistently every time, meaning that the keepalive returned from bedrock is never fully accurate. However, if we multiply the value by 1000, then divide by 1000 when sending back to java, the proper value is returned.
2020-12-12 00:45:41 -06:00
RednedEpic
a60ab4e80e Fix colored particles (Closes #1627) 2020-12-11 17:15:49 -06:00
RednedEpic
047bf5f0f4 Fix armor stand rotation (Closes #1634) 2020-12-11 17:06:33 -06:00
Camotoy
f19922ecf0
EnderCrystalEntity: don't appear to be on fire if fire is below (#1651) 2020-12-11 12:55:37 -05:00
Camotoy
bb21d05459
Update README to show all supported versions (#1647) 2020-12-11 12:55:19 -05:00
Kooldude183
39a11da7e5
Fix resource pack description in config (#1649) 2020-12-10 22:13:54 +00:00
Camotoy
87c52ad524
Add a config option for toggling showing coordinates (#1645) 2020-12-10 11:13:36 -05:00
rtm516
91cdda95db
Change version in query to use a more informative string (#1635)
* Change version in query to use a more informative string

* Fix removal of string

* Cleaner implementation of version

* Fix build

* Make more explicit what we're replacing

Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com>
2020-12-09 15:14:12 -05:00
rosiecube
2a44874458
Fix Bedrock ItemEntity Y position bug (#1636)
Setting motion while on the ground causes visual issues. Additionally, there is an offset difference in the movement of an item entity.
2020-12-09 15:09:14 -05:00
Camotoy
8e274daa75
Change default protocol version to 422 (#1640)
* Change default protocol version to 422

* Update Protocol

* Actually update to Protocol 2.6.1-SNAPSHOT

* Keep languages commit the same
2020-12-09 11:30:59 -05:00
D3ATHBRINGER13
3bcdf4cca1
Add map and banner cloning and map extending (#1623)
* Add all the crafting multi uuids

* Remove BANNER_ADD_PATTERN

* Remove TODO
2020-12-07 14:27:42 -05:00
qlow
a173005767
Added IGeyserPingPassthrough#getPingInformation(InetSocketAddress) to make logging of the pinging IPs possible (#1633)
Co-authored-by: qlow <info@qlow.eu>
2020-12-07 14:04:50 -05:00
Camotoy
798ae34cd1
WolfEntity: fix entire wolf being set to a color in rare instances (#1630) 2020-12-06 14:46:31 -05:00
Camotoy
2f294c9466
Fix player heads with a custom name (#1625) 2020-12-04 17:48:33 -05:00
OnlyBMan
2c0f3ec84d
Custom skull block support (#683)
Custom skulls are now implemented within the world when placed as a block. This is achieved by placing a fake player entity in the same spot.

Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
Co-authored-by: bundabrg <brendan@grieve.com.au>
Co-authored-by: bundabrg <bundabrg@grieve.com.au>
Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com>
2020-12-04 16:55:24 -05:00
rtm516
2067143b57
Fix supported version display name (#1593)
* Fix supported version display name

* Update connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java
2020-12-03 19:21:32 -05:00
D3ATHBRINGER13
b92d8d53e9
Bump languages submodule (#1619) 2020-12-03 18:20:39 +00:00
Camotoy
f6a26410da
Supply a unique network ID for each recipe (#1615)
This fixes crashes in the Minecraft betas.
2020-12-02 15:39:24 -05:00
Bastian Oppermann
24fd7dafc5
Do not send server custom chart for Metrics (#1610)
The server chart is automatically populated by the bStats backend.
2020-12-01 11:40:07 +00:00
Camotoy
ffd0c211fc
Fix villagers accepting books (#1605)
* Hopefully fix villagers accepting books

Fixes a couple of inconsistencies getting books from the creative menu.

* Fix fake news
2020-11-30 10:55:35 -05:00
rtm516
eb687e6638
Add check to fix NONE team color causing an NPE (#1602) 2020-11-28 15:10:19 +00:00
Camotoy
0215c383b0
GUI: Don't exit if there is a config error (#1600)
Leave the window open so the user understands there is an error.

This also changes the exit code to 1 when exiting without a GUI since we have an error.
2020-11-27 18:55:33 -05:00
rtm516
da2dc69441
Update MCProtocolLib to Adventure migration (#1572)
* Use raw message data instead of converting the message

* Update MCProtocolLib to Adventure

* Ignore MCProtocolLib Adventure depend

* Remove unused dependency

* Fix isMessage handling `null` wrong.

* Update to adventure 4.2.0

* Clean-up isMessage

* Fix tests

* Clean-up of catch statements
2020-11-27 18:28:08 -05:00
Camotoy
11d9d30050
Fix mounts being unmountable with cache chunks (#1576)
Teleports need to be confirmed before riding
2020-11-27 17:56:32 -05:00
Carbuino
894275b8c4
Update UpstreamPacketHandler.java (#1570)
Changed the logging in message to display in the Action Bar instead of spamming the chat.
2020-11-24 11:14:02 -05:00
RednedEpic
896638ed84 Add support for latest beta (1.16.200.56) 2020-11-24 00:47:57 -06:00
rtm516
e412ba0993
Clear the Reflections scanners to stop it trying to scan (#1582) 2020-11-23 01:08:59 +00:00
rtm516
881e7a051c
Another android fix (#1575)
* Fix en_us hash reading on Android (again)

* Fix hash generation methods for Android
2020-11-22 10:40:53 +00:00
rtm516
9ed3197191
Fix en_us downloading and hashing on Android (#1574) 2020-11-22 01:59:57 +00:00
rtm516
0268ef7d2b
Clean-up translation string implementation (#1567) 2020-11-21 00:44:33 +00:00
Camotoy
67d5993ae1
LivingEntity: add visual support for riptide spin attack (#1551) 2020-11-20 18:06:27 -05:00
a70d3e2150
Fix inconsistencies with movement and position (#699)
Movement is now significant better, especially on slabs, stairs, and other half-blocks.

Co-authored-by: RednedEpic <redned235@gmail.com>
Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
Co-authored-by: Tim203 <mctim203@gmail.com>
Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com>
2020-11-20 14:56:39 -05:00
rtm516
4297215420
More chat fixes (#1557)
* Fix positional translation arguments not being handled

* Fix locale fallback

* Fix command completion

* Remove the expensive call to `containsKey`

* Unify adventure versions

* Fix some more formatting issues due to parity

* Fix and update tests

* Update adventure

* Add Javadoc for getCommandNames

* Formatting

Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com>
2020-11-18 23:18:36 +00:00
Camotoy
199778faea
Fix regressions from 1.16.100 (#1558)
* Fix regressions from 1.16.100

- Update mappings to fix recipe regressions and item differences
- Villager trading NBT now prefers the String identifier and not the integer ID

* Fix lodestone compass breaking
2020-11-18 01:10:49 -05:00
Camotoy
99558b61a6
Print reason for disconnect when outdated (#1556) 2020-11-17 13:28:08 -05:00
Camotoy
003a1bef03
Revert artifactory changes preventing compilation (#1555) 2020-11-17 12:54:09 -05:00
Camotoy
123b074cc7
Update to Bedrock 1.16.100 (#1552)
* Initial work on 1.16.100 - currently crashes the client

* Update runtime item states

* Use new Bedrock runtime IDs

Bedrock now hardcodes block runtime IDs in alphabetical order of the identifiers. This commit updates Geyser to accomodate.

- Remove runtime_block_states.dat and replace it with blockpalette.nbt
- Calculate the block runtime ID based on the order of the block palette
- Separate BlockTranslator.AIR into Bedrock and Java values
- Update the second layer of chunks to use air when not waterlogged
- Don't send item palette for now, as that's what crashes the game (will look into for v415)
- Other misc. changes

* Improve second layer chunk translation

* v415 support

- Add a message warning people they are on a beta version of Geyser

* Update to protocol v417

There are still some mappings changes that need to be gone through.

* Update runtime item states and clean up item frames

* Future-proof enchanment table

* Update for v418

* Update to v419

* Apply proper air ID to waterlogged chunk layer

* Fix missing import

* Remove beta warning

* Update mappings

* Manually patch runtime_item_states and send the ITEMS registry

* Update README

* Disable grindstone and smithing inventories (since they're broken)

* Use artifactory jenkins plugin (#1548)

* Use artifactory jenkins plugin

* Bump version to 1.2.0-SNAPSHOT

Co-authored-by: SupremeMortal <6178101+SupremeMortal@users.noreply.github.com>
2020-11-17 11:03:12 -06:00
rtm516
512f8cd6c2
Rewrite message handling in MessageUtils to use Adventure (#1498)
* Rewrite message handling in MessageUtils to use Adventure

* Move to static Adventure commit to fix a bug

* Initial test implementation

* Add RGB downgrade test

* Move MessageUtils and rename

* Clean-up and fix tests

* Fixed sign and book content handling

* Fix blank signs causing NPEs

* Fix reset before message being stripped

* Add comment about the reset character

* Fix legacy style server motds

* Fix more messages being handled wrong

* Fix title packets being handled wrong

* Fix trailing formatting characters on the end of sign lines

* Add auto updating of Java locale files

* Add en_us locale updating and hash caching

* Changes to hash determining

Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
2020-11-16 23:57:57 +00:00
Camotoy
47f25f1205
BannerTranslator: fix NPE when no block entity data (#1543) 2020-11-15 18:48:11 -05:00
RednedEpic
981ac3bf11 Move PlatformType to common module 2020-11-14 17:49:56 -06:00
Camotoy
445444204f
Fix GlobalPalette translation (#1528)
* Fix GlobalPalette translation

Global palettes don't have their own internal palette, which cannot be iterated through to create a Bedrock palette. Therefore we simply iterate over the whole palette one time. This commit also fixes a regression with flowers/pistons being on multiple chunk sections.

* Don't declare bedrockPalette until after global palette check
2020-11-14 12:05:33 -06:00
Niklas
bf05f64fac
Update LabyMod cape url (#1540) 2020-11-14 11:52:10 -06:00
Camotoy
80cf407fae
Update MCProtocolLib to fix more custom recipe stuff (#1534) 2020-11-13 23:00:09 -05:00
Camotoy
e748240a02
Add more interactive tags (mobile buttons) (#1443)
* Add more interactive tags (mobile buttons)

This expands our support for showing the interactive tags on touchscreen and console setups. This is not complete - specifically, the food compatibility of creatures needs to be expanded upon (I will work on this later and does not stop this PR from being mergable). This also includes:

- Creepers who are ignited with flint and steel now show up properly
- Zombie villagers now shake properly when converting and show their region outfits

* Add more food choices and add more panda entity metadata

* Re-add eating flag

* Remove debug line

* Refactor dimension usage, finish interactive tag usage, bees

* Print statements... ._.

* Don't make eating item packet data a non-constant

* Move BAMBOO to ItemRegistry

* Add missing break

* Make changes

* Minor final changes
2020-11-11 19:28:45 -05:00
rtm516
3676dd185f
Fix even more entity metadata flags (#1483)
* Fix even more entity metadata flags

* Add comment explaining magic value

* Fix horse flags and add more information

* Add more information about the Horse eating particles
2020-11-11 18:13:13 +00:00
David Choo
4237503d6d
Fix laying crash (#1510)
* Fix crash with GSit lay and use Java bed position data

* Fix GSit's lay position

* Move Bed Position metadata to the right class

* Actually fix lay for PosePlugin

* Revert "Actually fix lay for PosePlugin"

This reverts commit 3f21261162.

Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
2020-11-10 12:05:16 -05:00
Camotoy
109922f796
Update MCProtocolLib to fix datapacks that send empty result recipes (#1522)
Example: https://www.planetminecraft.com/data-pack/true-survival-a-hardcore-minecraft-experience/
2020-11-09 14:26:29 -05:00
Tim203
e00715ceab
Fixed some issues related to Scoreboards (#1446)
* Fixes some issues related to Scoreboard Teams

* The cached Score info should update no matter what kind of update the Team got.
* Team entities specified at the create Team packet should also be checked if they exist as Score in the registered Objectives

* Rewrote some Scoreboard code and fixed various issues

* Minor formatting changes
2020-11-09 10:34:27 +01:00
rtm516
2d95302b10
Add support for passing config options as arguments (#1506) 2020-11-07 13:17:17 -06:00
rtm516
c7654ff98c
Disable the sponsor button (#1509) 2020-11-07 18:47:45 +00:00
rtm516
a6cc28ee80
Add config option for enabling achievements (#1504)
* Add config option for enabling achievements

* Disabled achievements by default and added warning about commands being disabled

* Update config.yml

* Rename achievements-enabled to xbox-achievements-enabled for clarity

Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com>
2020-11-07 00:52:09 +00:00
Camotoy
0e15aa7441
Fireball and ghast improvements (#1469)
* Fireball and ghast improvements

- Ghasts now visually show if they're charging a fireball
- Fireballs are now vastly better and will update better

* Add gravity and drag to projectiles

* Add check for session close and improve fireball

* Remove motion stuff from fireball

* Make fireball hittable

* Add wither skull entity

* Small changes

* Add note about laggy fireballs

Co-authored-by: David Choo <davchoo3@gmail.com>
2020-11-05 18:42:33 -05:00
Tim203
c64d57439f
Block entity performance improvements (#1481)
* BlockEntity performance improvements

* Use chunk cache if possible for block caching

* Get new block state from ViaVersion if block entity

* Add Javadoc for FlowerPotBlockEntityTranslator.isFlowerBlock

* Remove debug line

* Don't add all RequiresBlockState instances if cache chunks is enabled

* Double chest map get optimization

* Last changes

Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
2020-11-05 22:36:22 +01:00
Camotoy
434a2e1500
Fix bell sound and visuals (#1502)
* Fix bell sound and visuals

The bell sound now correctly plays.

Bells will also visually ring when rung by another player.

* Compress elses

* Add more whitespace to new code
2020-11-05 14:59:01 -05:00
David Choo
ce64dd2788
Fix sitting with armor stand and animal mount offsets (#1492)
* Fix sitting with armor stand and animal offsets

* Fix riding players

* Moved @Getter
2020-11-04 20:30:55 -05:00
Matthias Neid
ea521078e1
Update supported version in README to 1.16.4 (#1488) 2020-11-02 16:44:45 -05:00
Camotoy
69d4d9f0d6
Send position update every 3 seconds if idle (#1421)
* Send position update every 3 seconds if idle

Prevents timeouts in certain instances when AFK.

* Cancel position sending on dimension switching

* Remove debug lines

* Create function to centralize movement translation
2020-11-02 16:04:08 -05:00
Camotoy
3e0d898b6a
Update to 1.16.4 (#1487)
* 1.16.4-pre1 support

* Update to support ViaVersion 3.2.0 (#1358)

* Update to support ViaVersion 3.2.0

This commit updates ViaVersion integration to support their recent mappings changes. 

Co-authored-by: Nassim <jahnke.nassim@gmail.com>

* Send adventure settings on gamemode change after gamemode swap

* Update Velocity to 1.1.0 proper

* Update to 1.16.4

Co-authored-by: Nassim <jahnke.nassim@gmail.com>
2020-11-02 13:28:31 -06:00
Camotoy
ca1f87d464
MapItemTranslator: support map tag being of short value (#1475)
GSigns sends this as a short. Who knows why.
2020-10-31 22:38:56 -04:00
Camotoy
e0f5deb329
Add support for more recipes (#1434)
* Add support for more recipes

- Tool repairing
- Book cloning
- Suspicious stew
- Tipped arrows

What still needs to be done:

- Map cloning/extending (though there may be item mapping mismatch getting in the way)
- Banner duplication (couldn't figure this out)

* Add some more spacing

* Explain recipe UUIDs
2020-10-29 18:40:42 -04:00
David Choo
8fdaf6a385
Ender dragon Melee Attacks (#1466)
* Create and position Ender Dragon Bounding Box

Currently allows the player to "kill aura" target
the ender dragon.

* Use an entity to handle attacks for each hitbox

* Use the proper flag to make entities invisible

* Clean up and add some comments

* Ender dragon entity metadata improvements

* Add doc to segment functions

* Add changes

Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
2020-10-29 18:35:46 -04:00
Camotoy
045c0e0637
Introduce CommandSender.getLocale() (#1431)
* Introduce CommandSender.getLocale()

This allows Geyser-specific commands (e.g. `/geyser help`) to be displayed in the (Java or Bedrock) player's default language, which stops those commands from simply being displayed in the default locale.

* Tweak Javadoc

* Set CommandManager's GeyserConnector to final

* Clean up
2020-10-29 18:30:52 -04:00
Camotoy
9b46bf8bc9
BedrockActionTranslator: Fix occasional death stall (#1432)
Usually this happened when joining from another dimension after the player exited to the main menu on the death screen. The player would not realize that they are dead.
2020-10-29 16:44:45 -04:00
Camotoy
a2a7e99402
GUI Improvements (#1462)
- Added `GeyserCommand.isExecutableOnConsole()`. If this is set to false, the command will not appear as an option in the GUI.
- Added `GeyserCommand.getSubCommands()`. If not empty, the subcommand options will now appear in the GUI.
2020-10-27 18:40:00 -04:00
SupremeMortal
04f0318bd0 Use new Open Collaboration maven repository 2020-10-27 11:24:18 +00:00
David Choo
d93d4d0942
Projectile fixes (#1451)
* Predict the trajectory of projectiles and add particles

* Correct lingering potion gravity

* Update last position on move absolute

* Clean up

* Add egg to ItemRegistry and update mappings
2020-10-26 11:54:37 -04:00
rtm516
c30cb78e74
Add statistics menu (#1424)
* Add statistics menu

* Changed back button text

* Add check to make sure the player requested the statistics display

* Better item translation support; misc changes

* Clean up session getting?

* Remove extra debug that is likely unnecessary

* Remove unused function

* Update languages submodule

* Clean up javadoc comment

* Fix typo

Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
Co-authored-by: Camotoy <20743703+DoctorMacc@users.noreply.github.com>
2020-10-24 23:33:49 +01:00
RednedEpic
dfba278f4d Use correct methods in refreshEmotes 2020-10-23 01:36:34 -05:00
RednedEpic
ee8c718c62 Translate emote list packet 2020-10-23 01:25:24 -05:00
rtm516
7f2b2e0913
Bedrock <-> Bedrock skin display fix (#1195)
* Implement partial bedrock skin fix

* Fix equals method

* Fix ViaVersion

Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
2020-10-22 23:01:03 -05:00
519 changed files with 14879 additions and 8394 deletions

2
.github/FUNDING.yml vendored
View file

@ -1,7 +1,7 @@
# These are supported funding model platforms # These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: GeyserMC patreon: #GeyserMC # Disabled currently
open_collective: # Replace with a single Open Collective username open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel

View file

@ -7,34 +7,51 @@ assignees: ''
--- ---
<!--- DELETING THIS TEMPLATE WILL GET YOUR ISSUE CLOSED! --->
<!--- Please follow this format COMPLETELY and make sure the bug you are reporting has not been reported yet. Reports should contain as much information or context as possible to help us find the problem. Simply creating an issue on a vague topic will not help us at all, and if you are unsure if something should belong here, please contact us on [Discord](http://discord.geysermc.org).--> <!--- Please follow this format COMPLETELY and make sure the bug you are reporting has not been reported yet. Reports should contain as much information or context as possible to help us find the problem. Simply creating an issue on a vague topic will not help us at all, and if you are unsure if something should belong here, please contact us on [Discord](http://discord.geysermc.org).-->
<!--- Issues pertaining to connection problem, or anything of that covered on the [Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues) do not belong here and only clutter this issue tracker. --> <!--- Issues pertaining to connection problems, or anything of that covered on the [Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues) do not belong here and only clutter this issue tracker. -->
**Describe the bug** **Describe the bug**
<!--- A clear and concise description of what the bug is. -->
A clear and concise description of what the bug is.
**To Reproduce** **To Reproduce**
<!--- Steps to reproduce the behavior: -->
<!--- 1. Go to '...' --> Steps to reproduce the behavior:
<!--- 2. Click on '....' --> 1. Go to '...'
<!--- 3. Scroll down to '....' --> 2. Click on '....'
<!--- 4. See error --> 3. Scroll down to '....'
4. See error
**Expected behavior** **Expected behavior**
<!--- A clear and concise description of what you expected to happen. -->
A clear and concise description of what you expected to happen.
**Screenshots / Videos** **Screenshots / Videos**
<!--- If applicable, add screenshots to help explain your problem. -->
**Server Version** If applicable, add screenshots to help explain your problem.
<!--- Give us the exact output from `/version`. Saying "latest" does not help us at all. -->
**Geyser Version** **Server Version and Plugins**
<!--- Give us the exact build number as well as branch if applicable. Saying "latest" does not help us at all. This info can be obtained from `/geyser version`.Please also include if you are running the standalone version, or specify which plugin version you are using. If your issue is a connection problem, please specify if you are using the Floodgate plugin. -->
If you just run Geyser-Spigot, you can leave this area blank as the next section covers this information.
If you're running a multi-server instance, or using Geyser Standalone:
- Give us the exact output from `/version` on all servers involved. Saying "latest" does not help us at all.
- Please list all plugins on all servers involved.
If this bug occurs on a server you do not control, please fill this in to the best of your knowledge.
**Geyser Dump**
If Geyser starts correctly, please also include the link to a dump by using `/geyser dump`. If you use the Standalone GUI, the option can be found under `Commands` => `Dump`. This provides us information about your server that we can use to debug your issue.
**Minecraft: Bedrock Edition Version** **Minecraft: Bedrock Edition Version**
<!-- The version of your Minecraft: Bedrock Edition client you tested with. -->
The version of your Minecraft: Bedrock Edition client you tested with, along with your device type (e.g. Windows 10, Switch...).
**Additional Context** **Additional Context**
<!--- Add any other context about the problem here. Include any plugins on the Minecraft server that may cause problems. Please also include the link to a dump by using `/geyser dump` --->
Add any other context about the problem here.

3
.gitignore vendored
View file

@ -242,4 +242,5 @@ logs/
public-key.pem public-key.pem
locales/ locales/
/cache/ /cache/
/packs/ /packs/
/dump.json

33
Jenkinsfile vendored
View file

@ -24,8 +24,29 @@ pipeline {
when { when {
branch "master" branch "master"
} }
steps { steps {
sh 'mvn javadoc:jar source:jar deploy -DskipTests' rtMavenDeployer(
id: "maven-deployer",
serverId: "opencollab-artifactory",
releaseRepo: "maven-releases",
snapshotRepo: "maven-snapshots"
)
rtMavenResolver(
id: "maven-resolver",
serverId: "opencollab-artifactory",
releaseRepo: "release",
snapshotRepo: "snapshot"
)
rtMavenRun(
pom: 'pom.xml',
goals: 'javadoc:jar source:jar install -DskipTests',
deployerId: "maven-deployer",
resolverId: "maven-resolver"
)
rtPublishBuildInfo(
serverId: "opencollab-artifactory"
)
} }
} }
} }
@ -65,7 +86,15 @@ pipeline {
} }
deleteDir() deleteDir()
withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) { withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) {
discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.nukkitx.com/job/Geyser)", footer: 'Cloudburst Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.opencollab.dev/job/GeyserMC/job/Geyser)", footer: 'Open Collaboration Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK
}
}
success {
script {
if (env.BRANCH_NAME == 'master') {
build propagate: false, wait: false, job: 'GeyserMC/Geyser-Fabric/java-1.16'
build propagate: false, wait: false, job: 'GeyserMC/GeyserAndroid/master'
}
} }
} }
} }

View file

@ -1,6 +1,6 @@
The MIT License The MIT License
Copyright (c) 2019-2020 GeyserMC. http://geysermc.org Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -3,7 +3,7 @@
[![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) [![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Build Status](https://ci.nukkitx.com/job/Geyser/job/master/badge/icon)](https://ci.nukkitx.com/job/GeyserMC/job/Geyser/job/master/) [![Build Status](https://ci.opencollab.dev/job/Geyser/job/master/badge/icon)](https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/)
[![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/)
[![HitCount](http://hits.dwyl.io/Geyser/GeyserMC.svg)](http://hits.dwyl.io/Geyser/GeyserMC) [![HitCount](http://hits.dwyl.io/Geyser/GeyserMC.svg)](http://hits.dwyl.io/Geyser/GeyserMC)
[![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/) [![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/)
@ -18,7 +18,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here! Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here!
### Currently supporting Minecraft Bedrock v1.16.x and Minecraft Java v1.16.3. ### Currently supporting Minecraft Bedrock v1.16.100 - v1.16.201 and Minecraft Java v1.16.4.
## Setting Up ## Setting Up
Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser. Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser.
@ -34,16 +34,26 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
- Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock - Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock
## What's Left to be Added/Fixed ## What's Left to be Added/Fixed
- The Following Inventories - Lecterns
- [ ] Enchantment Table (as a proper GUI) - Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you)
- [ ] Beacon - Resource pack conversion/CustomModelData
- [ ] Cartography Table
- [ ] Stonecutter
- [ ] Structure Block
- [ ] Horse Inventory
- [ ] Loom
- [ ] Smithing Table
- Some Entity Flags - Some Entity Flags
- The Following Inventories
- Enchantment Table (as a proper GUI)
- Beacon
- Cartography Table
- Stonecutter
- Structure Block
- Horse Inventory
- Loom
- Smithing Table
## What can't be fixed
The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now.
- Custom heads in inventories
- Clickable links in chat
- Glowing effect
## Compiling ## Compiling
1. Clone the repo to your computer 1. Clone the repo to your computer

View file

@ -6,15 +6,15 @@
<parent> <parent>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId> <artifactId>bootstrap-parent</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<artifactId>bootstrap-bungeecord</artifactId> <artifactId>bootstrap-bungeecord</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>connector</artifactId> <artifactId>connector</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -86,8 +86,8 @@
<shadedPattern>org.geysermc.platform.bungeecord.shaded.dom4j</shadedPattern> <shadedPattern>org.geysermc.platform.bungeecord.shaded.dom4j</shadedPattern>
</relocation> </relocation>
<relocation> <relocation>
<pattern>net.kyori.adventure</pattern> <pattern>net.kyori</pattern>
<shadedPattern>org.geysermc.platform.bungeecord.shaded.adventure</shadedPattern> <shadedPattern>org.geysermc.platform.bungeecord.shaded.kyori</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
</configuration> </configuration>

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -47,14 +47,12 @@ import java.util.concurrent.CompletableFuture;
@AllArgsConstructor @AllArgsConstructor
public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener { public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener {
private static final GeyserPendingConnection PENDING_CONNECTION = new GeyserPendingConnection();
private final ProxyServer proxyServer; private final ProxyServer proxyServer;
@Override @Override
public GeyserPingInfo getPingInformation() { public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
CompletableFuture<ProxyPingEvent> future = new CompletableFuture<>(); CompletableFuture<ProxyPingEvent> future = new CompletableFuture<>();
proxyServer.getPluginManager().callEvent(new ProxyPingEvent(PENDING_CONNECTION, getPingInfo(), (event, throwable) -> { proxyServer.getPluginManager().callEvent(new ProxyPingEvent(new GeyserPendingConnection(inetSocketAddress), getPingInfo(), (event, throwable) -> {
if (throwable != null) future.completeExceptionally(throwable); if (throwable != null) future.completeExceptionally(throwable);
else future.complete(event); else future.complete(event);
})); }));
@ -89,7 +87,12 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
private static class GeyserPendingConnection implements PendingConnection { private static class GeyserPendingConnection implements PendingConnection {
private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes()); private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes());
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69);
private final InetSocketAddress remote;
public GeyserPendingConnection(InetSocketAddress remote) {
this.remote = remote;
}
@Override @Override
public String getName() { public String getName() {
@ -143,7 +146,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
@Override @Override
public InetSocketAddress getAddress() { public InetSocketAddress getAddress() {
return FAKE_REMOTE; return remote;
} }
@Override @Override

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -27,10 +27,10 @@ package org.geysermc.platform.bungeecord;
import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.common.PlatformType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -25,17 +25,20 @@
package org.geysermc.platform.bungeecord.command; package org.geysermc.platform.bungeecord.command;
import lombok.AllArgsConstructor;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.utils.LanguageUtils;
@AllArgsConstructor
public class BungeeCommandSender implements CommandSender { public class BungeeCommandSender implements CommandSender {
private net.md_5.bungee.api.CommandSender handle; private final net.md_5.bungee.api.CommandSender handle;
public BungeeCommandSender(net.md_5.bungee.api.CommandSender handle) {
this.handle = handle;
// Ensure even Java players' languages are loaded
LanguageUtils.loadGeyserLocale(getLocale());
}
@Override @Override
public String getName() { public String getName() {
@ -51,4 +54,14 @@ public class BungeeCommandSender implements CommandSender {
public boolean isConsole() { public boolean isConsole() {
return !(handle instanceof ProxiedPlayer); return !(handle instanceof ProxiedPlayer);
} }
@Override
public String getLocale() {
if (handle instanceof ProxiedPlayer) {
ProxiedPlayer player = (ProxiedPlayer) handle;
String locale = player.getLocale().getLanguage() + "_" + player.getLocale().getCountry();
return LanguageUtils.formatLocale(locale);
}
return LanguageUtils.getDefaultLocale();
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -27,13 +27,10 @@ package org.geysermc.platform.bungeecord.command;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor; import net.md_5.bungee.api.plugin.TabExecutor;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList; import java.util.ArrayList;
@ -41,7 +38,7 @@ import java.util.Arrays;
public class GeyserBungeeCommandExecutor extends Command implements TabExecutor { public class GeyserBungeeCommandExecutor extends Command implements TabExecutor {
private GeyserConnector connector; private final GeyserConnector connector;
public GeyserBungeeCommandExecutor(GeyserConnector connector) { public GeyserBungeeCommandExecutor(GeyserConnector connector) {
super("geyser"); super("geyser");
@ -54,14 +51,10 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
if (args.length > 0) { if (args.length > 0) {
if (getCommand(args[0]) != null) { if (getCommand(args[0]) != null) {
if (!sender.hasPermission(getCommand(args[0]).getPermission())) { if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
String message = ""; BungeeCommandSender commandSender = new BungeeCommandSender(sender);
if (sender instanceof GeyserSession) { String message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale());
message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", ((GeyserSession) sender).getClientData().getLanguageCode());
} else {
message = LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail");
}
sender.sendMessage(TextComponent.fromLegacyText(ChatColor.RED + message)); commandSender.sendMessage(ChatColor.RED + message);
return; return;
} }
getCommand(args[0]).execute(new BungeeCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); getCommand(args[0]).execute(new BungeeCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
@ -74,7 +67,7 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor
@Override @Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args) { public Iterable<String> onTabComplete(CommandSender sender, String[] args) {
if (args.length == 1) { if (args.length == 1) {
return Arrays.asList("?", "help", "reload", "shutdown", "stop"); return connector.getCommandManager().getCommandNames();
} }
return new ArrayList<>(); return new ArrayList<>();
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -6,12 +6,11 @@
<parent> <parent>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>geyser-parent</artifactId> <artifactId>geyser-parent</artifactId>
<version>parent</version> <version>1.2.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<artifactId>bootstrap-parent</artifactId> <artifactId>bootstrap-parent</artifactId>
<version>1.1.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<repositories> <repositories>
<repository> <repository>
<id>spigot-public</id> <id>spigot-public</id>

View file

@ -6,15 +6,15 @@
<parent> <parent>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId> <artifactId>bootstrap-parent</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<artifactId>bootstrap-spigot</artifactId> <artifactId>bootstrap-spigot</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>connector</artifactId> <artifactId>connector</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -26,9 +26,14 @@
<dependency> <dependency>
<groupId>us.myles</groupId> <groupId>us.myles</groupId>
<artifactId>viaversion</artifactId> <artifactId>viaversion</artifactId>
<version>3.1.1</version> <version>3.2.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.geysermc.adapters</groupId>
<artifactId>spigot-all</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<finalName>${outputName}-Spigot</finalName> <finalName>${outputName}-Spigot</finalName>
@ -92,8 +97,8 @@
<shadedPattern>org.geysermc.platform.spigot.shaded.dom4j</shadedPattern> <shadedPattern>org.geysermc.platform.spigot.shaded.dom4j</shadedPattern>
</relocation> </relocation>
<relocation> <relocation>
<pattern>net.kyori.adventure</pattern> <pattern>net.kyori</pattern>
<shadedPattern>org.geysermc.platform.spigot.shaded.adventure</shadedPattern> <shadedPattern>org.geysermc.platform.spigot.shaded.kyori</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
</configuration> </configuration>

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -35,6 +35,7 @@ import org.geysermc.connector.common.ping.GeyserPingInfo;
import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
@ -44,9 +45,9 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough {
private final GeyserSpigotLogger logger; private final GeyserSpigotLogger logger;
@Override @Override
public GeyserPingInfo getPingInformation() { public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
try { try {
ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers()); ServerListPingEvent event = new GeyserPingEvent(inetSocketAddress.getAddress(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(),
new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()), new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()),

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -25,12 +25,14 @@
package org.geysermc.platform.spigot; package org.geysermc.platform.spigot;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.geysermc.adapters.spigot.SpigotAdapters;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.common.PlatformType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.network.translators.world.WorldManager; import org.geysermc.connector.network.translators.world.WorldManager;
@ -40,18 +42,25 @@ import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor; import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor;
import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager; import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
import org.geysermc.platform.spigot.command.SpigotCommandSender;
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener; import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
import org.geysermc.platform.spigot.world.GeyserSpigotWorldManager; import org.geysermc.platform.spigot.world.manager.*;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.MappingData;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
private GeyserSpigotCommandManager geyserCommandManager; private GeyserSpigotCommandManager geyserCommandManager;
private GeyserSpigotConfiguration geyserConfig; private GeyserSpigotConfiguration geyserConfig;
private GeyserSpigotLogger geyserLogger; private GeyserSpigotLogger geyserLogger;
@ -120,6 +129,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
this.geyserCommandManager = new GeyserSpigotCommandManager(this, connector); this.geyserCommandManager = new GeyserSpigotCommandManager(this, connector);
boolean isViaVersion = (Bukkit.getPluginManager().getPlugin("ViaVersion") != null); boolean isViaVersion = (Bukkit.getPluginManager().getPlugin("ViaVersion") != null);
if (isViaVersion) {
if (!isCompatible(Via.getAPI().getVersion().replace("-SNAPSHOT", ""), "3.2.0")) {
geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.viaversion.too_old",
"https://ci.viaversion.com/job/ViaVersion/"));
isViaVersion = false;
}
}
// Used to determine if Block.getBlockData() is present. // Used to determine if Block.getBlockData() is present.
boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0"); boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0");
if (isLegacy) if (isLegacy)
@ -130,8 +146,51 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
geyserLogger.debug("Legacy version of Minecraft (1.15.2 or older) detected; not using 3D biomes."); geyserLogger.debug("Legacy version of Minecraft (1.15.2 or older) detected; not using 3D biomes.");
} }
this.geyserWorldManager = new GeyserSpigotWorldManager(isLegacy, use3dBiomes, isViaVersion); // Set if we need to use a different method for getting a player's locale
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, isLegacy, isViaVersion); SpigotCommandSender.setUseLegacyLocaleMethod(!isCompatible(Bukkit.getServer().getVersion(), "1.12.0"));
if (connector.getConfig().isUseAdapters()) {
try {
String name = Bukkit.getServer().getClass().getPackage().getName();
String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
SpigotAdapters.registerWorldAdapter(nmsVersion);
if (isViaVersion && isViaVersionNeeded()) {
if (isLegacy) {
// Pre-1.13
this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager();
} else {
// Post-1.13
this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, use3dBiomes);
}
} else {
// No ViaVersion
this.geyserWorldManager = new GeyserSpigotNativeWorldManager(use3dBiomes);
}
geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion);
} catch (Exception e) {
if (geyserConfig.isDebugMode()) {
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
e.printStackTrace();
}
}
} else {
geyserLogger.debug("Not using NMS adapter as it is disabled in the config.");
}
if (this.geyserWorldManager == null) {
// No NMS adapter
if (isLegacy && isViaVersion) {
// Use ViaVersion for converting pre-1.13 block states
this.geyserWorldManager = new GeyserSpigot1_12WorldManager();
} else if (isLegacy) {
// Not sure how this happens - without ViaVersion, we don't know any block states, so just assume everything is air
this.geyserWorldManager = new GeyserSpigotFallbackWorldManager();
} else {
// Post-1.13
this.geyserWorldManager = new GeyserSpigotWorldManager(use3dBiomes);
}
geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass());
}
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, this.geyserWorldManager);
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
@ -140,8 +199,9 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
@Override @Override
public void onDisable() { public void onDisable() {
if (connector != null) if (connector != null) {
connector.shutdown(); connector.shutdown();
}
} }
@Override @Override
@ -174,6 +234,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
return getDataFolder().toPath(); return getDataFolder().toPath();
} }
@Override
public BootstrapDumpInfo getDumpInfo() {
return new GeyserSpigotDumpInfo();
}
public boolean isCompatible(String version, String whichVersion) { public boolean isCompatible(String version, String whichVersion) {
int[] currentVersion = parseVersion(version); int[] currentVersion = parseVersion(version);
int[] otherVersion = parseVersion(whichVersion); int[] otherVersion = parseVersion(whichVersion);
@ -201,15 +266,43 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
String t = stringArray[index].replaceAll("\\D", ""); String t = stringArray[index].replaceAll("\\D", "");
try { try {
temp[index] = Integer.parseInt(t); temp[index] = Integer.parseInt(t);
} catch(NumberFormatException ex) { } catch (NumberFormatException ex) {
temp[index] = 0; temp[index] = 0;
} }
} }
return temp; return temp;
} }
@Override /**
public BootstrapDumpInfo getDumpInfo() { * @return the server version before ViaVersion finishes initializing
return new GeyserSpigotDumpInfo(); */
public ProtocolVersion getServerProtocolVersion() {
String bukkitVersion = Bukkit.getServer().getVersion();
// Turn "(MC: 1.16.4)" into 1.16.4.
String version = bukkitVersion.split("\\(MC: ")[1].split("\\)")[0];
return ProtocolVersion.getClosest(version);
}
/**
* This function should not run unless ViaVersion is installed on the server.
*
* @return true if there is any block mappings difference between the server and client.
*/
private boolean isViaVersionNeeded() {
ProtocolVersion serverVersion = getServerProtocolVersion();
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
serverVersion.getVersion());
if (protocolList == null) {
// No translation needed!
return false;
}
for (int i = protocolList.size() - 1; i >= 0; i--) {
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
if (mappingData != null) {
return true;
}
}
// All mapping data is null, which means client and server block states are the same
return false;
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -32,7 +32,6 @@ import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor; import org.bukkit.command.TabExecutor;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList; import java.util.ArrayList;
@ -42,21 +41,17 @@ import java.util.List;
@AllArgsConstructor @AllArgsConstructor
public class GeyserSpigotCommandExecutor implements TabExecutor { public class GeyserSpigotCommandExecutor implements TabExecutor {
private GeyserConnector connector; private final GeyserConnector connector;
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length > 0) { if (args.length > 0) {
if (getCommand(args[0]) != null) { if (getCommand(args[0]) != null) {
if (!sender.hasPermission(getCommand(args[0]).getPermission())) { if (!sender.hasPermission(getCommand(args[0]).getPermission())) {
String message = ""; SpigotCommandSender commandSender = new SpigotCommandSender(sender);
if (sender instanceof GeyserSession) { String message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale());;
message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", ((GeyserSession) sender).getClientData().getLanguageCode());
} else {
message = LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail");
}
sender.sendMessage(ChatColor.RED + message); commandSender.sendMessage(ChatColor.RED + message);
return true; return true;
} }
getCommand(args[0]).execute(new SpigotCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); getCommand(args[0]).execute(new SpigotCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]);
@ -72,7 +67,7 @@ public class GeyserSpigotCommandExecutor implements TabExecutor {
@Override @Override
public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) { public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
if (args.length == 1) { if (args.length == 1) {
return Arrays.asList("?", "help", "reload", "shutdown", "stop"); return connector.getCommandManager().getCommandNames();
} }
return new ArrayList<>(); return new ArrayList<>();
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -25,15 +25,33 @@
package org.geysermc.platform.spigot.command; package org.geysermc.platform.spigot.command;
import lombok.AllArgsConstructor;
import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.utils.LanguageUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@AllArgsConstructor
public class SpigotCommandSender implements CommandSender { public class SpigotCommandSender implements CommandSender {
private org.bukkit.command.CommandSender handle; /**
* Whether to use {@code Player.getLocale()} or {@code Player.spigot().getLocale()}, depending on version.
* 1.12 or greater should not use the legacy method.
*/
private static boolean USE_LEGACY_METHOD = false;
private static Method LOCALE_METHOD;
private final org.bukkit.command.CommandSender handle;
private final String locale;
public SpigotCommandSender(org.bukkit.command.CommandSender handle) {
this.handle = handle;
this.locale = getSpigotLocale();
// Ensure even Java players' languages are loaded
LanguageUtils.loadGeyserLocale(locale);
}
@Override @Override
public String getName() { public String getName() {
@ -49,4 +67,49 @@ public class SpigotCommandSender implements CommandSender {
public boolean isConsole() { public boolean isConsole() {
return handle instanceof ConsoleCommandSender; return handle instanceof ConsoleCommandSender;
} }
@Override
public String getLocale() {
return locale;
}
/**
* Set if we are on pre-1.12, and therefore {@code player.getLocale()} doesn't exist and we have to get
* {@code player.spigot().getLocale()}.
*
* @param useLegacyMethod if we are running pre-1.12 and therefore need to use reflection to get the player locale
*/
public static void setUseLegacyLocaleMethod(boolean useLegacyMethod) {
USE_LEGACY_METHOD = useLegacyMethod;
if (USE_LEGACY_METHOD) {
try {
//noinspection JavaReflectionMemberAccess - of course it doesn't exist; that's why we're doing it
LOCALE_METHOD = Player.Spigot.class.getMethod("getLocale");
} catch (NoSuchMethodException e) {
GeyserConnector.getInstance().getLogger().debug("Player.Spigot.getLocale() doesn't exist? Not a big deal but if you're seeing this please report it to the developers!");
}
}
}
/**
* So we only have to do nasty reflection stuff once per command
*
* @return the locale of the Spigot player
*/
private String getSpigotLocale() {
if (handle instanceof Player) {
Player player = (Player) handle;
if (USE_LEGACY_METHOD) {
try {
// sigh
// This was the only option on older Spigot instances and now it's gone
return (String) LOCALE_METHOD.invoke(player.spigot());
} catch (IllegalAccessException | InvocationTargetException ignored) {
}
} else {
return player.getLocale();
}
}
return LanguageUtils.getDefaultLocale();
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -36,13 +36,13 @@ import org.bukkit.event.block.BlockPlaceEvent;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.platform.spigot.world.manager.GeyserSpigotWorldManager;
@AllArgsConstructor @AllArgsConstructor
public class GeyserSpigotBlockPlaceListener implements Listener { public class GeyserSpigotBlockPlaceListener implements Listener {
private final GeyserConnector connector; private final GeyserConnector connector;
private final boolean isLegacy; private final GeyserSpigotWorldManager worldManager;
private final boolean isViaVersion;
@EventHandler @EventHandler
public void place(final BlockPlaceEvent event) { public void place(final BlockPlaceEvent event) {
@ -52,14 +52,13 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
placeBlockSoundPacket.setSound(SoundEvent.PLACE); placeBlockSoundPacket.setSound(SoundEvent.PLACE);
placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())); placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()));
placeBlockSoundPacket.setBabySound(false); placeBlockSoundPacket.setBabySound(false);
String javaBlockId; if (worldManager.isLegacy()) {
if (isLegacy) { placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(worldManager.getBlockAt(session,
javaBlockId = BlockTranslator.getJavaIdBlockMap().inverse().get(GeyserSpigotWorldManager.getLegacyBlock(session, event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ(), isViaVersion));
} else { } else {
javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, BlockTranslator.JAVA_AIR_ID)));
} }
placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, 0)));
placeBlockSoundPacket.setIdentifier(":"); placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket); session.sendUpstreamPacket(placeBlockSoundPacket);
session.setLastBlockPlacePosition(null); session.setLastBlockPlacePosition(null);

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.geysermc.adapters.spigot.SpigotAdapters;
import org.geysermc.adapters.spigot.SpigotWorldAdapter;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
/**
* Used with ViaVersion and pre-1.13.
*/
public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldManager {
private final SpigotWorldAdapter adapter;
public GeyserSpigot1_12NativeWorldManager() {
this.adapter = SpigotAdapters.getWorldAdapter();
// Unlike post-1.13, we can't build up a cache of block states, because block entities need some special conversion
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return BlockTranslator.JAVA_AIR_ID;
}
// Get block entity storage
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
int blockId = adapter.getBlockAt(player.getWorld(), x, y, z);
return getLegacyBlock(storage, blockId, x, y, z);
}
}

View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.MappingData;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage;
import java.util.List;
/**
* Should be used when ViaVersion is present, no NMS adapter is being used, and we are pre-1.13.
*
* You need ViaVersion to connect to an older server with the Geyser-Spigot plugin.
*/
public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
/**
* Specific mapping data for 1.12 to 1.13. Used to convert the 1.12 block into the 1.13 block state.
* (Block IDs did not change between server versions until 1.13 and after)
*/
private final MappingData mappingData1_12to1_13;
/**
* The list of all protocols from the client's version to 1.13.
*/
private final List<Pair<Integer, Protocol>> protocolList;
public GeyserSpigot1_12WorldManager() {
super(false);
this.mappingData1_12to1_13 = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData();
this.protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION,
ProtocolVersion.v1_13.getVersion());
}
@Override
@SuppressWarnings("deprecation")
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return BlockTranslator.JAVA_AIR_ID;
}
// Get block entity storage
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
Block block = player.getWorld().getBlockAt(x, y, z);
// Black magic that gets the old block state ID
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
return getLegacyBlock(storage, blockId, x, y, z);
}
/**
*
* @param storage ViaVersion's block entity storage (used to fix block entity state differences)
* @param blockId the pre-1.13 block id
* @param x X coordinate of block
* @param y Y coordinate of block
* @param z Z coordinate of block
* @return the block state updated to the latest Minecraft version
*/
@SuppressWarnings("deprecation")
public int getLegacyBlock(BlockStorage storage, int blockId, int x, int y, int z) {
// Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
blockId = mappingData1_12to1_13.getNewBlockId(blockId);
// Translate block entity differences - some information was stored in block tags and not block states
if (storage.isWelcome(blockId)) { // No getOrDefault method
BlockStorage.ReplacementData data = storage.get(new Position(x, (short) y, z));
if (data != null && data.getReplacement() != -1) {
blockId = data.getReplacement();
}
}
for (int i = protocolList.size() - 1; i >= 0; i--) {
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
if (mappingData != null) {
blockId = mappingData.getNewBlockStateId(blockId);
}
}
return blockId;
}
@SuppressWarnings("deprecation")
@Override
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return;
}
World world = player.getWorld();
// Get block entity storage
BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class);
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
for (int blockZ = 0; blockZ < 16; blockZ++) {
for (int blockX = 0; blockX < 16; blockX++) {
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
// Black magic that gets the old block state ID
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, blockId, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ));
}
}
}
}
@Override
public boolean isLegacy() {
return true;
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
/**
* Should only be used when we know {@link GeyserSpigotWorldManager#getBlockAt(GeyserSession, int, int, int)}
* cannot be accurate. Typically, this is when ViaVersion is not installed but a client still manages to connect.
* If this occurs to you somehow, please let us know!!
*/
public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager {
public GeyserSpigotFallbackWorldManager() {
// Since this is pre-1.13 (and thus pre-1.15), there will never be 3D biomes.
super(false);
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
return BlockTranslator.JAVA_AIR_ID;
}
@Override
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
// Do nothing, since we can't do anything with the chunk
}
@Override
public boolean hasMoreBlockDataThanChunkCache() {
return false;
}
@Override
public boolean isLegacy() {
return true;
}
}

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntList;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.platform.spigot.GeyserSpigotPlugin;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.api.data.MappingData;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
import java.util.List;
/**
* Used when block IDs need to be translated to the latest version
*/
public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorldManager {
private final Int2IntMap oldToNewBlockId;
public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean use3dBiomes) {
super(use3dBiomes);
IntList allBlockStates = adapter.getAllBlockStates();
oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size());
ProtocolVersion serverVersion = plugin.getServerProtocolVersion();
List<Pair<Integer, Protocol>> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION,
serverVersion.getVersion());
for (int oldBlockId : allBlockStates) {
int newBlockId = oldBlockId;
// protocolList should *not* be null; we checked for that before initializing this class
for (int i = protocolList.size() - 1; i >= 0; i--) {
MappingData mappingData = protocolList.get(i).getValue().getMappingData();
if (mappingData != null) {
newBlockId = mappingData.getNewBlockStateId(newBlockId);
}
}
oldToNewBlockId.put(oldBlockId, newBlockId);
}
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
int nativeBlockId = super.getBlockAt(session, x, y, z);
return oldToNewBlockId.getOrDefault(nativeBlockId, nativeBlockId);
}
@Override
public boolean isLegacy() {
return true;
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.platform.spigot.world.manager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.geysermc.adapters.spigot.SpigotAdapters;
import org.geysermc.adapters.spigot.SpigotWorldAdapter;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
protected final SpigotWorldAdapter adapter;
public GeyserSpigotNativeWorldManager(boolean use3dBiomes) {
super(use3dBiomes);
adapter = SpigotAdapters.getWorldAdapter();
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
return BlockTranslator.JAVA_AIR_ID;
}
return adapter.getBlockAt(player.getWorld(), x, y, z);
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,9 +23,10 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.platform.spigot.world; package org.geysermc.platform.spigot.world.manager;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; import com.github.steveice10.mc.protocol.data.game.chunk.Chunk;
import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
@ -33,6 +34,7 @@ import org.bukkit.Bukkit;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.session.GeyserSession;
@ -41,20 +43,22 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.FileUtils;
import org.geysermc.connector.utils.GameRule; import org.geysermc.connector.utils.GameRule;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13;
import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.data.MappingData;
import java.io.InputStream; import java.io.InputStream;
/**
* The base world manager to use when there is no supported NMS revision
*/
public class GeyserSpigotWorldManager extends GeyserWorldManager { public class GeyserSpigotWorldManager extends GeyserWorldManager {
private final boolean isLegacy;
private final boolean use3dBiomes;
/** /**
* You need ViaVersion to connect to an older server with Geyser. * The current client protocol version for ViaVersion usage.
* However, we still check for ViaVersion in case there's some other way that gets Geyser on a pre-1.13 Bukkit server
*/ */
private final boolean isViaVersion; protected static final int CLIENT_PROTOCOL_VERSION = MinecraftConstants.PROTOCOL_VERSION;
/**
* Whether the server is pre-1.16 and therefore does not support 3D biomes on an API level guaranteed.
*/
private final boolean use3dBiomes;
/** /**
* Stores a list of {@link Biome} ordinal numbers to Minecraft biome numeric IDs. * Stores a list of {@link Biome} ordinal numbers to Minecraft biome numeric IDs.
* *
@ -68,10 +72,8 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
*/ */
private final Int2IntMap biomeToIdMap = new Int2IntOpenHashMap(Biome.values().length); private final Int2IntMap biomeToIdMap = new Int2IntOpenHashMap(Biome.values().length);
public GeyserSpigotWorldManager(boolean isLegacy, boolean use3dBiomes, boolean isViaVersion) { public GeyserSpigotWorldManager(boolean use3dBiomes) {
this.isLegacy = isLegacy;
this.use3dBiomes = use3dBiomes; this.use3dBiomes = use3dBiomes;
this.isViaVersion = isViaVersion;
// Load the values into the biome-to-ID map // Load the values into the biome-to-ID map
InputStream biomeStream = FileUtils.getResource("biomes.json"); InputStream biomeStream = FileUtils.getResource("biomes.json");
@ -83,8 +85,9 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
} }
// Only load in the biomes that are present in this version of Minecraft // Only load in the biomes that are present in this version of Minecraft
for (Biome enumBiome : Biome.values()) { for (Biome enumBiome : Biome.values()) {
if (biomes.has(enumBiome.toString())) { JsonNode biome = biomes.get(enumBiome.toString());
biomeToIdMap.put(enumBiome.ordinal(), biomes.get(enumBiome.toString()).intValue()); if (biome != null) {
biomeToIdMap.put(enumBiome.ordinal(), biome.intValue());
} else { } else {
GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() + GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() +
", defaulting to 0"); ", defaulting to 0");
@ -96,71 +99,26 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
@Override @Override
public int getBlockAt(GeyserSession session, int x, int y, int z) { public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player bukkitPlayer; Player bukkitPlayer;
if ((this.isLegacy && !this.isViaVersion) if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|| session.getPlayerEntity() == null return BlockTranslator.JAVA_AIR_ID;
|| (bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return BlockTranslator.AIR;
} }
World world = bukkitPlayer.getWorld(); World world = bukkitPlayer.getWorld();
if (isLegacy) { return BlockTranslator.getJavaIdBlockMap().getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
return getLegacyBlock(session, x, y, z, true);
}
//TODO possibly: detect server version for all versions and use ViaVersion for block state mappings like below
return BlockTranslator.getJavaIdBlockMap().getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), 0);
}
public static int getLegacyBlock(GeyserSession session, int x, int y, int z, boolean isViaVersion) {
if (isViaVersion) {
return getLegacyBlock(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld(), x, y, z, true);
} else {
return BlockTranslator.AIR;
}
}
@SuppressWarnings("deprecation")
public static int getLegacyBlock(World world, int x, int y, int z, boolean isViaVersion) {
if (isViaVersion) {
Block block = world.getBlockAt(x, y, z);
// Black magic that gets the old block state ID
int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
// Convert block state from old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2
int thirteenBlockId = us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData.blockMappings.getNewId(oldBlockId);
int thirteenPointOneBlockId = Protocol1_13_1To1_13.getNewBlockStateId(thirteenBlockId);
int fourteenBlockId = us.myles.ViaVersion.protocols.protocol1_14to1_13_2.data.MappingData.blockStateMappings.getNewId(thirteenPointOneBlockId);
int fifteenBlockId = us.myles.ViaVersion.protocols.protocol1_15to1_14_4.data.MappingData.blockStateMappings.getNewId(fourteenBlockId);
int sixteenBlockId = us.myles.ViaVersion.protocols.protocol1_16to1_15_2.data.MappingData.blockStateMappings.getNewId(fifteenBlockId);
return MappingData.blockStateMappings.getNewId(sixteenBlockId);
} else {
return BlockTranslator.AIR;
}
} }
@Override @Override
public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) { public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) {
Player bukkitPlayer; Player bukkitPlayer;
if ((this.isLegacy && !this.isViaVersion) if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
|| session.getPlayerEntity() == null
|| (bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
return; return;
} }
World world = bukkitPlayer.getWorld(); World world = bukkitPlayer.getWorld();
if (this.isLegacy) { for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order for (int blockZ = 0; blockZ < 16; blockZ++) {
for (int blockZ = 0; blockZ < 16; blockZ++) { for (int blockX = 0; blockX < 16; blockX++) {
for (int blockX = 0; blockX < 16; blockX++) { Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
chunk.set(blockX, blockY, blockZ, getLegacyBlock(world, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ, true)); int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID);
} chunk.set(blockX, blockY, blockZ, id);
}
}
} else {
//TODO: see above TODO in getBlockAt
for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order
for (int blockZ = 0; blockZ < 16; blockZ++) {
for (int blockX = 0; blockX < 16; blockX++) {
Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ);
int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), 0);
chunk.set(blockX, blockY, blockZ, id);
}
} }
} }
} }
@ -222,4 +180,16 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
public boolean hasPermission(GeyserSession session, String permission) { public boolean hasPermission(GeyserSession session, String permission) {
return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission); return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission);
} }
/**
* This must be set to true if we are pre-1.13, and {@link BlockData#getAsString() does not exist}.
*
* This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id
* to the current one.
*
* @return whether there is a difference between client block state and server block state that requires extra processing
*/
public boolean isLegacy() {
return false;
}
} }

View file

@ -6,15 +6,15 @@
<parent> <parent>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId> <artifactId>bootstrap-parent</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<artifactId>bootstrap-sponge</artifactId> <artifactId>bootstrap-sponge</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>connector</artifactId> <artifactId>connector</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -86,8 +86,8 @@
<shadedPattern>org.geysermc.platform.sponge.shaded.dom4j</shadedPattern> <shadedPattern>org.geysermc.platform.sponge.shaded.dom4j</shadedPattern>
</relocation> </relocation>
<relocation> <relocation>
<pattern>net.kyori.adventure</pattern> <pattern>net.kyori</pattern>
<shadedPattern>org.geysermc.platform.sponge.shaded.adventure</shadedPattern> <shadedPattern>org.geysermc.platform.sponge.shaded.kyori</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
</configuration> </configuration>

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -38,31 +38,29 @@ import org.spongepowered.api.network.status.StatusClient;
import org.spongepowered.api.profile.GameProfile; import org.spongepowered.api.profile.GameProfile;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.Inet4Address;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.Optional; import java.util.Optional;
public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
private static final GeyserStatusClient STATUS_CLIENT = new GeyserStatusClient();
private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer()); private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer());
private static Method SpongeStatusResponse_create; private static Method SpongeStatusResponse_create;
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
@Override @Override
public GeyserPingInfo getPingInformation() { public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
// come on Sponge, this is in commons, why not expose it :( // come on Sponge, this is in commons, why not expose it :(
ClientPingServerEvent event; ClientPingServerEvent event;
try { try {
if(SpongeStatusResponse_create == null) { if (SpongeStatusResponse_create == null) {
Class SpongeStatusResponse = Class.forName("org.spongepowered.common.network.status.SpongeStatusResponse"); Class SpongeStatusResponse = Class.forName("org.spongepowered.common.network.status.SpongeStatusResponse");
Class MinecraftServer = Class.forName("net.minecraft.server.MinecraftServer"); Class MinecraftServer = Class.forName("net.minecraft.server.MinecraftServer");
SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer); SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer);
} }
Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer()); Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer());
event = SpongeEventFactory.createClientPingServerEvent(CAUSE, STATUS_CLIENT, (ClientPingServerEvent.Response) response); event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response);
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -76,7 +74,7 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
new GeyserPingInfo.Version( new GeyserPingInfo.Version(
event.getResponse().getVersion().getName(), event.getResponse().getVersion().getName(),
MinecraftConstants.PROTOCOL_VERSION) // thanks for also not exposing this sponge MinecraftConstants.PROTOCOL_VERSION) // thanks for also not exposing this sponge
); );
event.getResponse().getPlayers().get().getProfiles().stream() event.getResponse().getPlayers().get().getProfiles().stream()
.map(GameProfile::getName) .map(GameProfile::getName)
.map(op -> op.orElseThrow(IllegalStateException::new)) .map(op -> op.orElseThrow(IllegalStateException::new))
@ -87,11 +85,15 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
@SuppressWarnings("NullableProblems") @SuppressWarnings("NullableProblems")
private static class GeyserStatusClient implements StatusClient { private static class GeyserStatusClient implements StatusClient {
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69); private final InetSocketAddress remote;
public GeyserStatusClient(InetSocketAddress remote) {
this.remote = remote;
}
@Override @Override
public InetSocketAddress getAddress() { public InetSocketAddress getAddress() {
return FAKE_REMOTE; return this.remote;
} }
@Override @Override

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -26,10 +26,10 @@
package org.geysermc.platform.sponge; package org.geysermc.platform.sponge;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.common.PlatformType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -70,7 +70,7 @@ public class GeyserSpongeCommandExecutor implements CommandCallable {
@Override @Override
public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException { public List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException {
if (arguments.split(" ").length == 1) { if (arguments.split(" ").length == 1) {
return Arrays.asList("?", "help", "reload", "shutdown", "stop"); return connector.getCommandManager().getCommandNames();
} }
return new ArrayList<>(); return new ArrayList<>();
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -6,15 +6,15 @@
<parent> <parent>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId> <artifactId>bootstrap-parent</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<artifactId>bootstrap-standalone</artifactId> <artifactId>bootstrap-standalone</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>connector</artifactId> <artifactId>connector</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -25,17 +25,23 @@
package org.geysermc.platform.standalone; package org.geysermc.platform.standalone;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import lombok.Getter; import lombok.Getter;
import net.minecrell.terminalconsole.TerminalConsoleAppender; import net.minecrell.terminalconsole.TerminalConsoleAppender;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.common.PlatformType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.configuration.GeyserJacksonConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough;
@ -50,7 +56,8 @@ import java.lang.reflect.Method;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.UUID; import java.util.*;
import java.util.stream.Collectors;
public class GeyserStandaloneBootstrap implements GeyserBootstrap { public class GeyserStandaloneBootstrap implements GeyserBootstrap {
@ -67,6 +74,9 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
private GeyserConnector connector; private GeyserConnector connector;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final Map<String, String> argsConfigKeys = new HashMap<>();
public static void main(String[] args) { public static void main(String[] args) {
GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap(); GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap();
@ -74,6 +84,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
boolean useGuiOpts = bootstrap.useGui; boolean useGuiOpts = bootstrap.useGui;
String configFilenameOpt = bootstrap.configFilename; String configFilenameOpt = bootstrap.configFilename;
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
// By default, standalone Geyser will check if it should open the GUI based on if the GUI is null // By default, standalone Geyser will check if it should open the GUI based on if the GUI is null
// Optionally, you can force the use of a GUI or no GUI by specifying args // Optionally, you can force the use of a GUI or no GUI by specifying args
@ -91,11 +103,11 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
case "--config": case "--config":
case "-c": case "-c":
if (i >= args.length - 1) { if (i >= args.length - 1) {
System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.confignotspecified"), "-c")); System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_not_specified"), "-c"));
return; return;
} }
configFilenameOpt = args[i+1]; i++; configFilenameOpt = args[i+1]; i++;
System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.configspecified"), configFilenameOpt)); System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_specified"), configFilenameOpt));
break; break;
case "--help": case "--help":
case "-h": case "-h":
@ -106,8 +118,43 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
System.out.println(" --gui, --nogui " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.gui")); System.out.println(" --gui, --nogui " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.gui"));
return; return;
default: default:
String badArgMsg = LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised"); // We have likely added a config option argument
System.err.println(MessageFormat.format(badArgMsg, arg)); if (arg.startsWith("--")) {
// Split the argument by an =
String[] argParts = arg.substring(2).split("=");
if (argParts.length == 2) {
// Split the config key by . to allow for nested options
String[] configKeyParts = argParts[0].split("\\.");
// Loop the possible config options to check the passed key is valid
boolean found = false;
for (BeanPropertyDefinition property : availableProperties) {
if (configKeyParts[0].equals(property.getName())) {
if (configKeyParts.length > 1) {
// Loop sub-section options to check the passed key is valid
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
if (configKeyParts[1].equals(subProperty.getName())) {
found = true;
break;
}
}
} else {
found = true;
}
break;
}
}
// Add the found key to the stored list for later usage
if (found) {
argsConfigKeys.put(argParts[0], argParts[1]);
break;
}
}
}
System.err.println(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised", arg));
return; return;
} }
} }
@ -148,13 +195,21 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
try { try {
File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()));
geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class); geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class);
handleArgsConfigOptions();
if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) {
geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug
geyserConfig.getRemote().setAddress("127.0.0.1"); geyserConfig.getRemote().setAddress("127.0.0.1");
} }
} catch (IOException ex) { } catch (IOException ex) {
geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex);
System.exit(0); if (gui == null) {
System.exit(1);
} else {
// Leave the process running so the GUI is still visible
return;
}
} }
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
@ -223,4 +278,99 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
public BootstrapDumpInfo getDumpInfo() { public BootstrapDumpInfo getDumpInfo() {
return new GeyserStandaloneDumpInfo(this); return new GeyserStandaloneDumpInfo(this);
} }
/**
* Get the {@link BeanPropertyDefinition}s for the given class
*
* @param clazz The class to get the definitions for
* @return A list of {@link BeanPropertyDefinition} for the given class
*/
public static List<BeanPropertyDefinition> getPOJOForClass(Class<?> clazz) {
JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructType(clazz);
// Introspect the given type
BeanDescription beanDescription = OBJECT_MAPPER.getSerializationConfig().introspect(javaType);
// Find properties
List<BeanPropertyDefinition> properties = beanDescription.findProperties();
// Get the ignored properties
Set<String> ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector()
.findPropertyIgnorals(beanDescription.getClassInfo()).getIgnored();
// Filter properties removing the ignored ones
return properties.stream()
.filter(property -> !ignoredProperties.contains(property.getName()))
.collect(Collectors.toList());
}
/**
* Set a POJO property value on an object
*
* @param property The {@link BeanPropertyDefinition} to set
* @param parentObject The object to alter
* @param value The new value of the property
*/
private static void setConfigOption(BeanPropertyDefinition property, Object parentObject, Object value) {
Object parsedValue = value;
// Change the values type if needed
if (int.class.equals(property.getRawPrimaryType())) {
parsedValue = Integer.valueOf((String) parsedValue);
} else if (boolean.class.equals(property.getRawPrimaryType())) {
parsedValue = Boolean.valueOf((String) parsedValue);
}
// Force the value to be set
AnnotatedField field = property.getField();
field.fixAccess(true);
field.setValue(parentObject, parsedValue);
}
/**
* Update the loaded {@link GeyserStandaloneConfiguration} with any values passed in the command line arguments
*/
private void handleArgsConfigOptions() {
// Get the available properties from the class
List<BeanPropertyDefinition> availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class);
for (Map.Entry<String, String> configKey : argsConfigKeys.entrySet()) {
String[] configKeyParts = configKey.getKey().split("\\.");
// Loop over the properties looking for any matches against the stored one from the argument
for (BeanPropertyDefinition property : availableProperties) {
if (configKeyParts[0].equals(property.getName())) {
if (configKeyParts.length > 1) {
// Loop through the sub property if the first part matches
for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) {
if (configKeyParts[1].equals(subProperty.getName())) {
geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
// Set the sub property value on the config
try {
Object subConfig = property.getGetter().callOn(geyserConfig);
setConfigOption(subProperty, subConfig, configKey.getValue());
} catch (Exception e) {
geyserLogger.error("Failed to set config option: " + property.getFullName());
}
break;
}
}
} else {
geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue()));
// Set the property value on the config
try {
setConfigOption(property, geyserConfig, configKey.getValue());
} catch (Exception e) {
geyserLogger.error("Failed to set config option: " + property.getFullName());
}
}
break;
}
}
}
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -261,14 +261,30 @@ public class GeyserStandaloneGUI {
for (Map.Entry<String, GeyserCommand> command : geyserCommandManager.getCommands().entrySet()) { for (Map.Entry<String, GeyserCommand> command : geyserCommandManager.getCommands().entrySet()) {
// Remove the offhand command and any alias commands to prevent duplicates in the list // Remove the offhand command and any alias commands to prevent duplicates in the list
if ("offhand".equals(command.getValue().getName()) || command.getValue().getAliases().contains(command.getKey())) { if (!command.getValue().isExecutableOnConsole() || command.getValue().getAliases().contains(command.getKey())) {
continue; continue;
} }
// Create the button that runs the command // Create the button that runs the command
JMenuItem commandButton = new JMenuItem(command.getValue().getName()); boolean hasSubCommands = command.getValue().hasSubCommands();
// Add an extra menu if there are more commands that can be run
JMenuItem commandButton = hasSubCommands ? new JMenu(command.getValue().getName()) : new JMenuItem(command.getValue().getName());
commandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription()); commandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription());
commandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ })); if (!hasSubCommands) {
commandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ }));
} else {
// Add a submenu that's the same name as the menu can't be pressed
JMenuItem otherCommandButton = new JMenuItem(command.getValue().getName());
otherCommandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription());
otherCommandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ }));
commandButton.add(otherCommandButton);
// Add a menu option for all possible subcommands
for (String subCommandName : command.getValue().getSubCommands()) {
JMenuItem item = new JMenuItem(subCommandName);
item.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{subCommandName}));
commandButton.add(item);
}
}
commandsMenu.add(commandButton); commandsMenu.add(commandButton);
} }
@ -291,7 +307,7 @@ public class GeyserStandaloneGUI {
playerTableModel.getDataVector().removeAllElements(); playerTableModel.getDataVector().removeAllElements();
for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) { for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) {
Vector row = new Vector(); Vector<String> row = new Vector<>();
row.add(player.getSocketAddress().getHostName()); row.add(player.getSocketAddress().getHostName());
row.add(player.getPlayerEntity().getUsername()); row.add(player.getPlayerEntity().getUsername());

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -6,21 +6,21 @@
<parent> <parent>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>bootstrap-parent</artifactId> <artifactId>bootstrap-parent</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<artifactId>bootstrap-velocity</artifactId> <artifactId>bootstrap-velocity</artifactId>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>connector</artifactId> <artifactId>connector</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.velocitypowered</groupId> <groupId>com.velocitypowered</groupId>
<artifactId>velocity-api</artifactId> <artifactId>velocity-api</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>1.1.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@ -82,8 +82,8 @@
<shadedPattern>org.geysermc.platform.velocity.shaded.dom4j</shadedPattern> <shadedPattern>org.geysermc.platform.velocity.shaded.dom4j</shadedPattern>
</relocation> </relocation>
<relocation> <relocation>
<pattern>net.kyori.adventure</pattern> <pattern>net.kyori</pattern>
<shadedPattern>org.geysermc.platform.velocity.shaded.adventure</shadedPattern> <shadedPattern>org.geysermc.platform.velocity.shaded.kyori</shadedPattern>
</relocation> </relocation>
</relocations> </relocations>
</configuration> </configuration>
@ -93,7 +93,16 @@
<artifactSet> <artifactSet>
<excludes> <excludes>
<exclude>com.google.code.gson:*</exclude> <exclude>com.google.code.gson:*</exclude>
<exclude>io.netty:*</exclude> <!-- Needed because Velocity provides every dependency except netty-resolver-dns -->
<exclude>io.netty:netty-transport-native-epoll:*</exclude>
<exclude>io.netty:netty-transport-native-unix-common:*</exclude>
<exclude>io.netty:netty-transport-native-kqueue:*</exclude>
<exclude>io.netty:netty-handler:*</exclude>
<exclude>io.netty:netty-common:*</exclude>
<exclude>io.netty:netty-buffer:*</exclude>
<exclude>io.netty:netty-resolver:*</exclude>
<exclude>io.netty:netty-transport:*</exclude>
<exclude>io.netty:netty-codec:*</exclude>
<exclude>org.slf4j:*</exclude> <exclude>org.slf4j:*</exclude>
<exclude>org.ow2.asm:*</exclude> <exclude>org.ow2.asm:*</exclude>
</excludes> </excludes>

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -43,15 +43,13 @@ import java.util.concurrent.ExecutionException;
@AllArgsConstructor @AllArgsConstructor
public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough { public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
private static final GeyserInboundConnection FAKE_INBOUND_CONNECTION = new GeyserInboundConnection();
private final ProxyServer server; private final ProxyServer server;
@Override @Override
public GeyserPingInfo getPingInformation() { public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) {
ProxyPingEvent event; ProxyPingEvent event;
try { try {
event = server.getEventManager().fire(new ProxyPingEvent(FAKE_INBOUND_CONNECTION, ServerPing.builder() event = server.getEventManager().fire(new ProxyPingEvent(new GeyserInboundConnection(inetSocketAddress), ServerPing.builder()
.description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount()) .description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount())
.maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get(); .maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get();
} catch (ExecutionException | InterruptedException e) { } catch (ExecutionException | InterruptedException e) {
@ -74,11 +72,15 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
private static class GeyserInboundConnection implements InboundConnection { private static class GeyserInboundConnection implements InboundConnection {
private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69); private final InetSocketAddress remote;
public GeyserInboundConnection(InetSocketAddress remote) {
this.remote = remote;
}
@Override @Override
public InetSocketAddress getRemoteAddress() { public InetSocketAddress getRemoteAddress() {
return FAKE_REMOTE; return this.remote;
} }
@Override @Override

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -33,9 +33,9 @@ import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.Plugin; import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import lombok.Getter; import lombok.Getter;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.common.PlatformType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.dump.BootstrapDumpInfo;
import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough;
@ -121,7 +121,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
this.connector = GeyserConnector.start(PlatformType.VELOCITY, this); this.connector = GeyserConnector.start(PlatformType.VELOCITY, this);
this.geyserCommandManager = new GeyserVelocityCommandManager(connector); this.geyserCommandManager = new GeyserVelocityCommandManager(connector);
this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser"); this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(connector));
if (geyserConfig.isLegacyPingPassthrough()) { if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector);
} else { } else {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -25,41 +25,48 @@
package org.geysermc.platform.velocity.command; package org.geysermc.platform.velocity.command;
import com.velocitypowered.api.command.Command;
import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import net.kyori.text.TextComponent;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
@AllArgsConstructor @AllArgsConstructor
public class GeyserVelocityCommandExecutor implements Command { public class GeyserVelocityCommandExecutor implements SimpleCommand {
private GeyserConnector connector; private final GeyserConnector connector;
@Override @Override
public void execute(CommandSource source, String[] args) { public void execute(Invocation invocation) {
if (args.length > 0) { if (invocation.arguments().length > 0) {
if (getCommand(args[0]) != null) { if (getCommand(invocation.arguments()[0]) != null) {
if (!source.hasPermission(getCommand(args[0]).getPermission())) { if (!invocation.source().hasPermission(getCommand(invocation.arguments()[0]).getPermission())) {
// Not ideal to use log here but we dont get a session CommandSender sender = new VelocityCommandSender(invocation.source());
source.sendMessage(TextComponent.of(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail"))); sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale()));
return; return;
} }
getCommand(args[0]).execute(new VelocityCommandSender(source), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); getCommand(invocation.arguments()[0]).execute(new VelocityCommandSender(invocation.source()), invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]);
} }
} else { } else {
getCommand("help").execute(new VelocityCommandSender(source), new String[0]); getCommand("help").execute(new VelocityCommandSender(invocation.source()), new String[0]);
} }
} }
@Override
public List<String> suggest(Invocation invocation) {
if (invocation.arguments().length == 0) {
return connector.getCommandManager().getCommandNames();
}
return new ArrayList<>();
}
private GeyserCommand getCommand(String label) { private GeyserCommand getCommand(String label) {
return connector.getCommandManager().getCommands().get(label); return connector.getCommandManager().getCommands().get(label);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -28,17 +28,21 @@ package org.geysermc.platform.velocity.command;
import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.api.proxy.ConsoleCommandSource;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import lombok.AllArgsConstructor;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.utils.LanguageUtils;
import java.util.Locale;
@AllArgsConstructor
public class VelocityCommandSender implements CommandSender { public class VelocityCommandSender implements CommandSender {
private CommandSource handle; private final CommandSource handle;
public VelocityCommandSender(CommandSource handle) {
this.handle = handle;
// Ensure even Java players' languages are loaded
LanguageUtils.loadGeyserLocale(getLocale());
}
@Override @Override
public String getName() { public String getName() {
@ -59,4 +63,13 @@ public class VelocityCommandSender implements CommandSender {
public boolean isConsole() { public boolean isConsole() {
return handle instanceof ConsoleCommandSource; return handle instanceof ConsoleCommandSource;
} }
@Override
public String getLocale() {
if (handle instanceof Player) {
Locale locale = ((Player) handle).getPlayerSettings().getLocale();
return LanguageUtils.formatLocale(locale.getLanguage() + "_" + locale.getCountry());
}
return LanguageUtils.getDefaultLocale();
}
} }

View file

@ -6,11 +6,10 @@
<parent> <parent>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>geyser-parent</artifactId> <artifactId>geyser-parent</artifactId>
<version>parent</version> <version>1.2.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<artifactId>common</artifactId> <artifactId>common</artifactId>
<version>1.1.0</version>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser * @link https://github.com/GeyserMC/Geyser
*/ */
package org.geysermc.connector.common; package org.geysermc.common;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -92,7 +92,7 @@ public class CustomFormWindow extends FormWindow {
} }
public void setResponse(String data) { public void setResponse(String data) {
if (data == null || data.equalsIgnoreCase("null") || data.isEmpty()) { if (data == null || data.trim().equalsIgnoreCase("null") || data.isEmpty()) {
closed = true; closed = true;
return; return;
} }
@ -108,7 +108,7 @@ public class CustomFormWindow extends FormWindow {
List<String> componentResponses = new ArrayList<>(); List<String> componentResponses = new ArrayList<>();
try { try {
componentResponses = new ObjectMapper().readValue(data, new TypeReference<List<String>>(){}); componentResponses = new ObjectMapper().readValue(data.trim(), new TypeReference<List<String>>(){});
} catch (IOException e) { } } catch (IOException e) { }
for (String response : componentResponses) { for (String response : componentResponses) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -72,14 +72,14 @@ public class SimpleFormWindow extends FormWindow {
} }
public void setResponse(String data) { public void setResponse(String data) {
if (data == null || data.equalsIgnoreCase("null")) { if (data == null || data.trim().equalsIgnoreCase("null")) {
closed = true; closed = true;
return; return;
} }
int buttonID; int buttonID;
try { try {
buttonID = Integer.parseInt(data); buttonID = Integer.parseInt(data.trim());
} catch (Exception ex) { } catch (Exception ex) {
return; return;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -6,16 +6,15 @@
<parent> <parent>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>geyser-parent</artifactId> <artifactId>geyser-parent</artifactId>
<version>parent</version> <version>1.2.0-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent> </parent>
<artifactId>connector</artifactId> <artifactId>connector</artifactId>
<version>1.1.0</version>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.geysermc</groupId> <groupId>org.geysermc</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
<version>1.1.0</version> <version>1.2.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -32,16 +31,27 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.CloudburstMC.Protocol</groupId> <groupId>com.github.CloudburstMC.Protocol</groupId>
<artifactId>bedrock-v408</artifactId> <artifactId>bedrock-v422</artifactId>
<version>02f46a8700</version> <version>d41b84e86c</version>
<scope>compile</scope> <scope>compile</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>net.sf.trove4j</groupId> <groupId>net.sf.trove4j</groupId>
<artifactId>trove</artifactId> <artifactId>trove</artifactId>
</exclusion> </exclusion>
<!-- Stay on the older version of Network while it's rewritten -->
<exclusion>
<groupId>com.nukkitx.network</groupId>
<artifactId>raknet</artifactId>
</exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency>
<groupId>com.nukkitx.network</groupId>
<artifactId>raknet</artifactId>
<version>1.6.20</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>com.nukkitx.fastutil</groupId> <groupId>com.nukkitx.fastutil</groupId>
<artifactId>fastutil-int-int-maps</artifactId> <artifactId>fastutil-int-int-maps</artifactId>
@ -111,10 +121,30 @@
<dependency> <dependency>
<groupId>com.github.steveice10</groupId> <groupId>com.github.steveice10</groupId>
<artifactId>mcprotocollib</artifactId> <artifactId>mcprotocollib</artifactId>
<version>1b01b1ffef</version> <version>26201a4</version>
<scope>compile</scope> <scope>compile</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-gson</artifactId>
</exclusion>
<exclusion>
<groupId>com.github.steveice10</groupId>
<artifactId>packetlib</artifactId>
</exclusion>
<exclusion>
<groupId>com.github.steveice10</groupId>
<artifactId>mcauthlib</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.steveice10</groupId>
<artifactId>PacketLib</artifactId>
<version>54f761c</version>
<scope>compile</scope>
<exclusions>
<exclusion> <!-- Move this exclusion back to MCProtocolLib it gets the latest PacketLib -->
<groupId>io.netty</groupId> <groupId>io.netty</groupId>
<artifactId>netty-all</artifactId> <artifactId>netty-all</artifactId>
</exclusion> </exclusion>
@ -126,6 +156,12 @@
<version>4.1.43.Final</version> <version>4.1.43.Final</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-haproxy</artifactId>
<version>4.1.56.Final</version>
<scope>compile</scope>
</dependency>
<dependency> <dependency>
<groupId>org.reflections</groupId> <groupId>org.reflections</groupId>
<artifactId>reflections</artifactId> <artifactId>reflections</artifactId>
@ -139,21 +175,38 @@
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId> <artifactId>adventure-api</artifactId>
<version>4.1.1</version> <version>4.3.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-gson</artifactId> <artifactId>adventure-text-serializer-gson</artifactId>
<version>4.1.1</version> <version>4.3.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-legacy</artifactId> <artifactId>adventure-text-serializer-legacy</artifactId>
<version>4.1.1</version> <version>4.3.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-gson-legacy-impl</artifactId>
<version>4.3.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.GeyserMC</groupId>
<artifactId>MCAuthLib</artifactId>
<version>0e48a094f2</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
@ -210,8 +263,12 @@
</includes> </includes>
<replacements> <replacements>
<replacement> <replacement>
<token>VERSION = ".*"</token> <token>String VERSION = ".*"</token>
<value>VERSION = "${project.version} (git-${git.branch}-${git.commit.id.abbrev})"</value> <value>String VERSION = "${project.version} (" + GIT_VERSION + ")"</value>
</replacement>
<replacement>
<token>String GIT_VERSION = ".*"</token>
<value>String GIT_VERSION = "git-${git.branch}-${git.commit.id.abbrev}"</value>
</replacement> </replacement>
</replacements> </replacements>
</configuration> </configuration>
@ -229,8 +286,12 @@
</includes> </includes>
<replacements> <replacements>
<replacement> <replacement>
<token>VERSION = ".*"</token> <token>String VERSION = ".*"</token>
<value>VERSION = "DEV"</value> <value>String VERSION = "DEV"</value>
</replacement>
<replacement>
<token>String GIT_VERSION = ".*"</token>
<value>String GIT_VERSION = "DEV"</value>
</replacement> </replacement>
</replacements> </replacements>
</configuration> </configuration>
@ -252,6 +313,8 @@
<script><![CDATA[ <script><![CDATA[
new org.reflections.Reflections("org.geysermc.connector.network.translators") new org.reflections.Reflections("org.geysermc.connector.network.translators")
.save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators-reflections.xml") .save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators-reflections.xml")
new org.reflections.Reflections("org.geysermc.connector.network.translators.collision.translators")
.save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators.collision.translators-reflections.xml")
new org.reflections.Reflections("org.geysermc.connector.network.translators.item") new org.reflections.Reflections("org.geysermc.connector.network.translators.item")
.save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators.item-reflections.xml") .save("${project.artifactId}/target/classes/META-INF/reflections/org.geysermc.connector.network.translators.item-reflections.xml")
new org.reflections.Reflections("org.geysermc.connector.network.translators.sound") new org.reflections.Reflections("org.geysermc.connector.network.translators.sound")
@ -283,6 +346,15 @@
</dependency> </dependency>
</dependencies> </dependencies>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<!-- Force the right file encoding during unit testing -->
<argLine>-Dfile.encoding=${project.build.sourceEncoding}</argLine>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -32,10 +32,10 @@ import com.nukkitx.network.raknet.RakNetConstants;
import com.nukkitx.protocol.bedrock.BedrockServer; import com.nukkitx.protocol.bedrock.BedrockServer;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.geysermc.common.PlatformType;
import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.bootstrap.GeyserBootstrap;
import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.command.CommandManager;
import org.geysermc.connector.common.AuthType; import org.geysermc.connector.common.AuthType;
import org.geysermc.connector.common.PlatformType;
import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.configuration.GeyserConfiguration;
import org.geysermc.connector.metrics.Metrics; import org.geysermc.connector.metrics.Metrics;
import org.geysermc.connector.network.ConnectorServerEventHandler; import org.geysermc.connector.network.ConnectorServerEventHandler;
@ -44,6 +44,7 @@ import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.translators.BiomeTranslator; import org.geysermc.connector.network.translators.BiomeTranslator;
import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.EntityIdentifierRegistry;
import org.geysermc.connector.network.translators.PacketTranslatorRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry;
import org.geysermc.connector.network.translators.collision.CollisionTranslator;
import org.geysermc.connector.network.translators.effect.EffectRegistry; import org.geysermc.connector.network.translators.effect.EffectRegistry;
import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemRegistry;
import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator;
@ -54,6 +55,7 @@ import org.geysermc.connector.network.translators.sound.SoundRegistry;
import org.geysermc.connector.network.translators.world.WorldManager; import org.geysermc.connector.network.translators.world.WorldManager;
import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator;
import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator;
import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator;
import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.DimensionUtils;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
import org.geysermc.connector.utils.LocaleUtils; import org.geysermc.connector.utils.LocaleUtils;
@ -65,10 +67,7 @@ import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
@ -77,11 +76,21 @@ import java.util.concurrent.TimeUnit;
@Getter @Getter
public class GeyserConnector { public class GeyserConnector {
public static final ObjectMapper JSON_MAPPER = new ObjectMapper().enable(JsonParser.Feature.IGNORE_UNDEFINED).enable(JsonParser.Feature.ALLOW_COMMENTS).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); public static final ObjectMapper JSON_MAPPER = new ObjectMapper()
.enable(JsonParser.Feature.IGNORE_UNDEFINED)
.enable(JsonParser.Feature.ALLOW_COMMENTS)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
public static final String NAME = "Geyser"; public static final String NAME = "Geyser";
public static final String GIT_VERSION = "DEV"; // A fallback for running in IDEs
public static final String VERSION = "DEV"; // A fallback for running in IDEs public static final String VERSION = "DEV"; // A fallback for running in IDEs
/**
* Oauth client ID for Microsoft authentication
*/
public static final String OAUTH_CLIENT_ID = "204cefd1-4818-4de1-b98d-513fae875d88";
private static final String IP_REGEX = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"; private static final String IP_REGEX = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b";
private final List<GeyserSession> players = new ArrayList<>(); private final List<GeyserSession> players = new ArrayList<>();
@ -97,8 +106,8 @@ public class GeyserConnector {
private final ScheduledExecutorService generalThreadPool; private final ScheduledExecutorService generalThreadPool;
private BedrockServer bedrockServer; private BedrockServer bedrockServer;
private PlatformType platformType; private final PlatformType platformType;
private GeyserBootstrap bootstrap; private final GeyserBootstrap bootstrap;
private Metrics metrics; private Metrics metrics;
@ -134,6 +143,7 @@ public class GeyserConnector {
EntityIdentifierRegistry.init(); EntityIdentifierRegistry.init();
ItemRegistry.init(); ItemRegistry.init();
ItemTranslator.init(); ItemTranslator.init();
CollisionTranslator.init();
LocaleUtils.init(); LocaleUtils.init();
PotionMixRegistry.init(); PotionMixRegistry.init();
RecipeRegistry.init(); RecipeRegistry.init();
@ -179,8 +189,8 @@ public class GeyserConnector {
remoteServer = new RemoteServer(config.getRemote().getAddress(), remotePort); remoteServer = new RemoteServer(config.getRemote().getAddress(), remotePort);
authType = AuthType.getByName(config.getRemote().getAuthType()); authType = AuthType.getByName(config.getRemote().getAuthType());
if (config.isAboveBedrockNetherBuilding()) DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether
DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether SkullBlockEntityTranslator.ALLOW_CUSTOM_SKULLS = config.isAllowCustomSkulls();
// https://github.com/GeyserMC/Geyser/issues/957 // https://github.com/GeyserMC/Geyser/issues/957
RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu(); RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu();
@ -199,7 +209,6 @@ public class GeyserConnector {
if (config.getMetrics().isEnabled()) { if (config.getMetrics().isEnabled()) {
metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger("")); metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger(""));
metrics.addCustomChart(new Metrics.SingleLineChart("servers", () -> 1));
metrics.addCustomChart(new Metrics.SingleLineChart("players", players::size)); metrics.addCustomChart(new Metrics.SingleLineChart("players", players::size));
// Prevent unwanted words best we can // Prevent unwanted words best we can
metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> AuthType.getByName(config.getRemote().getAuthType()).toString().toLowerCase())); metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> AuthType.getByName(config.getRemote().getAuthType()).toString().toLowerCase()));
@ -255,7 +264,7 @@ public class GeyserConnector {
message += LanguageUtils.getLocaleStringLog("geyser.core.finish.console"); message += LanguageUtils.getLocaleStringLog("geyser.core.finish.console");
} }
logger.info(message); logger.info(message);
if (platformType == PlatformType.STANDALONE) { if (platformType == PlatformType.STANDALONE) {
logger.warning(LanguageUtils.getLocaleStringLog("geyser.core.movement_warn")); logger.warning(LanguageUtils.getLocaleStringLog("geyser.core.movement_warn"));
} }
@ -271,7 +280,7 @@ public class GeyserConnector {
// Make a copy to prevent ConcurrentModificationException // Make a copy to prevent ConcurrentModificationException
final List<GeyserSession> tmpPlayers = new ArrayList<>(players); final List<GeyserSession> tmpPlayers = new ArrayList<>(players);
for (GeyserSession playerSession : tmpPlayers) { for (GeyserSession playerSession : tmpPlayers) {
playerSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.core.shutdown.kick.message", playerSession.getClientData().getLanguageCode())); playerSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.core.shutdown.kick.message", playerSession.getLocale()));
} }
CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() { CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
@ -319,6 +328,38 @@ public class GeyserConnector {
players.remove(player); players.remove(player);
} }
/**
* Gets a player by their current UUID
*
* @param uuid the uuid
* @return the player or <code>null</code> if there is no player online with this UUID
*/
public GeyserSession getPlayerByUuid(UUID uuid) {
for (GeyserSession session : players) {
if (session.getPlayerEntity().getUuid().equals(uuid)) {
return session;
}
}
return null;
}
/**
* Gets a player by their Xbox user identifier
*
* @param xuid the Xbox user identifier
* @return the player or <code>null</code> if there is no player online with this xuid
*/
public GeyserSession getPlayerByXuid(String xuid) {
for (GeyserSession session : players) {
if (session.getAuthData() != null && session.getAuthData().getXboxUUID().equals(xuid)) {
return session;
}
}
return null;
}
public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) { public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) {
return new GeyserConnector(platformType, bootstrap); return new GeyserConnector(platformType, bootstrap);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -31,27 +31,28 @@ import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.defaults.*; import org.geysermc.connector.command.defaults.*;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
import java.util.Collections; import java.util.*;
import java.util.HashMap;
import java.util.Map;
public abstract class CommandManager { public abstract class CommandManager {
@Getter @Getter
private final Map<String, GeyserCommand> commands = Collections.synchronizedMap(new HashMap<>()); private final Map<String, GeyserCommand> commands = Collections.synchronizedMap(new HashMap<>());
private GeyserConnector connector; private final GeyserConnector connector;
public CommandManager(GeyserConnector connector) { public CommandManager(GeyserConnector connector) {
this.connector = connector; this.connector = connector;
registerCommand(new HelpCommand(connector, "help", LanguageUtils.getLocaleStringLog("geyser.commands.help.desc"), "geyser.command.help")); registerCommand(new HelpCommand(connector, "help", "geyser.commands.help.desc", "geyser.command.help"));
registerCommand(new ListCommand(connector, "list", LanguageUtils.getLocaleStringLog("geyser.commands.list.desc"), "geyser.command.list")); registerCommand(new ListCommand(connector, "list", "geyser.commands.list.desc", "geyser.command.list"));
registerCommand(new ReloadCommand(connector, "reload", LanguageUtils.getLocaleStringLog("geyser.commands.reload.desc"), "geyser.command.reload")); registerCommand(new ReloadCommand(connector, "reload", "geyser.commands.reload.desc", "geyser.command.reload"));
registerCommand(new StopCommand(connector, "stop", LanguageUtils.getLocaleStringLog("geyser.commands.stop.desc"), "geyser.command.stop")); registerCommand(new StopCommand(connector, "stop", "geyser.commands.stop.desc", "geyser.command.stop"));
registerCommand(new OffhandCommand(connector, "offhand", LanguageUtils.getLocaleStringLog("geyser.commands.offhand.desc"), "geyser.command.offhand")); registerCommand(new OffhandCommand(connector, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand"));
registerCommand(new DumpCommand(connector, "dump", LanguageUtils.getLocaleStringLog("geyser.commands.dump.desc"), "geyser.command.dump")); registerCommand(new DumpCommand(connector, "dump", "geyser.commands.dump.desc", "geyser.command.dump"));
registerCommand(new VersionCommand(connector, "version", LanguageUtils.getLocaleStringLog("geyser.commands.version.desc"), "geyser.command.version")); registerCommand(new VersionCommand(connector, "version", "geyser.commands.version.desc", "geyser.command.version"));
registerCommand(new SettingsCommand(connector, "settings", "geyser.commands.settings.desc", "geyser.command.settings"));
registerCommand(new StatisticsCommand(connector, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics"));
registerCommand(new AdvancementsCommand(connector, "advancements", "geyser.commands.advancements.desc", "geyser.command.advancements"));
} }
public void registerCommand(GeyserCommand command) { public void registerCommand(GeyserCommand command) {
@ -91,6 +92,13 @@ public abstract class CommandManager {
cmd.execute(sender, args); cmd.execute(sender, args);
} }
/**
* @return a list of all subcommands under {@code /geyser}.
*/
public List<String> getCommandNames() {
return Arrays.asList(connector.getCommandManager().getCommands().keySet().toArray(new String[0]));
}
/** /**
* Returns the description of the given command * Returns the description of the given command
* *

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -25,6 +25,12 @@
package org.geysermc.connector.command; package org.geysermc.connector.command;
import org.geysermc.connector.utils.LanguageUtils;
/**
* Implemented on top of any class that can send a command.
* For example, it wraps around Spigot's CommandSender class.
*/
public interface CommandSender { public interface CommandSender {
String getName(); String getName();
@ -37,5 +43,17 @@ public interface CommandSender {
void sendMessage(String message); void sendMessage(String message);
/**
* @return true if the specified sender is from the console.
*/
boolean isConsole(); boolean isConsole();
/**
* Returns the locale of the command sender. Defaults to the default locale at {@link LanguageUtils#getDefaultLocale()}.
*
* @return the locale of the command sender.
*/
default String getLocale() {
return LanguageUtils.getDefaultLocale();
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -30,6 +30,7 @@ import lombok.RequiredArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
@Getter @Getter
@ -37,6 +38,9 @@ import java.util.List;
public abstract class GeyserCommand { public abstract class GeyserCommand {
protected final String name; protected final String name;
/**
* The description of the command - will attempt to be translated.
*/
protected final String description; protected final String description;
protected final String permission; protected final String permission;
@ -44,4 +48,31 @@ public abstract class GeyserCommand {
private List<String> aliases = new ArrayList<>(); private List<String> aliases = new ArrayList<>();
public abstract void execute(CommandSender sender, String[] args); public abstract void execute(CommandSender sender, String[] args);
/**
* If false, hides the command from being shown on the Geyser Standalone GUI.
*
* @return true if the command can be run on the server console
*/
public boolean isExecutableOnConsole() {
return true;
}
/**
* Used in the GUI to know what subcommands can be run
*
* @return a list of all possible subcommands, or empty if none.
*/
public List<String> getSubCommands() {
return Collections.emptyList();
}
/**
* Shortcut to {@link #getSubCommands()}{@code .isEmpty()}.
*
* @return true if there are subcommand present for this command.
*/
public boolean hasSubCommands() {
return !getSubCommands().isEmpty();
}
} }

View file

@ -0,0 +1,74 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.connector.command.defaults;
import org.geysermc.common.window.SimpleFormWindow;
import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.connector.network.session.cache.AdvancementsCache;
public class AdvancementsCommand extends GeyserCommand {
private final GeyserConnector connector;
public AdvancementsCommand(GeyserConnector connector, String name, String description, String permission) {
super(name, description, permission);
this.connector = connector;
}
@Override
public void execute(CommandSender sender, String[] args) {
if (sender.isConsole()) {
return;
}
// Make sure the sender is a Bedrock edition client
GeyserSession session = null;
if (sender instanceof GeyserSession) {
session = (GeyserSession) sender;
} else {
// Needed for Spigot - sender is not an instance of GeyserSession
for (GeyserSession otherSession : connector.getPlayers()) {
if (sender.getName().equals(otherSession.getPlayerEntity().getUsername())) {
session = otherSession;
break;
}
}
}
if (session == null) return;
SimpleFormWindow window = session.getAdvancementsCache().buildMenuForm();
session.sendForm(window, AdvancementsCache.ADVANCEMENTS_MENU_FORM_ID);
}
@Override
public boolean isExecutableOnConsole() {
return false;
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -27,12 +27,10 @@ package org.geysermc.connector.command.defaults;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.common.serializer.AsteriskSerializer; import org.geysermc.connector.common.serializer.AsteriskSerializer;
import org.geysermc.connector.dump.DumpInfo; import org.geysermc.connector.dump.DumpInfo;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
@ -40,6 +38,8 @@ import org.geysermc.connector.utils.WebUtils;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class DumpCommand extends GeyserCommand { public class DumpCommand extends GeyserCommand {
@ -73,7 +73,7 @@ public class DumpCommand extends GeyserCommand {
AsteriskSerializer.showSensitive = showSensitive; AsteriskSerializer.showSensitive = showSensitive;
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collecting")); sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collecting", sender.getLocale()));
String dumpData = ""; String dumpData = "";
try { try {
if (offlineDump) { if (offlineDump) {
@ -82,7 +82,7 @@ public class DumpCommand extends GeyserCommand {
dumpData = MAPPER.writeValueAsString(new DumpInfo()); dumpData = MAPPER.writeValueAsString(new DumpInfo());
} }
} catch (IOException e) { } catch (IOException e) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error")); sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.getLocale()));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e); connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e);
return; return;
} }
@ -90,21 +90,21 @@ public class DumpCommand extends GeyserCommand {
String uploadedDumpUrl = ""; String uploadedDumpUrl = "";
if (offlineDump) { if (offlineDump) {
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.writing")); sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.writing", sender.getLocale()));
try { try {
FileOutputStream outputStream = new FileOutputStream(GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile()); FileOutputStream outputStream = new FileOutputStream(GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile());
outputStream.write(dumpData.getBytes()); outputStream.write(dumpData.getBytes());
outputStream.close(); outputStream.close();
} catch (IOException e) { } catch (IOException e) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error")); sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.write_error", sender.getLocale()));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error_short"), e); connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error_short"), e);
return; return;
} }
uploadedDumpUrl = "dump.json"; uploadedDumpUrl = "dump.json";
} else { } else {
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.uploading")); sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.uploading", sender.getLocale()));
String response; String response;
JsonNode responseNode; JsonNode responseNode;
@ -112,22 +112,27 @@ public class DumpCommand extends GeyserCommand {
response = WebUtils.post(DUMP_URL + "documents", dumpData); response = WebUtils.post(DUMP_URL + "documents", dumpData);
responseNode = MAPPER.readTree(response); responseNode = MAPPER.readTree(response);
} catch (IOException e) { } catch (IOException e) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error")); sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.upload_error", sender.getLocale()));
connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e); connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e);
return; return;
} }
if (!responseNode.has("key")) { if (!responseNode.has("key")) {
sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short") + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response)); sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.getLocale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
return; return;
} }
uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText(); uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
} }
sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.message") + " " + ChatColor.DARK_AQUA + uploadedDumpUrl); sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.message", sender.getLocale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl);
if (!sender.isConsole()) { if (!sender.isConsole()) {
connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.commands.dump.created", sender.getName(), uploadedDumpUrl)); connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.commands.dump.created", sender.getName(), uploadedDumpUrl));
} }
} }
@Override
public List<String> getSubCommands() {
return Arrays.asList("offline", "full");
}
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -25,11 +25,10 @@
package org.geysermc.connector.command.defaults; package org.geysermc.connector.command.defaults;
import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.GeyserConnector;
import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.CommandSender;
import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.command.GeyserCommand;
import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.common.ChatColor;
import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.connector.utils.LanguageUtils;
import java.util.Collections; import java.util.Collections;
@ -52,17 +51,12 @@ public class HelpCommand extends GeyserCommand {
public void execute(CommandSender sender, String[] args) { public void execute(CommandSender sender, String[] args) {
int page = 1; int page = 1;
int maxPage = 1; int maxPage = 1;
String header = ""; String header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", sender.getLocale(), page, maxPage);
if (sender instanceof GeyserSession) {
header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", ((GeyserSession) sender).getClientData().getLanguageCode(), page, maxPage);
} else {
header = LanguageUtils.getLocaleStringLog("geyser.commands.help.header", page, maxPage);
}
sender.sendMessage(header); sender.sendMessage(header);
Map<String, GeyserCommand> cmds = connector.getCommandManager().getCommands(); Map<String, GeyserCommand> cmds = connector.getCommandManager().getCommands();
List<String> commands = connector.getCommandManager().getCommands().keySet().stream().sorted().collect(Collectors.toList()); List<String> commands = connector.getCommandManager().getCommands().keySet().stream().sorted().collect(Collectors.toList());
commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " + cmds.get(cmd).getDescription())); commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " +
LanguageUtils.getPlayerLocaleString(cmds.get(cmd).getDescription(), sender.getLocale())));
} }
} }

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