From d9785289ddba6f21bd2f840702f3b91d5a703e2a Mon Sep 17 00:00:00 2001
From: Melledy <121644117+Melledy@users.noreply.github.com>
Date: Thu, 14 Dec 2023 06:22:49 -0800
Subject: [PATCH] Fix debuffs from summoned skills not expiring
---
.../proto/EntityBuffChangeInfoOuterClass.java | 157 +++++++++---------
.../emu/lunarcore/game/player/Player.java | 22 +--
.../java/emu/lunarcore/game/scene/Scene.java | 12 +-
.../emu/lunarcore/game/scene/SceneBuff.java | 4 +
.../game/scene/entity/EntityMonster.java | 30 +++-
.../emu/lunarcore/server/game/GameServer.java | 8 +-
.../emu/lunarcore/server/game/Tickable.java | 7 +
...acketSyncEntityBuffChangeListScNotify.java | 15 +-
8 files changed, 158 insertions(+), 97 deletions(-)
create mode 100644 src/main/java/emu/lunarcore/server/game/Tickable.java
diff --git a/src/generated/main/emu/lunarcore/proto/EntityBuffChangeInfoOuterClass.java b/src/generated/main/emu/lunarcore/proto/EntityBuffChangeInfoOuterClass.java
index f887a1d..948c1f2 100644
--- a/src/generated/main/emu/lunarcore/proto/EntityBuffChangeInfoOuterClass.java
+++ b/src/generated/main/emu/lunarcore/proto/EntityBuffChangeInfoOuterClass.java
@@ -19,9 +19,9 @@ public final class EntityBuffChangeInfoOuterClass {
private static final long serialVersionUID = 0L;
/**
- * optional uint32 CBOEIMDHBIJ = 5;
+ * optional uint32 remove_buff_id = 5;
*/
- private int cBOEIMDHBIJ;
+ private int removeBuffId;
/**
* optional uint32 entity_id = 8;
@@ -29,9 +29,9 @@ public final class EntityBuffChangeInfoOuterClass {
private int entityId;
/**
- * optional .BuffInfo buff_change_info = 4;
+ * optional .BuffInfo add_buff_info = 4;
*/
- private final BuffInfoOuterClass.BuffInfo buffChangeInfo = BuffInfoOuterClass.BuffInfo.newInstance();
+ private final BuffInfoOuterClass.BuffInfo addBuffInfo = BuffInfoOuterClass.BuffInfo.newInstance();
private EntityBuffChangeInfo() {
}
@@ -49,59 +49,59 @@ public final class EntityBuffChangeInfoOuterClass {
public EntityBuffChangeInfo clearInfo() {
if (hasInfo()) {
- clearCBOEIMDHBIJ();
- clearBuffChangeInfo();
+ clearRemoveBuffId();
+ clearAddBuffInfo();
}
return this;
}
- private void clearInfoOtherCBOEIMDHBIJ() {
+ private void clearInfoOtherRemoveBuffId() {
if ((((bitField0_ & 0x00000002)) != 0)) {
- clearBuffChangeInfo();
+ clearAddBuffInfo();
}
}
- private void clearInfoOtherBuffChangeInfo() {
+ private void clearInfoOtherAddBuffInfo() {
if ((((bitField0_ & 0x00000001)) != 0)) {
- clearCBOEIMDHBIJ();
+ clearRemoveBuffId();
}
}
/**
- * optional uint32 CBOEIMDHBIJ = 5;
- * @return whether the cBOEIMDHBIJ field is set
+ * optional uint32 remove_buff_id = 5;
+ * @return whether the removeBuffId field is set
*/
- public boolean hasCBOEIMDHBIJ() {
+ public boolean hasRemoveBuffId() {
return (bitField0_ & 0x00000001) != 0;
}
/**
- * optional uint32 CBOEIMDHBIJ = 5;
+ * optional uint32 remove_buff_id = 5;
* @return this
*/
- public EntityBuffChangeInfo clearCBOEIMDHBIJ() {
+ public EntityBuffChangeInfo clearRemoveBuffId() {
bitField0_ &= ~0x00000001;
- cBOEIMDHBIJ = 0;
+ removeBuffId = 0;
return this;
}
/**
- * optional uint32 CBOEIMDHBIJ = 5;
- * @return the cBOEIMDHBIJ
+ * optional uint32 remove_buff_id = 5;
+ * @return the removeBuffId
*/
- public int getCBOEIMDHBIJ() {
- return cBOEIMDHBIJ;
+ public int getRemoveBuffId() {
+ return removeBuffId;
}
/**
- * optional uint32 CBOEIMDHBIJ = 5;
- * @param value the cBOEIMDHBIJ to set
+ * optional uint32 remove_buff_id = 5;
+ * @param value the removeBuffId to set
* @return this
*/
- public EntityBuffChangeInfo setCBOEIMDHBIJ(final int value) {
- clearInfoOtherCBOEIMDHBIJ();
+ public EntityBuffChangeInfo setRemoveBuffId(final int value) {
+ clearInfoOtherRemoveBuffId();
bitField0_ |= 0x00000001;
- cBOEIMDHBIJ = value;
+ removeBuffId = value;
return this;
}
@@ -143,39 +143,39 @@ public final class EntityBuffChangeInfoOuterClass {
}
/**
- * optional .BuffInfo buff_change_info = 4;
- * @return whether the buffChangeInfo field is set
+ * optional .BuffInfo add_buff_info = 4;
+ * @return whether the addBuffInfo field is set
*/
- public boolean hasBuffChangeInfo() {
+ public boolean hasAddBuffInfo() {
return (bitField0_ & 0x00000002) != 0;
}
/**
- * optional .BuffInfo buff_change_info = 4;
+ * optional .BuffInfo add_buff_info = 4;
* @return this
*/
- public EntityBuffChangeInfo clearBuffChangeInfo() {
+ public EntityBuffChangeInfo clearAddBuffInfo() {
bitField0_ &= ~0x00000002;
- buffChangeInfo.clear();
+ addBuffInfo.clear();
return this;
}
/**
- * optional .BuffInfo buff_change_info = 4;
+ * optional .BuffInfo add_buff_info = 4;
*
* This method returns the internal storage object without modifying any has state.
* The returned object should not be modified and be treated as read-only.
*
- * Use {@link #getMutableBuffChangeInfo()} if you want to modify it.
+ * Use {@link #getMutableAddBuffInfo()} if you want to modify it.
*
* @return internal storage object for reading
*/
- public BuffInfoOuterClass.BuffInfo getBuffChangeInfo() {
- return buffChangeInfo;
+ public BuffInfoOuterClass.BuffInfo getAddBuffInfo() {
+ return addBuffInfo;
}
/**
- * optional .BuffInfo buff_change_info = 4;
+ * optional .BuffInfo add_buff_info = 4;
*
* This method returns the internal storage object and sets the corresponding
* has state. The returned object will become part of this message and its
@@ -183,21 +183,21 @@ public final class EntityBuffChangeInfoOuterClass {
*
* @return internal storage object for modifications
*/
- public BuffInfoOuterClass.BuffInfo getMutableBuffChangeInfo() {
- clearInfoOtherBuffChangeInfo();
+ public BuffInfoOuterClass.BuffInfo getMutableAddBuffInfo() {
+ clearInfoOtherAddBuffInfo();
bitField0_ |= 0x00000002;
- return buffChangeInfo;
+ return addBuffInfo;
}
/**
- * optional .BuffInfo buff_change_info = 4;
- * @param value the buffChangeInfo to set
+ * optional .BuffInfo add_buff_info = 4;
+ * @param value the addBuffInfo to set
* @return this
*/
- public EntityBuffChangeInfo setBuffChangeInfo(final BuffInfoOuterClass.BuffInfo value) {
- clearInfoOtherBuffChangeInfo();
+ public EntityBuffChangeInfo setAddBuffInfo(final BuffInfoOuterClass.BuffInfo value) {
+ clearInfoOtherAddBuffInfo();
bitField0_ |= 0x00000002;
- buffChangeInfo.copyFrom(value);
+ addBuffInfo.copyFrom(value);
return this;
}
@@ -206,9 +206,9 @@ public final class EntityBuffChangeInfoOuterClass {
cachedSize = other.cachedSize;
if ((bitField0_ | other.bitField0_) != 0) {
bitField0_ = other.bitField0_;
- cBOEIMDHBIJ = other.cBOEIMDHBIJ;
+ removeBuffId = other.removeBuffId;
entityId = other.entityId;
- buffChangeInfo.copyFrom(other.buffChangeInfo);
+ addBuffInfo.copyFrom(other.addBuffInfo);
}
return this;
}
@@ -219,14 +219,14 @@ public final class EntityBuffChangeInfoOuterClass {
return this;
}
cachedSize = -1;
- if (other.hasCBOEIMDHBIJ()) {
- setCBOEIMDHBIJ(other.cBOEIMDHBIJ);
+ if (other.hasRemoveBuffId()) {
+ setRemoveBuffId(other.removeBuffId);
}
if (other.hasEntityId()) {
setEntityId(other.entityId);
}
- if (other.hasBuffChangeInfo()) {
- getMutableBuffChangeInfo().mergeFrom(other.buffChangeInfo);
+ if (other.hasAddBuffInfo()) {
+ getMutableAddBuffInfo().mergeFrom(other.addBuffInfo);
}
return this;
}
@@ -238,9 +238,9 @@ public final class EntityBuffChangeInfoOuterClass {
}
cachedSize = -1;
bitField0_ = 0;
- cBOEIMDHBIJ = 0;
+ removeBuffId = 0;
entityId = 0;
- buffChangeInfo.clear();
+ addBuffInfo.clear();
return this;
}
@@ -251,7 +251,7 @@ public final class EntityBuffChangeInfoOuterClass {
}
cachedSize = -1;
bitField0_ = 0;
- buffChangeInfo.clearQuick();
+ addBuffInfo.clearQuick();
return this;
}
@@ -265,16 +265,16 @@ public final class EntityBuffChangeInfoOuterClass {
}
EntityBuffChangeInfo other = (EntityBuffChangeInfo) o;
return bitField0_ == other.bitField0_
- && (!hasCBOEIMDHBIJ() || cBOEIMDHBIJ == other.cBOEIMDHBIJ)
+ && (!hasRemoveBuffId() || removeBuffId == other.removeBuffId)
&& (!hasEntityId() || entityId == other.entityId)
- && (!hasBuffChangeInfo() || buffChangeInfo.equals(other.buffChangeInfo));
+ && (!hasAddBuffInfo() || addBuffInfo.equals(other.addBuffInfo));
}
@Override
public void writeTo(final ProtoSink output) throws IOException {
if ((bitField0_ & 0x00000001) != 0) {
output.writeRawByte((byte) 40);
- output.writeUInt32NoTag(cBOEIMDHBIJ);
+ output.writeUInt32NoTag(removeBuffId);
}
if ((bitField0_ & 0x00000004) != 0) {
output.writeRawByte((byte) 64);
@@ -282,7 +282,7 @@ public final class EntityBuffChangeInfoOuterClass {
}
if ((bitField0_ & 0x00000002) != 0) {
output.writeRawByte((byte) 34);
- output.writeMessageNoTag(buffChangeInfo);
+ output.writeMessageNoTag(addBuffInfo);
}
}
@@ -290,13 +290,13 @@ public final class EntityBuffChangeInfoOuterClass {
protected int computeSerializedSize() {
int size = 0;
if ((bitField0_ & 0x00000001) != 0) {
- size += 1 + ProtoSink.computeUInt32SizeNoTag(cBOEIMDHBIJ);
+ size += 1 + ProtoSink.computeUInt32SizeNoTag(removeBuffId);
}
if ((bitField0_ & 0x00000004) != 0) {
size += 1 + ProtoSink.computeUInt32SizeNoTag(entityId);
}
if ((bitField0_ & 0x00000002) != 0) {
- size += 1 + ProtoSink.computeMessageSizeNoTag(buffChangeInfo);
+ size += 1 + ProtoSink.computeMessageSizeNoTag(addBuffInfo);
}
return size;
}
@@ -309,9 +309,9 @@ public final class EntityBuffChangeInfoOuterClass {
while (true) {
switch (tag) {
case 40: {
- // cBOEIMDHBIJ
- clearInfoOtherCBOEIMDHBIJ();
- cBOEIMDHBIJ = input.readUInt32();
+ // removeBuffId
+ clearInfoOtherRemoveBuffId();
+ removeBuffId = input.readUInt32();
bitField0_ |= 0x00000001;
tag = input.readTag();
if (tag != 64) {
@@ -328,9 +328,9 @@ public final class EntityBuffChangeInfoOuterClass {
}
}
case 34: {
- // buffChangeInfo
- clearInfoOtherBuffChangeInfo();
- input.readMessage(buffChangeInfo);
+ // addBuffInfo
+ clearInfoOtherAddBuffInfo();
+ input.readMessage(addBuffInfo);
bitField0_ |= 0x00000002;
tag = input.readTag();
if (tag != 0) {
@@ -355,13 +355,13 @@ public final class EntityBuffChangeInfoOuterClass {
public void writeTo(final JsonSink output) throws IOException {
output.beginObject();
if ((bitField0_ & 0x00000001) != 0) {
- output.writeUInt32(FieldNames.cBOEIMDHBIJ, cBOEIMDHBIJ);
+ output.writeUInt32(FieldNames.removeBuffId, removeBuffId);
}
if ((bitField0_ & 0x00000004) != 0) {
output.writeUInt32(FieldNames.entityId, entityId);
}
if ((bitField0_ & 0x00000002) != 0) {
- output.writeMessage(FieldNames.buffChangeInfo, buffChangeInfo);
+ output.writeMessage(FieldNames.addBuffInfo, addBuffInfo);
}
output.endObject();
}
@@ -373,11 +373,12 @@ public final class EntityBuffChangeInfoOuterClass {
}
while (!input.isAtEnd()) {
switch (input.readFieldHash()) {
- case 1350914854: {
- if (input.isAtField(FieldNames.cBOEIMDHBIJ)) {
+ case -1339555214:
+ case 927119308: {
+ if (input.isAtField(FieldNames.removeBuffId)) {
if (!input.trySkipNullValue()) {
- clearInfoOtherCBOEIMDHBIJ();
- cBOEIMDHBIJ = input.readUInt32();
+ clearInfoOtherRemoveBuffId();
+ removeBuffId = input.readUInt32();
bitField0_ |= 0x00000001;
}
} else {
@@ -397,12 +398,12 @@ public final class EntityBuffChangeInfoOuterClass {
}
break;
}
- case -731204303:
- case -369384975: {
- if (input.isAtField(FieldNames.buffChangeInfo)) {
+ case 1797813090:
+ case 888334076: {
+ if (input.isAtField(FieldNames.addBuffInfo)) {
if (!input.trySkipNullValue()) {
- clearInfoOtherBuffChangeInfo();
- input.readMessage(buffChangeInfo);
+ clearInfoOtherAddBuffInfo();
+ input.readMessage(addBuffInfo);
bitField0_ |= 0x00000002;
}
} else {
@@ -463,11 +464,11 @@ public final class EntityBuffChangeInfoOuterClass {
* Contains name constants used for serializing JSON
*/
static class FieldNames {
- static final FieldName cBOEIMDHBIJ = FieldName.forField("CBOEIMDHBIJ");
+ static final FieldName removeBuffId = FieldName.forField("removeBuffId", "remove_buff_id");
static final FieldName entityId = FieldName.forField("entityId", "entity_id");
- static final FieldName buffChangeInfo = FieldName.forField("buffChangeInfo", "buff_change_info");
+ static final FieldName addBuffInfo = FieldName.forField("addBuffInfo", "add_buff_info");
}
}
}
diff --git a/src/main/java/emu/lunarcore/game/player/Player.java b/src/main/java/emu/lunarcore/game/player/Player.java
index 4e341cd..9497773 100644
--- a/src/main/java/emu/lunarcore/game/player/Player.java
+++ b/src/main/java/emu/lunarcore/game/player/Player.java
@@ -59,6 +59,7 @@ import emu.lunarcore.proto.SimpleAvatarInfoOuterClass.SimpleAvatarInfo;
import emu.lunarcore.proto.SimpleInfoOuterClass.SimpleInfo;
import emu.lunarcore.server.game.GameServer;
import emu.lunarcore.server.game.GameSession;
+import emu.lunarcore.server.game.Tickable;
import emu.lunarcore.server.packet.BasePacket;
import emu.lunarcore.server.packet.CmdId;
import emu.lunarcore.server.packet.send.*;
@@ -73,7 +74,7 @@ import lombok.Setter;
@Entity(value = "players", useDiscriminator = false)
@Getter
-public class Player {
+public class Player implements Tickable {
@Id private int uid;
@Indexed private String accountUid;
private String name;
@@ -519,27 +520,26 @@ public class Player {
return amount;
}
- private void updateStamina() {
- // Get current timestamp
- long time = System.currentTimeMillis();
+ private void updateStamina(long timestamp) {
+ // Setup on change flag
boolean hasChanged = false;
// Check if we can add stamina
- while (time >= this.nextStaminaRecover) {
+ while (timestamp >= this.nextStaminaRecover) {
// Add stamina
if (this.stamina < GameConstants.MAX_STAMINA) {
this.stamina += 1;
hasChanged = true;
} else if (this.stamina < GameConstants.MAX_STAMINA_RESERVE) {
double rate = LunarCore.getConfig().getServerOptions().getStaminaReserveRecoveryRate();
- double amount = (time - this.nextStaminaRecover) / (rate * 1000D);
+ double amount = (timestamp - this.nextStaminaRecover) / (rate * 1000D);
this.staminaReserve = Math.min(this.staminaReserve + amount, GameConstants.MAX_STAMINA_RESERVE);
hasChanged = true;
}
// Calculate next stamina recover time
if (this.stamina >= GameConstants.MAX_STAMINA) {
- this.nextStaminaRecover = time;
+ this.nextStaminaRecover = timestamp;
}
this.nextStaminaRecover += LunarCore.getConfig().getServerOptions().getStaminaRecoveryRate() * 1000;
@@ -722,12 +722,12 @@ public class Player {
}
}
- public void onTick() {
+ public void onTick(long timestamp, long delta) {
// Update stamina
- this.updateStamina();
+ this.updateStamina(timestamp);
// Scene update
if (this.getScene() != null) {
- this.getScene().onTick();
+ this.getScene().onTick(timestamp, delta);
}
}
@@ -746,7 +746,7 @@ public class Player {
this.getRogueManager().loadFromDatabase();
// Update stamina
- this.updateStamina();
+ this.updateStamina(System.currentTimeMillis());
// Check instances
if (this.getChallengeInstance() != null && !this.getChallengeInstance().validate(this)) {
diff --git a/src/main/java/emu/lunarcore/game/scene/Scene.java b/src/main/java/emu/lunarcore/game/scene/Scene.java
index 3f4f6cc..e632bc1 100644
--- a/src/main/java/emu/lunarcore/game/scene/Scene.java
+++ b/src/main/java/emu/lunarcore/game/scene/Scene.java
@@ -19,6 +19,7 @@ import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
import emu.lunarcore.proto.SceneEntityGroupInfoOuterClass.SceneEntityGroupInfo;
import emu.lunarcore.proto.SceneGroupStateOuterClass.SceneGroupState;
import emu.lunarcore.proto.SceneInfoOuterClass.SceneInfo;
+import emu.lunarcore.server.game.Tickable;
import emu.lunarcore.server.packet.send.PacketActivateFarmElementScRsp;
import emu.lunarcore.server.packet.send.PacketRefreshTriggerByClientScNotify;
import emu.lunarcore.server.packet.send.PacketSceneGroupRefreshScNotify;
@@ -29,7 +30,7 @@ import lombok.Getter;
import us.hebi.quickbuf.RepeatedInt;
@Getter
-public class Scene {
+public class Scene implements Tickable {
private final Player player;
private final MazePlaneExcel excel;
private final FloorInfo floorInfo;
@@ -352,13 +353,20 @@ public class Scene {
// Player events
- public void onTick() {
+ @Override
+ public synchronized void onTick(long timestamp, long delta) {
// Remove summoned unit if it expired
if (this.getPlayerSummon() != null) {
if (this.getPlayerSummon().isExpired()) {
this.removeSummonUnit();
}
}
+ // Tick entities
+ for (GameEntity entity : this.getEntities().values()) {
+ if (entity instanceof Tickable tickableEntity) {
+ tickableEntity.onTick(timestamp, delta);
+ }
+ }
}
public void onBattleStart(Battle battle) {
diff --git a/src/main/java/emu/lunarcore/game/scene/SceneBuff.java b/src/main/java/emu/lunarcore/game/scene/SceneBuff.java
index 9cfb114..dd261d1 100644
--- a/src/main/java/emu/lunarcore/game/scene/SceneBuff.java
+++ b/src/main/java/emu/lunarcore/game/scene/SceneBuff.java
@@ -21,6 +21,10 @@ public class SceneBuff {
this.expiry = this.createTime + duration;
}
+ public boolean isExpired(long timestamp) {
+ return timestamp > this.expiry;
+ }
+
// Serialization
public BuffInfo toProto() {
diff --git a/src/main/java/emu/lunarcore/game/scene/entity/EntityMonster.java b/src/main/java/emu/lunarcore/game/scene/entity/EntityMonster.java
index 16e679b..1dbbe8f 100644
--- a/src/main/java/emu/lunarcore/game/scene/entity/EntityMonster.java
+++ b/src/main/java/emu/lunarcore/game/scene/entity/EntityMonster.java
@@ -10,6 +10,8 @@ import emu.lunarcore.game.scene.triggers.PropTriggerType;
import emu.lunarcore.proto.MotionInfoOuterClass.MotionInfo;
import emu.lunarcore.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import emu.lunarcore.proto.SceneNpcMonsterInfoOuterClass.SceneNpcMonsterInfo;
+import emu.lunarcore.server.game.Tickable;
+import emu.lunarcore.server.packet.send.PacketSyncEntityBuffChangeListScNotify;
import emu.lunarcore.util.Position;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@@ -17,7 +19,7 @@ import lombok.Getter;
import lombok.Setter;
@Getter
-public class EntityMonster implements GameEntity {
+public class EntityMonster implements GameEntity, Tickable {
@Setter private NpcMonsterExcel excel;
@Setter private int entityId;
@Setter private int worldLevel;
@@ -56,7 +58,7 @@ public class EntityMonster implements GameEntity {
}
}
- public SceneBuff addBuff(int caster, int buffId, int duration) {
+ public synchronized SceneBuff addBuff(int caster, int buffId, int duration) {
if (this.buffs == null) {
this.buffs = new Int2ObjectOpenHashMap<>();
}
@@ -69,12 +71,12 @@ public class EntityMonster implements GameEntity {
return buff;
}
- public void applyBuffs(Battle battle) {
+ public synchronized void applyBuffs(Battle battle) {
if (this.buffs == null) return;
for (var entry : this.buffs.int2ObjectEntrySet()) {
// Check expiry for buff
- if (entry.getValue().getExpiry() < battle.getTimestamp()) {
+ if (entry.getValue().isExpired(battle.getTimestamp())) {
continue;
}
@@ -99,6 +101,26 @@ public class EntityMonster implements GameEntity {
// Try to fire any triggers
getScene().invokePropTrigger(PropTriggerType.MONSTER_DIE, this.getGroupId(), this.getInstId());
}
+
+ @Override
+ public synchronized void onTick(long timestamp, long delta) {
+ // Check if we need to remove any buffs
+ if (this.buffs != null && this.buffs.size() > 0) {
+ var it = this.buffs.values().iterator();
+
+ while (it.hasNext()) {
+ var buff = it.next();
+
+ if (buff.isExpired(timestamp)) {
+ // Safely remove from iterator
+ it.remove();
+
+ // Send packet to notify the client that we are removing the buff
+ getScene().getPlayer().sendPacket(new PacketSyncEntityBuffChangeListScNotify(this.getEntityId(), buff.getBuffId()));
+ }
+ }
+ }
+ }
@Override
public SceneEntityInfo toSceneEntityProto() {
diff --git a/src/main/java/emu/lunarcore/server/game/GameServer.java b/src/main/java/emu/lunarcore/server/game/GameServer.java
index 95a4e66..14442dd 100644
--- a/src/main/java/emu/lunarcore/server/game/GameServer.java
+++ b/src/main/java/emu/lunarcore/server/game/GameServer.java
@@ -27,6 +27,7 @@ public class GameServer extends KcpServer {
private final Int2ObjectMap players;
private final Timer gameLoopTimer;
+ private long lastTickTime;
// Managers
@Getter private final GameServerPacketHandler packetHandler;
@@ -56,6 +57,7 @@ public class GameServer extends KcpServer {
this.shopService = new ShopService(this);
// Game loop
+ this.lastTickTime = System.currentTimeMillis();
this.gameLoopTimer = new Timer();
this.gameLoopTimer.scheduleAtFixedRate(new TimerTask() {
@Override
@@ -173,10 +175,14 @@ public class GameServer extends KcpServer {
}
private void onTick() {
+ long timestamp = System.currentTimeMillis();
+ long delta = timestamp - lastTickTime;
+ this.lastTickTime = timestamp;
+
synchronized (this.players) {
for (Player player : this.players.values()) {
try {
- player.onTick();
+ player.onTick(timestamp, delta);
} catch (Exception e) {
LunarCore.getLogger().error("[UID: " + player.getUid() + "] Player tick error: ", e);
}
diff --git a/src/main/java/emu/lunarcore/server/game/Tickable.java b/src/main/java/emu/lunarcore/server/game/Tickable.java
new file mode 100644
index 0000000..65daef6
--- /dev/null
+++ b/src/main/java/emu/lunarcore/server/game/Tickable.java
@@ -0,0 +1,7 @@
+package emu.lunarcore.server.game;
+
+public interface Tickable {
+
+ public void onTick(long timestamp, long delta);
+
+}
diff --git a/src/main/java/emu/lunarcore/server/packet/send/PacketSyncEntityBuffChangeListScNotify.java b/src/main/java/emu/lunarcore/server/packet/send/PacketSyncEntityBuffChangeListScNotify.java
index ec29c7d..42f72e2 100644
--- a/src/main/java/emu/lunarcore/server/packet/send/PacketSyncEntityBuffChangeListScNotify.java
+++ b/src/main/java/emu/lunarcore/server/packet/send/PacketSyncEntityBuffChangeListScNotify.java
@@ -12,7 +12,20 @@ public class PacketSyncEntityBuffChangeListScNotify extends BasePacket {
super(CmdId.SyncEntityBuffChangeListScNotify);
var buffChange = EntityBuffChangeInfo.newInstance().setEntityId(entityId)
- .setBuffChangeInfo(buff.toProto())
+ .setAddBuffInfo(buff.toProto())
+ .setEntityId(entityId);
+
+ var data = SyncEntityBuffChangeListScNotify.newInstance()
+ .addEntityBuffInfoList(buffChange);
+
+ this.setData(data);
+ }
+
+ public PacketSyncEntityBuffChangeListScNotify(int entityId, int removeBuffId) {
+ super(CmdId.SyncEntityBuffChangeListScNotify);
+
+ var buffChange = EntityBuffChangeInfo.newInstance().setEntityId(entityId)
+ .setRemoveBuffId(removeBuffId)
.setEntityId(entityId);
var data = SyncEntityBuffChangeListScNotify.newInstance()