Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 16:12:46 +01:00
Merge branch 'master' of https://github.com/GeyserMC/Geyser into floodgate-2.0
Dieser Commit ist enthalten in:
Commit
404419df08
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,5 +1,5 @@
|
|||||||
name: Bug report
|
name: Bug report
|
||||||
about: Create a report to help us improve
|
description: Create a report to help us improve
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
@ -41,11 +41,11 @@ body:
|
|||||||
If you're running a multi-server instance or using Geyser Standalone:
|
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.
|
* 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.
|
* Please list all plugins on all servers involved.
|
||||||
If this bug occurs on a server you do not control, please full this in to the best of your knowledge.
|
If this bug occurs on a server you do not control, please fill this in to the best of your knowledge.
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Geyser Dump
|
label: Geyser Dump
|
||||||
description: If Geyser starts correctly, please also include the link to a dump by using `/geyser dump`. If you're using 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.
|
description: If Geyser starts correctly, please include the link to a dump using `/geyser dump`. If you're using the Standalone GUI, you can find the option under `Commands` => `Dump`. Doing this provides us information about your server that we can use to debug your issue.
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Geyser Version
|
label: Geyser Version
|
||||||
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -5,7 +5,7 @@ contact_links:
|
|||||||
about: Check the common issues to see if you are not alone with that issue and see how you can fix them.
|
about: Check the common issues to see if you are not alone with that issue and see how you can fix them.
|
||||||
- name: Frequently Asked Questions
|
- name: Frequently Asked Questions
|
||||||
url: https://github.com/GeyserMC/Geyser/wiki/FAQ
|
url: https://github.com/GeyserMC/Geyser/wiki/FAQ
|
||||||
about: Look at the FAQ page for answers for frequently asked questions.
|
about: Look at the FAQ page for answers to frequently asked questions.
|
||||||
- name: Get help on the GeyserMC Discord server
|
- name: Get help on the GeyserMC Discord server
|
||||||
url: https://discord.gg/geysermc
|
url: https://discord.gg/geysermc
|
||||||
about: If your issue seems like it could possibly be an easy fix due to configuration, please hop on our Discord.
|
about: If your issue seems like it could possibly be an easy fix due to configuration, please hop on our Discord.
|
||||||
|
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
4
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -1,11 +1,11 @@
|
|||||||
name: Feature request
|
name: Feature request
|
||||||
about: Suggest an idea for this project
|
description: Suggest an idea for this project
|
||||||
labels: "Feature Request"
|
labels: "Feature Request"
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thanks for taking the time to fill out this feature request for Geyser! Fill out the following form to your best ability to help us understand your feature request and greately improve the change of it getting added.
|
Thanks for taking the time to fill out this feature request for Geyser! Please fill out the following form to your best ability to help us understand your feature request and significantly improve the chance of getting added.
|
||||||
For anything else than a feature request, use: [our Discord server](https://discord.gg/geysermc), [the FAQ](https://github.com/GeyserMC/Geyser/wiki/FAQ) or [the Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues).
|
For anything else than a feature request, use: [our Discord server](https://discord.gg/geysermc), [the FAQ](https://github.com/GeyserMC/Geyser/wiki/FAQ) or [the Common Issues](https://github.com/GeyserMC/Geyser/wiki/Common-Issues).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
Thank for for considering a contribution! Generally, Geyser welcomes PRs from everyone. There are some guidelines about what features should go where:
|
Thank you for considering a contribution! Generally, Geyser welcomes PRs from everyone. There are some guidelines about what features should go where:
|
||||||
|
|
||||||
|
|
||||||
*Pull requests that may not get accepted:* Niche features that apply to a specific group, for example integration with a specific plugin. For now, please create a separate plugin if possible.
|
*Pull requests that may not get accepted:* Niche features that apply to a specific group, for example, integration with a specific plugin. For now, please create a separate plugin if possible.
|
||||||
|
|
||||||
*Pull requests for Floodgate:* Anything that opens up information within the game for developers to use.
|
*Pull requests for Floodgate:* Anything that opens up information within the game for developers to use.
|
||||||
|
|
||||||
*Pull requests for Geyser:* Anything that fixes compatibility between Java or Bedrock, or improves the quality of play for Bedrock players. The exception is wherever direct server access is required; in this case it may be better for Floodgate.
|
*Pull requests for Geyser:* Anything that fixes compatibility between Java or Bedrock or improves the quality of play for Bedrock players. The exception is wherever direct server access is required; in this case, it may be better for Floodgate.
|
||||||
|
|
||||||
|
|
||||||
We have some general style guides that should be applied throughout the code:
|
We have some general style guides that should be applied throughout the code:
|
||||||
@ -48,4 +48,4 @@ Make sure to comment your code where possible.
|
|||||||
|
|
||||||
The nature of our software requires a lot of arrays and maps to be stored - where possible, use Fastutil's specialized maps. For example, if you're storing block state translations, use an `Int2IntMap`.
|
The nature of our software requires a lot of arrays and maps to be stored - where possible, use Fastutil's specialized maps. For example, if you're storing block state translations, use an `Int2IntMap`.
|
||||||
|
|
||||||
We have a rundown of all the tools you need to develop over on our [wiki](https://github.com/GeyserMC/Geyser/wiki/Developer-Guide). If you have any questions, please feel free to reach out to our [Discord](https://discord.geysermc.org)!
|
We have a rundown of all the tools you need to develop over on our [wiki](https://github.com/GeyserMC/Geyser/wiki/Developer-Guide). If you have any questions, please feel free to reach out to our [Discord](https://discord.gg/geysermc)!
|
||||||
|
14
README.md
14
README.md
@ -1,10 +1,10 @@
|
|||||||
<img src="https://geysermc.org/img/geyser-1760-860.png" alt="Geyser" width="600"/>
|
<img src="https://geysermc.org/img/geyser-1760-860.png" alt="Geyser" width="600"/>
|
||||||
|
|
||||||
[![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/)
|
[![forthebadge made-with-java](https://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.opencollab.dev/job/Geyser/job/master/badge/icon)](https://ci.opencollab.dev/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)](https://discord.gg/geysermc/)
|
||||||
[![HitCount](http://hits.dwyl.com/Geyser/GeyserMC.svg)](http://hits.dwyl.com/Geyser/GeyserMC)
|
[![HitCount](http://hits.dwyl.com/Geyser/GeyserMC.svg)](http://hits.dwyl.com/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/)
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ Geyser is an open collaboration project by [CubeCraft Games](https://cubecraft.n
|
|||||||
Geyser is a proxy, bridging the gap between Minecraft: Bedrock Edition and Minecraft: Java Edition servers.
|
Geyser is a proxy, bridging the gap between Minecraft: Bedrock Edition and Minecraft: Java Edition servers.
|
||||||
The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible. **Please note, this project is still a work in progress and should not be used on production. Expect bugs!**
|
The ultimate goal of this project is to allow Minecraft: Bedrock Edition users to join Minecraft: Java Edition servers as seamlessly as possible. **Please note, this project is still a work in progress and should not be used on production. Expect bugs!**
|
||||||
|
|
||||||
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 joined us here!
|
||||||
|
|
||||||
### Currently supporting Minecraft Bedrock v1.16.100 - v1.16.220 and Minecraft Java v1.16.4 - v1.16.5.
|
### Currently supporting Minecraft Bedrock v1.16.100 - v1.16.220 and Minecraft Java v1.16.4 - v1.16.5.
|
||||||
|
|
||||||
@ -28,8 +28,8 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
|
|||||||
## Links:
|
## Links:
|
||||||
- Website: https://geysermc.org
|
- Website: https://geysermc.org
|
||||||
- Docs: https://github.com/GeyserMC/Geyser/wiki
|
- Docs: https://github.com/GeyserMC/Geyser/wiki
|
||||||
- Download: http://ci.geysermc.org
|
- Download: https://ci.geysermc.org
|
||||||
- Discord: http://discord.geysermc.org/
|
- Discord: https://discord.gg/geysermc
|
||||||
- ~~Donate: https://patreon.com/GeyserMC~~ Currently disabled.
|
- ~~Donate: https://patreon.com/GeyserMC~~ Currently disabled.
|
||||||
- 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
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set
|
|||||||
- Structure block UI
|
- Structure block UI
|
||||||
|
|
||||||
## What can't be fixed
|
## 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.
|
The following things cannot be fixed without changes to Bedrock. As of now, they are not fixable in Geyser.
|
||||||
|
|
||||||
- Custom heads in inventories
|
- Custom heads in inventories
|
||||||
- Clickable links in chat
|
- Clickable links in chat
|
||||||
@ -50,7 +50,7 @@ The following things can't be fixed because of Bedrock limitations. They might b
|
|||||||
## Compiling
|
## Compiling
|
||||||
1. Clone the repo to your computer
|
1. Clone the repo to your computer
|
||||||
2. [Install Maven](https://maven.apache.org/install.html)
|
2. [Install Maven](https://maven.apache.org/install.html)
|
||||||
3. Navigate to the Geyser root directory and run `git submodule update --init --recursive`. This downloads all the needed submodules for Geyser and is a crucial step in this process.
|
3. Navigate to the Geyser root directory and run `git submodule update --init --recursive`. This command downloads all the needed submodules for Geyser and is a crucial step in this process.
|
||||||
4. Run `mvn clean install` and locate to the `target` folder.
|
4. Run `mvn clean install` and locate to the `target` folder.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
@ -263,7 +263,7 @@ public class Entity {
|
|||||||
metadata.getFlags().setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !metadata.getFlags().getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire
|
metadata.getFlags().setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !metadata.getFlags().getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire
|
||||||
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
|
metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02);
|
||||||
metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
|
metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08);
|
||||||
metadata.getFlags().setFlag(EntityFlag.SWIMMING, ((xd & 0x10) == 0x10) && metadata.getFlags().getFlag(EntityFlag.SPRINTING)); // Otherwise swimming is enabled on older servers
|
// Swimming is ignored here and instead we rely on the pose
|
||||||
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80);
|
||||||
|
|
||||||
// Armour stands are handled in their own class
|
// Armour stands are handled in their own class
|
||||||
@ -297,17 +297,38 @@ public class Entity {
|
|||||||
case 5: // no gravity
|
case 5: // no gravity
|
||||||
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
|
metadata.getFlags().setFlag(EntityFlag.HAS_GRAVITY, !(boolean) entityMetadata.getValue());
|
||||||
break;
|
break;
|
||||||
case 6: // Pose change
|
case 6: // Pose change - typically used for bounding box and not animation
|
||||||
if (entityMetadata.getValue().equals(Pose.SLEEPING)) {
|
Pose pose = (Pose) entityMetadata.getValue();
|
||||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, true);
|
|
||||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f);
|
metadata.getFlags().setFlag(EntityFlag.SLEEPING, pose.equals(Pose.SLEEPING));
|
||||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f);
|
// Triggered when crawling
|
||||||
} else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) {
|
metadata.getFlags().setFlag(EntityFlag.SWIMMING, pose.equals(Pose.SWIMMING));
|
||||||
metadata.getFlags().setFlag(EntityFlag.SLEEPING, false);
|
float width = entityType.getWidth();
|
||||||
metadata.put(EntityData.BOUNDING_BOX_WIDTH, getEntityType().getWidth());
|
float height = entityType.getHeight();
|
||||||
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, getEntityType().getHeight());
|
switch (pose) {
|
||||||
|
case SLEEPING:
|
||||||
|
if (this instanceof LivingEntity) {
|
||||||
|
width = 0.2f;
|
||||||
|
height = 0.2f;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SNEAKING:
|
||||||
|
if (entityType == EntityType.PLAYER) {
|
||||||
|
height = 1.5f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FALL_FLYING:
|
||||||
|
case SPIN_ATTACK:
|
||||||
|
case SWIMMING:
|
||||||
|
if (entityType == EntityType.PLAYER) {
|
||||||
|
// Seems like this is only cared about for players; nothing else
|
||||||
|
height = 0.6f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_WIDTH, width);
|
||||||
|
metadata.put(EntityData.BOUNDING_BOX_HEIGHT, height);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,10 @@
|
|||||||
package org.geysermc.connector.entity.player;
|
package org.geysermc.connector.entity.player;
|
||||||
|
|
||||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -35,6 +38,10 @@ import java.util.UUID;
|
|||||||
* The entity class specifically for a {@link GeyserSession}'s player.
|
* The entity class specifically for a {@link GeyserSession}'s player.
|
||||||
*/
|
*/
|
||||||
public class SessionPlayerEntity extends PlayerEntity {
|
public class SessionPlayerEntity extends PlayerEntity {
|
||||||
|
/**
|
||||||
|
* Whether to check for updated speed after all entity metadata has been processed
|
||||||
|
*/
|
||||||
|
private boolean refreshSpeed = false;
|
||||||
|
|
||||||
private final GeyserSession session;
|
private final GeyserSession session;
|
||||||
|
|
||||||
@ -43,7 +50,6 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.session.getCollisionManager().updatePlayerBoundingBox(position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -64,4 +70,27 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||||||
}
|
}
|
||||||
super.setPosition(position);
|
super.setPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) {
|
||||||
|
super.updateBedrockMetadata(entityMetadata, session);
|
||||||
|
if (entityMetadata.getId() == 0) {
|
||||||
|
session.setSwimmingInWater((((byte) entityMetadata.getValue()) & 0x10) == 0x10 && metadata.getFlags().getFlag(EntityFlag.SPRINTING));
|
||||||
|
refreshSpeed = true;
|
||||||
|
} else if (entityMetadata.getId() == 6) {
|
||||||
|
session.setPose((Pose) entityMetadata.getValue());
|
||||||
|
refreshSpeed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBedrockMetadata(GeyserSession session) {
|
||||||
|
super.updateBedrockMetadata(session);
|
||||||
|
if (refreshSpeed) {
|
||||||
|
if (session.adjustSpeed()) {
|
||||||
|
updateBedrockAttributes(session);
|
||||||
|
}
|
||||||
|
refreshSpeed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
|
|||||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||||
import com.github.steveice10.mc.protocol.data.SubProtocol;
|
import com.github.steveice10.mc.protocol.data.SubProtocol;
|
||||||
|
import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
|
||||||
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
|
||||||
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
|
import com.github.steveice10.mc.protocol.data.game.recipe.Recipe;
|
||||||
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
|
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
|
||||||
@ -55,7 +56,10 @@ import com.nukkitx.protocol.bedrock.BedrockPacket;
|
|||||||
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
import com.nukkitx.protocol.bedrock.BedrockServerSession;
|
||||||
import com.nukkitx.protocol.bedrock.data.*;
|
import com.nukkitx.protocol.bedrock.data.*;
|
||||||
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
import com.nukkitx.protocol.bedrock.data.command.CommandPermission;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.packet.*;
|
import com.nukkitx.protocol.bedrock.packet.*;
|
||||||
|
import com.nukkitx.protocol.bedrock.v431.Bedrock_v431;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
@ -75,6 +79,8 @@ import org.geysermc.connector.command.CommandSender;
|
|||||||
import org.geysermc.connector.common.AuthType;
|
import org.geysermc.connector.common.AuthType;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.entity.Tickable;
|
import org.geysermc.connector.entity.Tickable;
|
||||||
|
import org.geysermc.connector.entity.attribute.Attribute;
|
||||||
|
import org.geysermc.connector.entity.attribute.AttributeType;
|
||||||
import org.geysermc.connector.entity.player.SessionPlayerEntity;
|
import org.geysermc.connector.entity.player.SessionPlayerEntity;
|
||||||
import org.geysermc.connector.entity.player.SkullPlayerEntity;
|
import org.geysermc.connector.entity.player.SkullPlayerEntity;
|
||||||
import org.geysermc.connector.inventory.Inventory;
|
import org.geysermc.connector.inventory.Inventory;
|
||||||
@ -215,6 +221,12 @@ public class GeyserSession implements CommandSender {
|
|||||||
|
|
||||||
private boolean sneaking;
|
private boolean sneaking;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the Java pose that the server and/or Geyser believes the player currently has.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private Pose pose = Pose.STANDING;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private boolean sprinting;
|
private boolean sprinting;
|
||||||
|
|
||||||
@ -224,6 +236,22 @@ public class GeyserSession implements CommandSender {
|
|||||||
@Setter
|
@Setter
|
||||||
private boolean jumping;
|
private boolean jumping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the player is swimming in water.
|
||||||
|
* Used to update speed when crawling.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private boolean swimmingInWater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tracks the original speed attribute.
|
||||||
|
*
|
||||||
|
* We need to do this in order to emulate speeds when sneaking under 1.5-blocks-tall areas if the player isn't sneaking,
|
||||||
|
* and when crawling.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private float originalSpeedAttribute;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The dimension of the player.
|
* The dimension of the player.
|
||||||
* As all entities are in the same world, this can be safely applied to all other entities.
|
* As all entities are in the same world, this can be safely applied to all other entities.
|
||||||
@ -346,7 +374,6 @@ public class GeyserSession implements CommandSender {
|
|||||||
/**
|
/**
|
||||||
* If the current player is flying
|
* If the current player is flying
|
||||||
*/
|
*/
|
||||||
@Setter
|
|
||||||
private boolean flying = false;
|
private boolean flying = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -419,6 +446,7 @@ public class GeyserSession implements CommandSender {
|
|||||||
|
|
||||||
this.collisionManager = new CollisionManager(this);
|
this.collisionManager = new CollisionManager(this);
|
||||||
this.playerEntity = new SessionPlayerEntity(this);
|
this.playerEntity = new SessionPlayerEntity(this);
|
||||||
|
collisionManager.updatePlayerBoundingBox(this.playerEntity.getPosition());
|
||||||
|
|
||||||
this.playerInventory = new PlayerInventory();
|
this.playerInventory = new PlayerInventory();
|
||||||
this.openInventory = null;
|
this.openInventory = null;
|
||||||
@ -472,7 +500,12 @@ public class GeyserSession implements CommandSender {
|
|||||||
upstream.sendPacket(entityPacket);
|
upstream.sendPacket(entityPacket);
|
||||||
|
|
||||||
CreativeContentPacket creativePacket = new CreativeContentPacket();
|
CreativeContentPacket creativePacket = new CreativeContentPacket();
|
||||||
|
if (upstream.getSession().getPacketCodec().getProtocolVersion() < Bedrock_v431.V431_CODEC.getProtocolVersion()) {
|
||||||
|
creativePacket.setContents(ItemRegistry.getPre1_16_220CreativeContents());
|
||||||
|
} else {
|
||||||
|
// No additional work required
|
||||||
creativePacket.setContents(ItemRegistry.CREATIVE_ITEMS);
|
creativePacket.setContents(ItemRegistry.CREATIVE_ITEMS);
|
||||||
|
}
|
||||||
upstream.sendPacket(creativePacket);
|
upstream.sendPacket(creativePacket);
|
||||||
|
|
||||||
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
PlayStatusPacket playStatusPacket = new PlayStatusPacket();
|
||||||
@ -811,8 +844,21 @@ public class GeyserSession implements CommandSender {
|
|||||||
|
|
||||||
public void setSneaking(boolean sneaking) {
|
public void setSneaking(boolean sneaking) {
|
||||||
this.sneaking = sneaking;
|
this.sneaking = sneaking;
|
||||||
collisionManager.updatePlayerBoundingBox();
|
|
||||||
collisionManager.updateScaffoldingFlags();
|
// Update pose and bounding box on our end
|
||||||
|
if (!sneaking && adjustSpeed()) {
|
||||||
|
// Update attributes since we're still "sneaking" under a 1.5-block-tall area
|
||||||
|
playerEntity.updateBedrockAttributes(this);
|
||||||
|
// the server *should* update our pose once it has returned to normal
|
||||||
|
} else {
|
||||||
|
if (!flying) {
|
||||||
|
// The pose and bounding box should not be updated if the player is flying
|
||||||
|
setSneakingPose(sneaking);
|
||||||
|
}
|
||||||
|
collisionManager.updateScaffoldingFlags(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
playerEntity.updateBedrockMetadata(this);
|
||||||
|
|
||||||
if (mouseoverEntity != null) {
|
if (mouseoverEntity != null) {
|
||||||
// Horses, etc can change their property depending on if you're sneaking
|
// Horses, etc can change their property depending on if you're sneaking
|
||||||
@ -820,6 +866,53 @@ public class GeyserSession implements CommandSender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setSneakingPose(boolean sneaking) {
|
||||||
|
this.pose = sneaking ? Pose.SNEAKING : Pose.STANDING;
|
||||||
|
playerEntity.getMetadata().put(EntityData.BOUNDING_BOX_HEIGHT, sneaking ? 1.5f : playerEntity.getEntityType().getHeight());
|
||||||
|
playerEntity.getMetadata().getFlags().setFlag(EntityFlag.SNEAKING, sneaking);
|
||||||
|
|
||||||
|
collisionManager.updatePlayerBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwimming(boolean swimming) {
|
||||||
|
this.pose = swimming ? Pose.SWIMMING : Pose.STANDING;
|
||||||
|
playerEntity.getMetadata().put(EntityData.BOUNDING_BOX_HEIGHT, swimming ? 0.6f : playerEntity.getEntityType().getHeight());
|
||||||
|
playerEntity.getMetadata().getFlags().setFlag(EntityFlag.SWIMMING, swimming);
|
||||||
|
playerEntity.updateBedrockMetadata(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlying(boolean flying) {
|
||||||
|
this.flying = flying;
|
||||||
|
|
||||||
|
if (sneaking) {
|
||||||
|
// update bounding box as it is not reduced when flying
|
||||||
|
setSneakingPose(!flying);
|
||||||
|
playerEntity.updateBedrockMetadata(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts speed if the player is crawling.
|
||||||
|
*
|
||||||
|
* @return true if attributes should be updated.
|
||||||
|
*/
|
||||||
|
public boolean adjustSpeed() {
|
||||||
|
Attribute currentPlayerSpeed = playerEntity.getAttributes().get(AttributeType.MOVEMENT_SPEED);
|
||||||
|
if (currentPlayerSpeed != null) {
|
||||||
|
if ((pose.equals(Pose.SNEAKING) && !sneaking && collisionManager.isUnderSlab()) ||
|
||||||
|
(!swimmingInWater && playerEntity.getMetadata().getFlags().getFlag(EntityFlag.SWIMMING) && !collisionManager.isPlayerInWater())) {
|
||||||
|
// Either of those conditions means that Bedrock goes zoom when they shouldn't be
|
||||||
|
currentPlayerSpeed.setValue(originalSpeedAttribute / 3.32f);
|
||||||
|
return true;
|
||||||
|
} else if (originalSpeedAttribute != currentPlayerSpeed.getValue()) {
|
||||||
|
// Speed has reset to normal
|
||||||
|
currentPlayerSpeed.setValue(originalSpeedAttribute);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will be overwritten for GeyserConnect.
|
* Will be overwritten for GeyserConnect.
|
||||||
*/
|
*/
|
||||||
|
@ -27,6 +27,7 @@ package org.geysermc.connector.network.translators.bedrock;
|
|||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket;
|
||||||
import com.nukkitx.protocol.bedrock.data.AdventureSetting;
|
import com.nukkitx.protocol.bedrock.data.AdventureSetting;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
|
import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
@ -37,8 +38,14 @@ public class BedrockAdventureSettingsTranslator extends PacketTranslator<Adventu
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(AdventureSettingsPacket packet, GeyserSession session) {
|
public void translate(AdventureSettingsPacket packet, GeyserSession session) {
|
||||||
ClientPlayerAbilitiesPacket abilitiesPacket =
|
boolean isFlying = packet.getSettings().contains(AdventureSetting.FLYING);
|
||||||
new ClientPlayerAbilitiesPacket(packet.getSettings().contains(AdventureSetting.FLYING));
|
session.setFlying(isFlying);
|
||||||
|
ClientPlayerAbilitiesPacket abilitiesPacket = new ClientPlayerAbilitiesPacket(isFlying);
|
||||||
session.sendDownstreamPacket(abilitiesPacket);
|
session.sendDownstreamPacket(abilitiesPacket);
|
||||||
|
|
||||||
|
if (isFlying && session.getPlayerEntity().getMetadata().getFlags().getFlag(EntityFlag.SWIMMING)) {
|
||||||
|
// Bedrock can fly and swim at the same time? Make sure that can't happen
|
||||||
|
session.setSwimming(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye
|
|||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
import com.nukkitx.protocol.bedrock.data.LevelEventType;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerId;
|
||||||
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
import com.nukkitx.protocol.bedrock.data.inventory.ContainerType;
|
||||||
@ -150,13 +149,18 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
|
|||||||
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
|
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
|
||||||
|
|
||||||
// Adjust position for current eye height
|
// Adjust position for current eye height
|
||||||
if (flags.getFlag(EntityFlag.SNEAKING)) {
|
switch (session.getPose()) {
|
||||||
|
case SNEAKING:
|
||||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 1.27f), 0);
|
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 1.27f), 0);
|
||||||
} else if (flags.getFlag(EntityFlag.SWIMMING) || flags.getFlag(EntityFlag.GLIDING) || flags.getFlag(EntityFlag.DAMAGE_NEARBY_MOBS)) {
|
break;
|
||||||
// Swimming, gliding, or using the trident spin attack
|
case SWIMMING:
|
||||||
|
case FALL_FLYING: // Elytra
|
||||||
|
case SPIN_ATTACK: // Trident spin attack
|
||||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.4f), 0);
|
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.4f), 0);
|
||||||
} else if (flags.getFlag(EntityFlag.SLEEPING)) {
|
break;
|
||||||
|
case SLEEPING:
|
||||||
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.2f), 0);
|
playerPosition = playerPosition.sub(0, (EntityType.PLAYER.getOffset() - 0.2f), 0);
|
||||||
|
break;
|
||||||
} // else, we don't have to modify the position
|
} // else, we don't have to modify the position
|
||||||
|
|
||||||
float diffX = playerPosition.getX() - packet.getBlockPosition().getX();
|
float diffX = playerPosition.getX() - packet.getBlockPosition().getX();
|
||||||
|
@ -59,8 +59,6 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||||||
@Override
|
@Override
|
||||||
public void translate(PlayerActionPacket packet, GeyserSession session) {
|
public void translate(PlayerActionPacket packet, GeyserSession session) {
|
||||||
Entity entity = session.getPlayerEntity();
|
Entity entity = session.getPlayerEntity();
|
||||||
if (entity == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Send book update before any player action
|
// Send book update before any player action
|
||||||
if (packet.getAction() != PlayerActionType.RESPAWN) {
|
if (packet.getAction() != PlayerActionType.RESPAWN) {
|
||||||
@ -84,10 +82,14 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||||||
case START_SWIMMING:
|
case START_SWIMMING:
|
||||||
ClientPlayerStatePacket startSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
ClientPlayerStatePacket startSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.START_SPRINTING);
|
||||||
session.sendDownstreamPacket(startSwimPacket);
|
session.sendDownstreamPacket(startSwimPacket);
|
||||||
|
|
||||||
|
session.setSwimming(true);
|
||||||
break;
|
break;
|
||||||
case STOP_SWIMMING:
|
case STOP_SWIMMING:
|
||||||
ClientPlayerStatePacket stopSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
ClientPlayerStatePacket stopSwimPacket = new ClientPlayerStatePacket((int) entity.getEntityId(), PlayerState.STOP_SPRINTING);
|
||||||
session.sendDownstreamPacket(stopSwimPacket);
|
session.sendDownstreamPacket(stopSwimPacket);
|
||||||
|
|
||||||
|
session.setSwimming(false);
|
||||||
break;
|
break;
|
||||||
case START_GLIDE:
|
case START_GLIDE:
|
||||||
// Otherwise gliding will not work in creative
|
// Otherwise gliding will not work in creative
|
||||||
@ -114,7 +116,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||||||
}
|
}
|
||||||
session.sendDownstreamPacket(useItemPacket);
|
session.sendDownstreamPacket(useItemPacket);
|
||||||
session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, true);
|
session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, true);
|
||||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
// metadata will be updated when sneaking
|
||||||
}
|
}
|
||||||
|
|
||||||
session.setSneaking(true);
|
session.setSneaking(true);
|
||||||
@ -128,7 +130,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
|
|||||||
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, BlockUtils.POSITION_ZERO, BlockFace.DOWN);
|
ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, BlockUtils.POSITION_ZERO, BlockFace.DOWN);
|
||||||
session.sendDownstreamPacket(releaseItemPacket);
|
session.sendDownstreamPacket(releaseItemPacket);
|
||||||
session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, false);
|
session.getPlayerEntity().getMetadata().getFlags().setFlag(EntityFlag.BLOCKING, false);
|
||||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
// metadata will be updated when sneaking
|
||||||
}
|
}
|
||||||
|
|
||||||
session.setSneaking(false);
|
session.setSneaking(false);
|
||||||
|
@ -28,6 +28,7 @@ package org.geysermc.connector.network.translators.collision;
|
|||||||
import com.nukkitx.math.vector.Vector3d;
|
import com.nukkitx.math.vector.Vector3d;
|
||||||
import com.nukkitx.math.vector.Vector3f;
|
import com.nukkitx.math.vector.Vector3f;
|
||||||
import com.nukkitx.math.vector.Vector3i;
|
import com.nukkitx.math.vector.Vector3i;
|
||||||
|
import com.nukkitx.protocol.bedrock.data.entity.EntityData;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlag;
|
||||||
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
import com.nukkitx.protocol.bedrock.data.entity.EntityFlags;
|
||||||
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket;
|
||||||
@ -38,9 +39,13 @@ import org.geysermc.connector.entity.player.PlayerEntity;
|
|||||||
import org.geysermc.connector.entity.type.EntityType;
|
import org.geysermc.connector.entity.type.EntityType;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
import org.geysermc.connector.network.translators.collision.translators.BlockCollision;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.DecimalFormatSymbols;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class CollisionManager {
|
public class CollisionManager {
|
||||||
|
|
||||||
@ -66,6 +71,11 @@ public class CollisionManager {
|
|||||||
* This check doesn't allow players right up against the block, so they must be pushed slightly away.
|
* This check doesn't allow players right up against the block, so they must be pushed slightly away.
|
||||||
*/
|
*/
|
||||||
public static final double COLLISION_TOLERANCE = 0.00001;
|
public static final double COLLISION_TOLERANCE = 0.00001;
|
||||||
|
/**
|
||||||
|
* Trims Y coordinates when jumping to prevent rounding issues being sent to the server.
|
||||||
|
* The locale used is necessary so other regions don't use <code>,</code> as their decimal separator.
|
||||||
|
*/
|
||||||
|
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.#####", new DecimalFormatSymbols(Locale.ENGLISH));
|
||||||
|
|
||||||
public CollisionManager(GeyserSession session) {
|
public CollisionManager(GeyserSession session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
@ -104,17 +114,14 @@ public class CollisionManager {
|
|||||||
} else {
|
} else {
|
||||||
playerPosition = session.getPlayerEntity().getPosition();
|
playerPosition = session.getPlayerEntity().getPosition();
|
||||||
}
|
}
|
||||||
playerBoundingBox = new BoundingBox(playerPosition.getX(), playerPosition.getY() + 0.9, playerPosition.getZ(), 0.6, 1.8, 0.6);
|
playerBoundingBox = new BoundingBox(playerPosition.getX(), playerPosition.getY() + 0.9, playerPosition.getZ(),
|
||||||
|
EntityType.PLAYER.getWidth(), EntityType.PLAYER.getHeight(), EntityType.PLAYER.getLength());
|
||||||
} else {
|
} else {
|
||||||
// According to the Minecraft Wiki, when sneaking:
|
// According to the Minecraft Wiki, when sneaking:
|
||||||
// - In Bedrock Edition, the height becomes 1.65 blocks, allowing movement through spaces as small as 1.75 (2 - 1⁄4) blocks high.
|
// - In Bedrock Edition, the height becomes 1.65 blocks, allowing movement through spaces as small as 1.75 (2 - 1⁄4) blocks high.
|
||||||
// - In Java Edition, the height becomes 1.5 blocks.
|
// - In Java Edition, the height becomes 1.5 blocks.
|
||||||
// TODO: Have this depend on the player's literal bounding box variable
|
// Other instances have the player's bounding box become as small as 0.6 or 0.2.
|
||||||
if (session.isSneaking()) {
|
playerBoundingBox.setSizeY(session.getPlayerEntity().getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT));
|
||||||
playerBoundingBox.setSizeY(1.5);
|
|
||||||
} else {
|
|
||||||
playerBoundingBox.setSizeY(1.8);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +155,11 @@ public class CollisionManager {
|
|||||||
position = Vector3d.from(playerBoundingBox.getMiddleX(),
|
position = Vector3d.from(playerBoundingBox.getMiddleX(),
|
||||||
playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2),
|
playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2),
|
||||||
playerBoundingBox.getMiddleZ());
|
playerBoundingBox.getMiddleZ());
|
||||||
|
|
||||||
|
if (!onGround) {
|
||||||
|
// Trim the position to prevent rounding errors that make Java think we are clipping into a block
|
||||||
|
position = Vector3d.from(position.getX(), Double.parseDouble(DECIMAL_FORMAT.format(position.getY())), position.getZ());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// When chunk caching is off, we have to rely on this
|
// When chunk caching is off, we have to rely on this
|
||||||
// It rounds the Y position up to the nearest 0.5
|
// It rounds the Y position up to the nearest 0.5
|
||||||
@ -246,16 +258,48 @@ public class CollisionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScaffoldingFlags();
|
updateScaffoldingFlags(true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the block located at the player's floor position plus 1 would intersect with the player,
|
||||||
|
* were they not sneaking
|
||||||
|
*/
|
||||||
|
public boolean isUnderSlab() {
|
||||||
|
if (!session.getConnector().getConfig().isCacheChunks()) {
|
||||||
|
// We can't reliably determine this
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Vector3i position = session.getPlayerEntity().getPosition().toInt();
|
||||||
|
BlockCollision collision = CollisionTranslator.getCollisionAt(session, position.getX(), position.getY(), position.getZ());
|
||||||
|
if (collision != null) {
|
||||||
|
// Determine, if the player's bounding box *were* at full height, if it would intersect with the block
|
||||||
|
// at the current location.
|
||||||
|
playerBoundingBox.setSizeY(EntityType.PLAYER.getHeight());
|
||||||
|
boolean result = collision.checkIntersection(playerBoundingBox);
|
||||||
|
playerBoundingBox.setSizeY(session.getPlayerEntity().getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return if the player is currently in a water block
|
||||||
|
*/
|
||||||
|
public boolean isPlayerInWater() {
|
||||||
|
return session.getConnector().getConfig().isCacheChunks()
|
||||||
|
&& session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt()) == BlockTranslator.JAVA_WATER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates scaffolding entity flags
|
* Updates scaffolding entity flags
|
||||||
* Scaffolding needs to be checked per-move since it's a flag in Bedrock but Java does it client-side
|
* Scaffolding needs to be checked per-move since it's a flag in Bedrock but Java does it client-side
|
||||||
|
*
|
||||||
|
* @param updateMetadata whether we should update metadata if something changed
|
||||||
*/
|
*/
|
||||||
public void updateScaffoldingFlags() {
|
public void updateScaffoldingFlags(boolean updateMetadata) {
|
||||||
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
|
EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags();
|
||||||
boolean flagsChanged;
|
boolean flagsChanged;
|
||||||
boolean isSneakingWithScaffolding = (touchingScaffolding || onScaffolding) && session.isSneaking();
|
boolean isSneakingWithScaffolding = (touchingScaffolding || onScaffolding) && session.isSneaking();
|
||||||
@ -269,7 +313,7 @@ public class CollisionManager {
|
|||||||
flagsChanged |= flags.getFlag(EntityFlag.IN_SCAFFOLDING) != touchingScaffolding;
|
flagsChanged |= flags.getFlag(EntityFlag.IN_SCAFFOLDING) != touchingScaffolding;
|
||||||
flags.setFlag(EntityFlag.IN_SCAFFOLDING, touchingScaffolding);
|
flags.setFlag(EntityFlag.IN_SCAFFOLDING, touchingScaffolding);
|
||||||
|
|
||||||
if (flagsChanged) {
|
if (flagsChanged && updateMetadata) {
|
||||||
session.getPlayerEntity().updateBedrockMetadata(session);
|
session.getPlayerEntity().updateBedrockMetadata(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
import org.geysermc.connector.GeyserConnector;
|
||||||
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator;
|
||||||
import org.geysermc.connector.network.translators.world.block.BlockTranslator1_16_210;
|
import org.geysermc.connector.network.translators.world.block.BlockTranslator1_16_210;
|
||||||
import org.geysermc.connector.utils.FileUtils;
|
import org.geysermc.connector.utils.FileUtils;
|
||||||
import org.geysermc.connector.utils.LanguageUtils;
|
import org.geysermc.connector.utils.LanguageUtils;
|
||||||
@ -161,7 +162,7 @@ public class ItemRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object2IntMap<String> bedrockBlockIdOverrides = new Object2IntOpenHashMap<>();
|
Object2IntMap<String> bedrockBlockIdOverrides = new Object2IntOpenHashMap<>();
|
||||||
Set<String> blacklistedIdentifiers = new ObjectOpenHashSet<>();
|
Object2IntMap<String> blacklistedIdentifiers = new Object2IntOpenHashMap<>();
|
||||||
|
|
||||||
// Load creative items
|
// Load creative items
|
||||||
// We load this before item mappings to get overridden block runtime ID mappings
|
// We load this before item mappings to get overridden block runtime ID mappings
|
||||||
@ -226,10 +227,11 @@ public class ItemRegistry {
|
|||||||
|
|
||||||
if (blockRuntimeId != 0) {
|
if (blockRuntimeId != 0) {
|
||||||
// Add override for item mapping, unless it already exists... then we know multiple states can exist
|
// Add override for item mapping, unless it already exists... then we know multiple states can exist
|
||||||
if (!blacklistedIdentifiers.contains(identifier)) {
|
if (!blacklistedIdentifiers.containsKey(identifier)) {
|
||||||
if (bedrockBlockIdOverrides.containsKey(identifier)) {
|
if (bedrockBlockIdOverrides.containsKey(identifier)) {
|
||||||
bedrockBlockIdOverrides.remove(identifier);
|
bedrockBlockIdOverrides.remove(identifier);
|
||||||
blacklistedIdentifiers.add(identifier);
|
// Save this as a blacklist, but also as knowledge of what the block state name should be
|
||||||
|
blacklistedIdentifiers.put(identifier, blockRuntimeId);
|
||||||
} else {
|
} else {
|
||||||
// Unless there's multiple possibilities for this one state, let this be
|
// Unless there's multiple possibilities for this one state, let this be
|
||||||
bedrockBlockIdOverrides.put(identifier, blockRuntimeId);
|
bedrockBlockIdOverrides.put(identifier, blockRuntimeId);
|
||||||
@ -248,6 +250,8 @@ public class ItemRegistry {
|
|||||||
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockTranslator blockTranslator = BlockTranslator1_16_210.INSTANCE;
|
||||||
|
|
||||||
int itemIndex = 0;
|
int itemIndex = 0;
|
||||||
int javaFurnaceMinecartId = 0;
|
int javaFurnaceMinecartId = 0;
|
||||||
boolean usingFurnaceMinecart = GeyserConnector.getInstance().getConfig().isAddNonBedrockItems();
|
boolean usingFurnaceMinecart = GeyserConnector.getInstance().getConfig().isAddNonBedrockItems();
|
||||||
@ -275,7 +279,110 @@ public class ItemRegistry {
|
|||||||
// Straight from BDS is our best chance of getting an item that doesn't run into issues
|
// Straight from BDS is our best chance of getting an item that doesn't run into issues
|
||||||
bedrockBlockId = blockIdOverride;
|
bedrockBlockId = blockIdOverride;
|
||||||
} else {
|
} else {
|
||||||
bedrockBlockId = BlockTranslator1_16_210.INSTANCE.getBedrockBlockId(blockRuntimeIdNode.intValue());
|
// Try to get an example block runtime ID from the creative contents packet, for Bedrock identifier obtaining
|
||||||
|
int aValidBedrockBlockId = blacklistedIdentifiers.getOrDefault(bedrockIdentifier, -1);
|
||||||
|
if (aValidBedrockBlockId == -1) {
|
||||||
|
// Fallback
|
||||||
|
bedrockBlockId = blockTranslator.getBedrockBlockId(blockRuntimeIdNode.intValue());
|
||||||
|
} else {
|
||||||
|
// As of 1.16.220, every item requires a block runtime ID attached to it.
|
||||||
|
// This is mostly for identifying different blocks with the same item ID - wool, slabs, some walls.
|
||||||
|
// However, in order for some visuals and crafting to work, we need to send the first matching block state
|
||||||
|
// as indexed by Bedrock's block palette
|
||||||
|
// There are exceptions! But, ideally, the block ID override should take care of those.
|
||||||
|
String javaBlockIdentifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockRuntimeIdNode.intValue()).split("\\[")[0];
|
||||||
|
NbtMapBuilder requiredBlockStatesBuilder = NbtMap.builder();
|
||||||
|
String correctBedrockIdentifier = blockTranslator.getAllBedrockBlockStates().get(aValidBedrockBlockId).getString("name");
|
||||||
|
boolean firstPass = true;
|
||||||
|
for (Map.Entry<String, Integer> blockEntry : BlockTranslator.getJavaIdBlockMap().entrySet()) {
|
||||||
|
if (blockEntry.getKey().split("\\[")[0].equals(javaBlockIdentifier)) {
|
||||||
|
int bedrockBlockRuntimeId = blockTranslator.getBedrockBlockId(blockEntry.getValue());
|
||||||
|
NbtMap blockTag = blockTranslator.getAllBedrockBlockStates().get(bedrockBlockRuntimeId);
|
||||||
|
String bedrockName = blockTag.getString("name");
|
||||||
|
if (!bedrockName.equals(correctBedrockIdentifier)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NbtMap states = blockTag.getCompound("states");
|
||||||
|
|
||||||
|
if (firstPass) {
|
||||||
|
firstPass = false;
|
||||||
|
if (states.size() == 0) {
|
||||||
|
// No need to iterate and find all block states - this is the one, as there can't be any others
|
||||||
|
bedrockBlockId = bedrockBlockRuntimeId;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
requiredBlockStatesBuilder.putAll(states);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Object> nbtEntry : states.entrySet()) {
|
||||||
|
Object value = requiredBlockStatesBuilder.get(nbtEntry.getKey());
|
||||||
|
if (value != null && !nbtEntry.getValue().equals(value)) { // Null means this value has already been removed/deemed as unneeded
|
||||||
|
// This state can change between different block states, and therefore is not required
|
||||||
|
// to build a successful block state of this
|
||||||
|
requiredBlockStatesBuilder.remove(nbtEntry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (requiredBlockStatesBuilder.size() == 0) {
|
||||||
|
// There are no required block states
|
||||||
|
// E.G. there was only a direction property that is no longer in play
|
||||||
|
// (States that are important include color for glass)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NbtMap requiredBlockStates = requiredBlockStatesBuilder.build();
|
||||||
|
if (bedrockBlockId == -1) {
|
||||||
|
int i = -1;
|
||||||
|
// We need to loop around again (we can't cache the block tags above) because Bedrock can include states that we don't have a pairing for
|
||||||
|
// in it's "preferred" block state - I.E. the first matching block state in the list
|
||||||
|
for (NbtMap blockTag : blockTranslator.getAllBedrockBlockStates()) {
|
||||||
|
i++;
|
||||||
|
if (blockTag.getString("name").equals(correctBedrockIdentifier)) {
|
||||||
|
NbtMap states = blockTag.getCompound("states");
|
||||||
|
boolean valid = true;
|
||||||
|
for (Map.Entry<String, Object> nbtEntry : requiredBlockStates.entrySet()) {
|
||||||
|
if (!states.get(nbtEntry.getKey()).equals(nbtEntry.getValue())) {
|
||||||
|
// A required block state doesn't match - this one is not valid
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid) {
|
||||||
|
bedrockBlockId = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bedrockBlockId == -1) {
|
||||||
|
throw new RuntimeException("Could not find a block match for " + entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because we have replaced the Bedrock block ID, we also need to replace the creative contents block runtime ID
|
||||||
|
// That way, creative items work correctly for these blocks
|
||||||
|
for (int j = 0; j < creativeItems.size(); j++) {
|
||||||
|
ItemData itemData = creativeItems.get(j);
|
||||||
|
if (itemData.getId() == bedrockId) {
|
||||||
|
if (itemData.getDamage() != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NbtMap states = blockTranslator.getAllBedrockBlockStates().get(itemData.getBlockRuntimeId()).getCompound("states");
|
||||||
|
boolean valid = true;
|
||||||
|
for (Map.Entry<String, Object> nbtEntry : requiredBlockStates.entrySet()) {
|
||||||
|
if (!states.get(nbtEntry.getKey()).equals(nbtEntry.getValue())) {
|
||||||
|
// A required block state doesn't match - this one is not valid
|
||||||
|
valid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valid) {
|
||||||
|
creativeItems.set(j, itemData.toBuilder().blockRuntimeId(bedrockBlockId).build());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,6 +527,37 @@ public class ItemRegistry {
|
|||||||
JAVA_ONLY_ITEMS = ImmutableSet.copyOf(javaOnlyItems);
|
JAVA_ONLY_ITEMS = ImmutableSet.copyOf(javaOnlyItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* pre-1.16.220 support start */
|
||||||
|
|
||||||
|
private static ItemData[] LEGACY_CREATIVE_CONTENTS = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Built on the fly so extra memory isn't used if there are no 1.16.210-or-below clients joining.
|
||||||
|
*
|
||||||
|
* @return a list of creative items built for versions before 1.16.220.
|
||||||
|
*/
|
||||||
|
public static ItemData[] getPre1_16_220CreativeContents() {
|
||||||
|
if (LEGACY_CREATIVE_CONTENTS != null) {
|
||||||
|
return LEGACY_CREATIVE_CONTENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-1.16.220 relies on item damage values that the creative content packet drops
|
||||||
|
ItemData[] creativeContents = new ItemData[CREATIVE_ITEMS.length];
|
||||||
|
for (int i = 0; i < CREATIVE_ITEMS.length; i++) {
|
||||||
|
ItemData item = CREATIVE_ITEMS[i];
|
||||||
|
if (item.getBlockRuntimeId() != 0) {
|
||||||
|
creativeContents[i] = item.toBuilder().damage(getItem(item).getBedrockData()).build();
|
||||||
|
} else {
|
||||||
|
// No block runtime ID means that this item is backwards-compatible
|
||||||
|
creativeContents[i] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LEGACY_CREATIVE_CONTENTS = creativeContents;
|
||||||
|
return creativeContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pre-1.16.220 support end */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an {@link ItemEntry} from the given {@link ItemStack}.
|
* Gets an {@link ItemEntry} from the given {@link ItemStack}.
|
||||||
*
|
*
|
||||||
@ -437,10 +575,22 @@ public class ItemRegistry {
|
|||||||
* @return an item entry from the given item data
|
* @return an item entry from the given item data
|
||||||
*/
|
*/
|
||||||
public static ItemEntry getItem(ItemData data) {
|
public static ItemEntry getItem(ItemData data) {
|
||||||
|
boolean isBlock = data.getBlockRuntimeId() != 0;
|
||||||
|
boolean hasDamage = data.getDamage() != 0;
|
||||||
|
|
||||||
for (ItemEntry itemEntry : ITEM_ENTRIES.values()) {
|
for (ItemEntry itemEntry : ITEM_ENTRIES.values()) {
|
||||||
if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() ||
|
if (itemEntry.getBedrockId() == data.getId()) {
|
||||||
|
if (isBlock && !hasDamage) { // Pre-1.16.220 will not use block runtime IDs at all, so we shouldn't check either
|
||||||
|
if (data.getBlockRuntimeId() != itemEntry.getBedrockBlockId()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(itemEntry.getBedrockData() == data.getDamage() ||
|
||||||
// Make exceptions for potions and tipped arrows, whose damage values can vary
|
// Make exceptions for potions and tipped arrows, whose damage values can vary
|
||||||
(itemEntry.getJavaIdentifier().endsWith("potion") || itemEntry.getJavaIdentifier().equals("minecraft:arrow")))) {
|
(itemEntry.getJavaIdentifier().endsWith("potion") || itemEntry.getJavaIdentifier().equals("minecraft:arrow")))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!JAVA_ONLY_ITEMS.contains(itemEntry.getJavaIdentifier())) {
|
if (!JAVA_ONLY_ITEMS.contains(itemEntry.getJavaIdentifier())) {
|
||||||
// From a Bedrock item data, we aren't getting one of these items
|
// From a Bedrock item data, we aren't getting one of these items
|
||||||
return itemEntry;
|
return itemEntry;
|
||||||
|
@ -25,13 +25,12 @@
|
|||||||
|
|
||||||
package org.geysermc.connector.network.translators.java.entity;
|
package org.geysermc.connector.network.translators.java.entity;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket;
|
||||||
import org.geysermc.connector.entity.Entity;
|
import org.geysermc.connector.entity.Entity;
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket;
|
|
||||||
|
|
||||||
@Translator(packet = ServerEntityPositionPacket.class)
|
@Translator(packet = ServerEntityPositionPacket.class)
|
||||||
public class JavaEntityPositionTranslator extends PacketTranslator<ServerEntityPositionPacket> {
|
public class JavaEntityPositionTranslator extends PacketTranslator<ServerEntityPositionPacket> {
|
||||||
|
|
||||||
|
@ -67,7 +67,12 @@ public class JavaEntityPropertiesTranslator extends PacketTranslator<ServerEntit
|
|||||||
entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
||||||
break;
|
break;
|
||||||
case GENERIC_MOVEMENT_SPEED:
|
case GENERIC_MOVEMENT_SPEED:
|
||||||
entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
float value = (float) AttributeUtils.calculateValue(attribute);
|
||||||
|
entity.getAttributes().put(AttributeType.MOVEMENT_SPEED, AttributeType.MOVEMENT_SPEED.getAttribute(value));
|
||||||
|
if (isSessionPlayer) {
|
||||||
|
session.setOriginalSpeedAttribute(value);
|
||||||
|
session.adjustSpeed();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case GENERIC_FOLLOW_RANGE:
|
case GENERIC_FOLLOW_RANGE:
|
||||||
entity.getAttributes().put(AttributeType.FOLLOW_RANGE, AttributeType.FOLLOW_RANGE.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
entity.getAttributes().put(AttributeType.FOLLOW_RANGE, AttributeType.FOLLOW_RANGE.getAttribute((float) AttributeUtils.calculateValue(attribute)));
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
package org.geysermc.connector.network.translators.java.entity.player;
|
package org.geysermc.connector.network.translators.java.entity.player;
|
||||||
|
|
||||||
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerAbilitiesPacket;
|
import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerAbilitiesPacket;
|
||||||
import org.geysermc.connector.entity.player.PlayerEntity;
|
|
||||||
import org.geysermc.connector.network.session.GeyserSession;
|
import org.geysermc.connector.network.session.GeyserSession;
|
||||||
import org.geysermc.connector.network.translators.PacketTranslator;
|
import org.geysermc.connector.network.translators.PacketTranslator;
|
||||||
import org.geysermc.connector.network.translators.Translator;
|
import org.geysermc.connector.network.translators.Translator;
|
||||||
@ -36,10 +35,6 @@ public class JavaPlayerAbilitiesTranslator extends PacketTranslator<ServerPlayer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void translate(ServerPlayerAbilitiesPacket packet, GeyserSession session) {
|
public void translate(ServerPlayerAbilitiesPacket packet, GeyserSession session) {
|
||||||
PlayerEntity entity = session.getPlayerEntity();
|
|
||||||
if (entity == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
session.setCanFly(packet.isCanFly());
|
session.setCanFly(packet.isCanFly());
|
||||||
session.setFlying(packet.isFlying());
|
session.setFlying(packet.isFlying());
|
||||||
session.sendAdventureSettings();
|
session.sendAdventureSettings();
|
||||||
|
@ -52,6 +52,7 @@ public abstract class BlockTranslator {
|
|||||||
* The Java block runtime ID of air
|
* The Java block runtime ID of air
|
||||||
*/
|
*/
|
||||||
public static final int JAVA_AIR_ID = 0;
|
public static final int JAVA_AIR_ID = 0;
|
||||||
|
public static final int JAVA_WATER_ID;
|
||||||
/**
|
/**
|
||||||
* The Bedrock block runtime ID of air
|
* The Bedrock block runtime ID of air
|
||||||
*/
|
*/
|
||||||
@ -60,6 +61,9 @@ public abstract class BlockTranslator {
|
|||||||
|
|
||||||
private final Int2IntMap javaToBedrockBlockMap = new Int2IntOpenHashMap();
|
private final Int2IntMap javaToBedrockBlockMap = new Int2IntOpenHashMap();
|
||||||
private final Int2IntMap bedrockToJavaBlockMap = new Int2IntOpenHashMap();
|
private final Int2IntMap bedrockToJavaBlockMap = new Int2IntOpenHashMap();
|
||||||
|
|
||||||
|
private final NbtList<NbtMap> bedrockBlockStates;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores a list of differences in block identifiers.
|
* Stores a list of differences in block identifiers.
|
||||||
* Items will not be added to this list if the key and value is the same.
|
* Items will not be added to this list if the key and value is the same.
|
||||||
@ -131,6 +135,7 @@ public abstract class BlockTranslator {
|
|||||||
int furnaceLitRuntimeId = -1;
|
int furnaceLitRuntimeId = -1;
|
||||||
int spawnerRuntimeId = -1;
|
int spawnerRuntimeId = -1;
|
||||||
int uniqueJavaId = -1;
|
int uniqueJavaId = -1;
|
||||||
|
int waterRuntimeId = -1;
|
||||||
Iterator<Map.Entry<String, JsonNode>> blocksIterator = BLOCKS_JSON.fields();
|
Iterator<Map.Entry<String, JsonNode>> blocksIterator = BLOCKS_JSON.fields();
|
||||||
while (blocksIterator.hasNext()) {
|
while (blocksIterator.hasNext()) {
|
||||||
javaRuntimeId++;
|
javaRuntimeId++;
|
||||||
@ -196,6 +201,9 @@ public abstract class BlockTranslator {
|
|||||||
|
|
||||||
} else if (javaId.startsWith("minecraft:spawner")) {
|
} else if (javaId.startsWith("minecraft:spawner")) {
|
||||||
spawnerRuntimeId = javaRuntimeId;
|
spawnerRuntimeId = javaRuntimeId;
|
||||||
|
|
||||||
|
} else if ("minecraft:water[level=0]".equals(javaId)) {
|
||||||
|
waterRuntimeId = javaRuntimeId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +227,11 @@ public abstract class BlockTranslator {
|
|||||||
}
|
}
|
||||||
JAVA_RUNTIME_SPAWNER_ID = spawnerRuntimeId;
|
JAVA_RUNTIME_SPAWNER_ID = spawnerRuntimeId;
|
||||||
|
|
||||||
|
if (waterRuntimeId == -1) {
|
||||||
|
throw new AssertionError("Unable to find Java water in palette");
|
||||||
|
}
|
||||||
|
JAVA_WATER_ID = waterRuntimeId;
|
||||||
|
|
||||||
BlockTranslator1_16_100.init();
|
BlockTranslator1_16_100.init();
|
||||||
BlockTranslator1_16_210.init();
|
BlockTranslator1_16_210.init();
|
||||||
BLOCKS_JSON = null; // We no longer require this so let it garbage collect away
|
BLOCKS_JSON = null; // We no longer require this so let it garbage collect away
|
||||||
@ -232,6 +245,7 @@ public abstract class BlockTranslator {
|
|||||||
try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)))) {
|
try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(new GZIPInputStream(stream)))) {
|
||||||
NbtMap blockPalette = (NbtMap) nbtInputStream.readTag();
|
NbtMap blockPalette = (NbtMap) nbtInputStream.readTag();
|
||||||
blocksTag = (NbtList<NbtMap>) blockPalette.getList("blocks", NbtType.COMPOUND);
|
blocksTag = (NbtList<NbtMap>) blockPalette.getList("blocks", NbtType.COMPOUND);
|
||||||
|
this.bedrockBlockStates = blocksTag;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new AssertionError("Unable to get blocks from runtime block states", e);
|
throw new AssertionError("Unable to get blocks from runtime block states", e);
|
||||||
}
|
}
|
||||||
@ -411,6 +425,10 @@ public abstract class BlockTranslator {
|
|||||||
return bedrockWaterId;
|
return bedrockWaterId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NbtList<NbtMap> getAllBedrockBlockStates() {
|
||||||
|
return this.bedrockBlockStates;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the "block state version" generated in the Bedrock block palette that completes an NBT indication of a
|
* @return the "block state version" generated in the Bedrock block palette that completes an NBT indication of a
|
||||||
* block state.
|
* block state.
|
||||||
|
@ -133,8 +133,7 @@ public class BlockUtils {
|
|||||||
hasteLevel = session.getEffectCache().getEffectLevel(Effect.FASTER_DIG);
|
hasteLevel = session.getEffectCache().getEffectLevel(Effect.FASTER_DIG);
|
||||||
miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
|
miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG);
|
||||||
|
|
||||||
boolean isInWater = session.getConnector().getConfig().isCacheChunks()
|
boolean isInWater = session.getCollisionManager().isPlayerInWater();
|
||||||
&& session.getBlockTranslator().getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == session.getBlockTranslator().getBedrockWaterId();
|
|
||||||
|
|
||||||
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
|
boolean insideOfWaterWithoutAquaAffinity = isInWater &&
|
||||||
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;
|
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getNbt(), "minecraft:aqua_affinity") < 1;
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren