158158import java .util .List ;
159159import java .util .concurrent .CompletableFuture ;
160160import java .util .Map .Entry ;
161+ import java .util .Queue ;
161162import java .util .concurrent .ThreadLocalRandom ;
162163import java .util .concurrent .TimeUnit ;
163164import java .util .concurrent .atomic .AtomicBoolean ;
@@ -354,7 +355,7 @@ public class Player extends EntityHuman implements CommandSender, ChunkLoader, I
354355 protected boolean fakeInventoryOpen ;
355356 ///
356357
357- ///todo hack for receive a error position after teleport
358+ /// todo hack for receive a error position after teleport
358359 private Pair <Location , Long > lastTeleportMessage ;
359360 ///
360361
@@ -583,6 +584,9 @@ private void setTitle(String text) {
583584 SetTitlePacket packet = new SetTitlePacket ();
584585 packet .text = text ;
585586 packet .type = SetTitlePacket .TYPE_TITLE ;
587+ packet .fadeInTime = -1 ;
588+ packet .stayTime = -1 ;
589+ packet .fadeOutTime = -1 ;
586590 this .dataPacket (packet );
587591 }
588592
@@ -851,7 +855,7 @@ public void onRun(int currentTick) {
851855
852856 protected void checkNearEntities () {
853857 for (Entity entity : this .level .getNearbyEntities (this .boundingBox .grow (1 , 0.5 , 1 ), this )) {
854- if (entity == null ) continue ;
858+ if (entity == null ) continue ;
855859 entity .scheduleUpdate ();
856860
857861 if (!entity .isAlive () || !this .isAlive ()) {
@@ -1692,10 +1696,30 @@ public boolean hasAutoJump() {
16921696 return this .getAdventureSettings ().get (Type .AUTO_JUMP );
16931697 }
16941698
1699+ public void broadcastClientSyncedProperties (Player ... viewers ) {
1700+ PropertySyncData data = this .getClientSyncProperties ();
1701+ if (data == null ) return ;
1702+
1703+ SetEntityDataPacket pk = new SetEntityDataPacket ();
1704+ pk .eid = this .getId ();
1705+ pk .entityData = this .getEntityDataMap ();
1706+ pk .syncedProperties = data ;
1707+ pk .frame = 0L ;
1708+
1709+ Player [] targets = (viewers == null || viewers .length == 0 )
1710+ ? this .getViewers ().values ().toArray (Player .EMPTY_ARRAY )
1711+ : viewers ;
1712+
1713+ for (Player v : targets ) {
1714+ if (v != null ) v .dataPacket (pk );
1715+ }
1716+ }
1717+
16951718 @ Override
16961719 public void spawnTo (Player player ) {
16971720 if (player .spawned && this .isAlive () && player .getLevel () == this .level && player .canSee (this )/* && !this.isSpectator()*/ ) {
16981721 super .spawnTo (player );
1722+ this .broadcastClientSyncedProperties (player );
16991723
17001724 if (this .isSpectator ()) {
17011725 //发送旁观者的游戏模式给对方,使得对方客户端正确渲染玩家实体
@@ -2073,34 +2097,45 @@ public boolean isUsingItem(String itemId) {
20732097 }
20742098
20752099 /**
2076- * Sets the cooldown time for the specified item to use
2100+ * the cooldown of specified item is end
20772101 *
2078- * @param coolDownTick the cool down tick
2079- * @param itemId the item id
2102+ * @param itemId the item identifier
2103+ * @return the boolean
20802104 */
2081- public void setItemCoolDown (int coolDownTick , Identifier itemId ) {
2082- var pk = new PlayerStartItemCoolDownPacket ();
2083- pk .setCoolDownDuration (coolDownTick );
2084- pk .setItemCategory (itemId .toString ());
2085- this .cooldownTickMap .put (itemId .toString (), this .level .getTick () + coolDownTick );
2086- this .dataPacket (pk );
2105+ public boolean isItemCoolDownEnd (Identifier itemId ) {
2106+ return isItemCoolDownEnd (itemId .toString ());
20872107 }
20882108
20892109 /**
20902110 * the cooldown of specified item is end
20912111 *
2092- * @param itemId the item
2112+ * @param category a string category
20932113 * @return the boolean
20942114 */
2095- public boolean isItemCoolDownEnd (Identifier itemId ) {
2096- Integer tick = this .cooldownTickMap .getOrDefault (itemId .toString (), 0 );
2097- boolean result = this .getLevel ().getTick () - tick > 0 ;
2098- if (result ) {
2099- cooldownTickMap .remove (itemId .toString ());
2100- }
2101- return result ;
2115+ public boolean isItemCoolDownEnd (String category ) {
2116+ int now = this .getLevel ().getTick ();
2117+ int end = this .cooldownTickMap .getOrDefault (category , 0 );
2118+ boolean done = now - end >= 0 ;
2119+ if (done ) this .cooldownTickMap .remove (category );
2120+ return done ;
21022121 }
21032122
2123+ /**
2124+ * Sets the cooldown time for the specified item to use
2125+ *
2126+ * @param coolDownTick the cool down tick
2127+ * @param itemId the item id
2128+ */
2129+ public void setItemCoolDown (int coolDown , Identifier itemId ) {
2130+ setItemCoolDown (coolDown , itemId .toString ());
2131+ }
2132+
2133+ /**
2134+ * Sets the cooldown time for the specified item to use
2135+ *
2136+ * @param coolDownTick the cool down tick
2137+ * @param itemId a string category
2138+ */
21042139 public void setItemCoolDown (int coolDown , String category ) {
21052140 var pk = new PlayerStartItemCoolDownPacket ();
21062141 pk .setCoolDownDuration (coolDown );
@@ -2109,15 +2144,6 @@ public void setItemCoolDown(int coolDown, String category) {
21092144 this .dataPacket (pk );
21102145 }
21112146
2112- public boolean isItemCoolDownEnd (String category ) {
2113- Integer tick = this .cooldownTickMap .getOrDefault (category , 0 );
2114- boolean result = this .getLevel ().getTick () - tick > 0 ;
2115- if (result ) {
2116- cooldownTickMap .remove (category );
2117- }
2118- return result ;
2119- }
2120-
21212147 /**
21222148 * Start last use tick for an item(right-click).
21232149 *
@@ -2203,7 +2229,7 @@ public Pair<Position, SpawnPointType> getSpawn() {
22032229 public void setSpawn (Position pos , SpawnPointType spawnPointType ) {
22042230 Preconditions .checkNotNull (pos );
22052231 Preconditions .checkNotNull (pos .level );
2206- this .spawnPoint = new Position (pos .x , pos .y , pos .z , level );
2232+ this .spawnPoint = new Position (pos .x , pos .y , pos .z , pos . level );
22072233 this .spawnPointType = spawnPointType ;
22082234 SetSpawnPositionPacket pk = new SetSpawnPositionPacket ();
22092235 pk .spawnType = SetSpawnPositionPacket .TYPE_PLAYER_SPAWN ;
@@ -2231,8 +2257,8 @@ public void sendChunk(int x, int z, DataPacket packet) {
22312257 }
22322258 }
22332259
2234- for (BlockEntity entity : this .level .getChunkBlockEntities (x , z ).values ()) {
2235- if (entity instanceof BlockEntitySpawnable spawnable ) {
2260+ for (BlockEntity entity : this .level .getChunkBlockEntities (x , z ).values ()) {
2261+ if (entity instanceof BlockEntitySpawnable spawnable ) {
22362262 spawnable .spawnTo (this );
22372263 }
22382264 }
@@ -2680,7 +2706,7 @@ public boolean onUpdate(int currentTick) {
26802706
26812707 this .entityBaseTick (tickDiff );
26822708
2683- if (this .getServer ().getDifficulty () == 0 && this .level .getGameRules ().getBoolean (GameRule .NATURAL_REGENERATION )) {
2709+ if (this .getServer ().getDifficulty () == 0 || this .level .getGameRules ().getBoolean (GameRule .NATURAL_REGENERATION )) {
26842710 if (this .getHealth () < this .getMaxHealth () && this .ticksLived % 20 == 0 ) {
26852711 this .heal (1 );
26862712 }
@@ -4344,7 +4370,6 @@ public void refreshChunkRender() {
43444370 }
43454371
43464372 /**
4347- *
43484373 * Sends a form to a player and assigns the next ID to it
43494374 * To open a form safely, please use {@link Form#send(Player)}
43504375 *
@@ -4356,12 +4381,11 @@ public int sendForm(Form<?> form) {
43564381 }
43574382
43584383 /**
4359- *
43604384 * Sends a form to a player and assigns a given ID to it
43614385 * To open a form safely, please use {@link Form#send(Player)}
43624386 *
43634387 * @param form The form to open
4364- * @param id The ID to assign the form to
4388+ * @param id The ID to assign the form to
43654389 * @return The id assigned to the form
43664390 */
43674391 public int sendForm (Form <?> form , int id ) {
@@ -4370,7 +4394,7 @@ public int sendForm(Form<?> form, int id) {
43704394 return id ;
43714395 }
43724396
4373- if (!form .isViewer (this )) {
4397+ if (!form .isViewer (this )) {
43744398 form .viewers ().add (this );
43754399 }
43764400
@@ -4587,7 +4611,7 @@ public Inventory getWindowById(int id) {
45874611 * @return The unique identifier assigned to the window if successfully added and opened; -1 if the window fails to be added.
45884612 */
45894613 public int addWindow (@ NotNull Inventory inventory ) {
4590- if (getTopWindow ().isPresent () || inventoryOpen ) return -1 ;
4614+ if (getTopWindow ().isPresent () || inventoryOpen ) return -1 ;
45914615 Preconditions .checkNotNull (inventory );
45924616 if (this .windows .containsKey (inventory )) {
45934617 return this .windows .get (inventory );
@@ -4605,10 +4629,10 @@ public int addWindow(@NotNull Inventory inventory) {
46054629 this .removeWindow (inventory );
46064630 return -1 ;
46074631 }
4608- for (int index : inventory .getContents ().keySet ()) {
4632+ for (int index : inventory .getContents ().keySet ()) {
46094633 Item item = inventory .getUnclonedItem (index );
4610- if (item instanceof ItemBundle bundle ) {
4611- if (bundle .hasCompoundTag ()) {
4634+ if (item instanceof ItemBundle bundle ) {
4635+ if (bundle .hasCompoundTag ()) {
46124636 bundle .onChange (inventory );
46134637 inventory .sendSlot (index , this );
46144638 }
@@ -4909,14 +4933,21 @@ public Set<Long> getUsedChunks() {
49094933 @ Override
49104934 public void setSprinting (boolean value ) {
49114935 if (value && this .getFreezingTicks () > 0 ) return ;
4936+
49124937 if (isSprinting () != value ) {
49134938 super .setSprinting (value );
4914- this .setMovementSpeed (value ? getMovementSpeed () * 1.3f : getMovementSpeed () / 1.3f );
49154939
4940+ float base = DEFAULT_SPEED ;
4941+ int speedLvl = 0 ;
49164942 if (this .hasEffect (EffectType .SPEED )) {
4917- float movementSpeed = this .getMovementSpeed ();
4918- this .sendMovementSpeed (value ? movementSpeed * 1.3f : movementSpeed );
4943+ speedLvl = this .getEffect (EffectType .SPEED ).getLevel ();
49194944 }
4945+ float effectMul = 1.0f + 0.2f * speedLvl ;
4946+ float sprintMul = value ? 1.3f : 1.0f ;
4947+
4948+ float finalSpeed = base * effectMul * sprintMul ;
4949+
4950+ this .setMovementSpeed (finalSpeed , true );
49204951 }
49214952 }
49224953
0 commit comments