From 4e6e2e678d77f69aeca5b4e260d25a159f5ef747 Mon Sep 17 00:00:00 2001 From: Ceikry Date: Tue, 24 Jan 2023 01:37:39 +0000 Subject: [PATCH] Fixed issue preventing pickup of dwarf remains in Dwarf Cannon Added more sophisticated debug varp printing Fixed issue preventing surprise exam rewards if player moves before reward is granted Voluntarily leaving a clan should now persist Fixed bug that would result in keeping the previous wand when purchasing MTA upgrade Fixed issue preventing proper teleport jewellery usage Fixed a bug that prevented manual casting of Ancient spells Added many sanity checks to death code and fixed a bug with delayed impacts Added dragon slayer requirements to Green (g) and Green (t) bodies Rewrote the "catchup" logic used for growing farming patches during missed playtime Fixed bug preventing fruit trees and berries from growing while logged out Summoning potion now correctly restores 25% of summoning special energy --- .../content/activity/duel/DuelSession.java | 3 +- .../game/content/activity/mta/MTAShop.java | 10 ++++- .../game/content/consumable/Consumables.java | 3 +- .../java/core/game/node/entity/Entity.java | 2 + .../node/entity/combat/ImpactHandler.java | 5 +++ .../java/core/game/node/entity/npc/NPC.java | 5 ++- .../core/game/node/entity/player/Player.java | 5 +-- .../java/core/game/system/task/NodeTask.java | 1 + .../java/core/game/world/map/RegionManager.kt | 9 ++++ Server/src/main/kotlin/api/ContentAPI.kt | 28 +++++++++++-- .../events/supriseexam/SurpriseExamUtils.kt | 3 +- .../consumable/effects/RestoreSummoning.kt | 13 ------ .../effects/RestoreSummoningSpecial.kt | 11 +++++ .../alkharid/AlKharidShopKeeperDialogue.kt | 2 +- .../game/content/global/EnchantedJewellery.kt | 2 +- .../content/global/action/PickupHandler.kt | 5 +-- .../item/ItemQuestRequirementListener.kt | 4 +- .../game/node/entity/combat/CombatPulse.kt | 2 +- .../node/entity/player/info/PlayerMonitor.kt | 13 +++++- .../game/node/entity/skill/farming/Patch.kt | 10 +++++ .../state/newsys/states/FarmingState.kt | 42 +++++++++---------- .../kotlin/rs09/net/packet/PacketProcessor.kt | 8 ++-- .../main/kotlin/rs09/net/packet/in/Login.kt | 3 +- .../kotlin/rs09/worker/ManagementEvents.kt | 1 + 24 files changed, 129 insertions(+), 61 deletions(-) delete mode 100644 Server/src/main/kotlin/rs09/game/content/consumable/effects/RestoreSummoning.kt create mode 100644 Server/src/main/kotlin/rs09/game/content/consumable/effects/RestoreSummoningSpecial.kt diff --git a/Server/src/main/java/core/game/content/activity/duel/DuelSession.java b/Server/src/main/java/core/game/content/activity/duel/DuelSession.java index 7906a540f..dc7bf43d3 100644 --- a/Server/src/main/java/core/game/content/activity/duel/DuelSession.java +++ b/Server/src/main/java/core/game/content/activity/duel/DuelSession.java @@ -17,6 +17,7 @@ import core.plugin.Plugin; import core.tools.RandomFunction; import kotlin.Unit; import rs09.game.content.global.action.EquipHandler; +import rs09.game.node.entity.player.info.LogType; import rs09.game.node.entity.player.info.PlayerMonitor; import rs09.game.system.config.ItemConfigParser; @@ -311,7 +312,7 @@ public final class DuelSession extends ComponentPlugin { log = log.substring(0, log.length() - 1); } log += "}"; - PlayerMonitor.logMisc(player, "Duel", log); + PlayerMonitor.log(player, LogType.DUEL_INFO, log); } else { player.removeExtension(DuelSession.class); } diff --git a/Server/src/main/java/core/game/content/activity/mta/MTAShop.java b/Server/src/main/java/core/game/content/activity/mta/MTAShop.java index e1e744ea6..de454fd4a 100644 --- a/Server/src/main/java/core/game/content/activity/mta/MTAShop.java +++ b/Server/src/main/java/core/game/content/activity/mta/MTAShop.java @@ -1,5 +1,6 @@ package core.game.content.activity.mta; +import api.ContainerisedItem; import core.game.component.CloseEvent; import core.game.component.Component; import core.game.component.ComponentPlugin; @@ -15,6 +16,8 @@ import rs09.game.world.GameWorld; import java.util.ArrayList; import java.util.List; +import static api.ContentAPIKt.hasAnItem; + /** * Represents the mage training arena shop. * @author Vexia @@ -147,9 +150,11 @@ public class MTAShop { player.sendMessage("You already unlocked that spell."); return; } + ContainerisedItem itemToRemove = null; if (slot >= 1 && slot <= 3) { Item required = ITEMS[slot - 1]; - if (!player.hasItem(new Item(required.getId(), 1)) && !player.hasItem(new Item(6914, 1))) { + itemToRemove = hasAnItem(player, required.getId()); + if (!itemToRemove.exists() && !player.hasItem(new Item(6914, 1))) { player.sendMessage("You don't have the required wand in order to buy this upgrade."); return; } @@ -163,7 +168,8 @@ public class MTAShop { player.getSavedData().getActivityData().setBonesToPeaches(true); player.getDialogueInterpreter().sendDialogue("The guardian teaches you how to use the Bones to Peaches spell!"); } else { - player.getInventory().add(item); + if (itemToRemove == null || itemToRemove.remove()) + player.getInventory().add(item); } for (int i = 0; i < prices.length; i++) { decrementPoints(player, i, prices[i]); diff --git a/Server/src/main/java/core/game/content/consumable/Consumables.java b/Server/src/main/java/core/game/content/consumable/Consumables.java index 7c0d325ab..c14e32161 100644 --- a/Server/src/main/java/core/game/content/consumable/Consumables.java +++ b/Server/src/main/java/core/game/content/consumable/Consumables.java @@ -7,6 +7,7 @@ import core.game.world.update.flag.context.Animation; import core.game.content.consumable.effects.*; import core.game.node.entity.skill.Skills; import rs09.game.content.consumable.effects.KegOfBeerEffect; +import rs09.game.content.consumable.effects.RestoreSummoningSpecial; import java.util.HashMap; @@ -321,7 +322,7 @@ public enum Consumables { HUNTER(new Potion(new int[] {9998, 10000, 10002, 10004}, new SkillEffect(Skills.HUNTER, 3, 0))), RESTORE(new Potion(new int[] {2430, 127, 129, 131}, new RestoreEffect(10, 0.3))), SARA_BREW(new Potion(new int[] {6685, 6687, 6689, 6691}, new MultiEffect(new PercentHeal(2, .15), new SkillEffect(Skills.ATTACK, 0, -0.10), new SkillEffect(Skills.STRENGTH, 0, -0.10), new SkillEffect(Skills.MAGIC, 0, -0.10), new SkillEffect(Skills.RANGE, 0, -0.10), new SkillEffect(Skills.DEFENCE, 2, 0.2)))), - SUMMONING(new Potion(new int[] {12140, 12142, 12144, 12146}, new SummoningEffect(7, 0.25))), + SUMMONING(new Potion(new int[] {12140, 12142, 12144, 12146}, new MultiEffect(new RestoreSummoningSpecial(), new SummoningEffect(7, 0.25)))), COMBAT(new Potion(new int[] {9739, 9741, 9743, 9745}, new MultiEffect(new SkillEffect(Skills.STRENGTH, 3, .1), new SkillEffect(Skills.ATTACK, 3, .1)))), ENERGY(new Potion(new int[] {3008, 3010, 3012, 3014}, new MultiEffect(new EnergyEffect(10), new HealingEffect(3)))), FISHING(new Potion(new int[] {2438, 151, 153, 155}, new SkillEffect(Skills.FISHING, 3, 0))), diff --git a/Server/src/main/java/core/game/node/entity/Entity.java b/Server/src/main/java/core/game/node/entity/Entity.java index cc939e4f2..650198e9c 100644 --- a/Server/src/main/java/core/game/node/entity/Entity.java +++ b/Server/src/main/java/core/game/node/entity/Entity.java @@ -338,6 +338,8 @@ public abstract class Entity extends Node { * @param state The battle state. */ public void onImpact(final Entity entity, BattleState state) { + if (DeathTask.isDead(this)) + state.neutralizeHits(); if (properties.isRetaliating() && !properties.getCombatPulse().isAttacking() && !getLocks().isInteractionLocked() && properties.getCombatPulse().getNextAttack() < GameWorld.getTicks()) { if (!getWalkingQueue().hasPath() && !getPulseManager().isMovingPulse() || (this instanceof NPC)) { properties.getCombatPulse().attack(entity); diff --git a/Server/src/main/java/core/game/node/entity/combat/ImpactHandler.java b/Server/src/main/java/core/game/node/entity/combat/ImpactHandler.java index ee9126af5..8a9b1b84e 100644 --- a/Server/src/main/java/core/game/node/entity/combat/ImpactHandler.java +++ b/Server/src/main/java/core/game/node/entity/combat/ImpactHandler.java @@ -138,6 +138,11 @@ public final class ImpactHandler { * @return The impact object created. */ public Impact handleImpact(Entity source, int hit, final CombatStyle style, final BattleState state, HitsplatType type, boolean secondary) { + if (DeathTask.isDead(this.entity)) { + this.entity.getProperties().getCombatPulse().setVictim(null); + this.entity.getProperties().getCombatPulse().stop(); + return null; + } boolean fam = source instanceof Familiar; if (fam) { source = ((Familiar) source).getOwner(); diff --git a/Server/src/main/java/core/game/node/entity/npc/NPC.java b/Server/src/main/java/core/game/node/entity/npc/NPC.java index 0a60ea68e..204700146 100644 --- a/Server/src/main/java/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/java/core/game/node/entity/npc/NPC.java @@ -394,6 +394,8 @@ public class NPC extends Entity { return; } if (respawnTick > GameWorld.getTicks()) { + if (respawnTick - GameWorld.getTicks() == 2) + teleport(getProperties().getSpawnLocation()); return; } if (respawnTick == GameWorld.getTicks()) { @@ -522,9 +524,8 @@ public class NPC extends Entity { GlobalKillCounter.incrementKills(p, originalId); } handleDrops(p, killer); - if (!isRespawn()) { + if (!isRespawn()) clear(); - } killer.dispatch(new NPCKillEvent(this)); } diff --git a/Server/src/main/java/core/game/node/entity/player/Player.java b/Server/src/main/java/core/game/node/entity/player/Player.java index 5f303f03c..72e7e677d 100644 --- a/Server/src/main/java/core/game/node/entity/player/Player.java +++ b/Server/src/main/java/core/game/node/entity/player/Player.java @@ -65,13 +65,12 @@ import proto.management.ClanLeaveNotification; import proto.management.PlayerStatusUpdate; import rs09.GlobalStats; import rs09.ServerConstants; -import rs09.game.Varp; import rs09.game.VarpManager; import rs09.game.node.entity.combat.CombatSwingHandler; import rs09.game.node.entity.combat.equipment.EquipmentDegrader; import rs09.game.node.entity.player.graves.Grave; -import rs09.game.node.entity.player.graves.GraveType; import rs09.game.node.entity.player.graves.GraveController; +import rs09.game.node.entity.player.info.LogType; import rs09.game.node.entity.player.info.PlayerMonitor; import rs09.game.node.entity.player.info.login.PlayerSaver; import rs09.game.node.entity.skill.runecrafting.PouchManager; @@ -654,7 +653,7 @@ public class Player extends Entity { GroundItemManager.create(item, location, killer instanceof Player ? (Player) killer : this); } if (killer instanceof Player) - PlayerMonitor.logMisc((Player) killer, "PK", "Killed " + name + ", who dropped: " + itemsLost); + PlayerMonitor.log((Player) killer, LogType.PK, "Killed " + name + ", who dropped: " + itemsLost); sendMessage(colorize("%RDue to the circumstances of your death, you do not have a grave.")); } diff --git a/Server/src/main/java/core/game/system/task/NodeTask.java b/Server/src/main/java/core/game/system/task/NodeTask.java index 1780d2fdb..72347b8a8 100644 --- a/Server/src/main/java/core/game/system/task/NodeTask.java +++ b/Server/src/main/java/core/game/system/task/NodeTask.java @@ -103,6 +103,7 @@ public abstract class NodeTask { return NodeTask.this.removeFor(s, node, n); } }; + pulse.start(); return pulse; } diff --git a/Server/src/main/java/core/game/world/map/RegionManager.kt b/Server/src/main/java/core/game/world/map/RegionManager.kt index 2727af5f6..cc5ffc2d8 100644 --- a/Server/src/main/java/core/game/world/map/RegionManager.kt +++ b/Server/src/main/java/core/game/world/map/RegionManager.kt @@ -603,8 +603,17 @@ object RegionManager { val it = npcs.iterator() while (it.hasNext()) { val p = it.next() + if(p.properties.teleportLocation != null && !p.properties.teleportLocation.withinMaxnormDistance(n.location, 1)) { + it.remove() + continue + } + if(p.getAttribute("state:death", false)) { + it.remove() + continue + } if(p.isInvisible()) { it.remove() + continue } if(!p.location.withinMaxnormDistance(n.location, 1)) { it.remove() diff --git a/Server/src/main/kotlin/api/ContentAPI.kt b/Server/src/main/kotlin/api/ContentAPI.kt index 285651477..a382ff85b 100644 --- a/Server/src/main/kotlin/api/ContentAPI.kt +++ b/Server/src/main/kotlin/api/ContentAPI.kt @@ -55,6 +55,8 @@ import rs09.game.content.global.shops.Shops import rs09.game.ge.GrandExchangeRecords import rs09.game.interaction.InteractionListeners import rs09.game.interaction.inter.ge.StockMarket +import rs09.game.node.entity.player.info.LogType +import rs09.game.node.entity.player.info.PlayerMonitor import rs09.game.node.entity.skill.slayer.SlayerManager import rs09.game.system.SystemLogger import rs09.game.system.config.ItemConfigParser @@ -164,7 +166,14 @@ fun areAnyEquipped(player: Player, vararg ids: Int): Boolean { } } -data class ContainerisedItem(val container: core.game.container.Container?, val itemId: Int) +class ContainerisedItem(val container: core.game.container.Container?, val itemId: Int) { + fun remove() : Boolean { + return this.container?.remove(this.itemId.asItem()) ?: false + } + fun exists() : Boolean { + return this.container != null && this.itemId > -1 + } +} /** * Check if player has any of the specified item IDs equipped, in inventory, or in banks @@ -239,14 +248,27 @@ fun addItem(player: Player, id: Int, amount: Int = 1, container: Container = Con * @param container the Container to modify * @return the item that was previously in the slot, or null if none. */ -fun replaceSlot(player: Player, slot: Int, item: Item, container: Container = Container.INVENTORY): Item? { +fun replaceSlot(player: Player, slot: Int, item: Item, currentItem: Item? = null, container: Container = Container.INVENTORY): Item? { val cont = when (container) { Container.INVENTORY -> player.inventory Container.EQUIPMENT -> player.equipment Container.BANK -> player.bank } - return cont.replace(item, slot) + if (currentItem == null) { + return cont.replace(item, slot) + } + + if (cont.remove(currentItem)) + return cont.replace(item, slot) + PlayerMonitor.log(player, LogType.DUPE_ALERT, "Potential slot-replacement-based dupe attempt, slot: $slot, item: $item") + val other = when (container) { + Container.INVENTORY -> Container.EQUIPMENT + else -> Container.INVENTORY + } + if (removeItem(player, currentItem, other)) + return cont.replace(item, slot) + return null } /** diff --git a/Server/src/main/kotlin/rs09/game/content/ame/events/supriseexam/SurpriseExamUtils.kt b/Server/src/main/kotlin/rs09/game/content/ame/events/supriseexam/SurpriseExamUtils.kt index a9a512f4c..86f8892bc 100644 --- a/Server/src/main/kotlin/rs09/game/content/ame/events/supriseexam/SurpriseExamUtils.kt +++ b/Server/src/main/kotlin/rs09/game/content/ame/events/supriseexam/SurpriseExamUtils.kt @@ -1,6 +1,7 @@ package rs09.game.content.ame.events.supriseexam import api.* +import core.game.node.entity.impl.PulseType import core.game.node.entity.player.Player import core.game.node.item.GroundItemManager import core.game.node.item.Item @@ -51,7 +52,7 @@ object SurpriseExamUtils { } return true } - }) + }, PulseType.CUSTOM_1) } fun generateInterface(player: Player){ diff --git a/Server/src/main/kotlin/rs09/game/content/consumable/effects/RestoreSummoning.kt b/Server/src/main/kotlin/rs09/game/content/consumable/effects/RestoreSummoning.kt deleted file mode 100644 index aa48b16a8..000000000 --- a/Server/src/main/kotlin/rs09/game/content/consumable/effects/RestoreSummoning.kt +++ /dev/null @@ -1,13 +0,0 @@ -package rs09.game.content.consumable.effects - -import core.game.node.entity.player.Player -import core.game.content.consumable.ConsumableEffect -import core.game.node.entity.skill.Skills - -class RestoreSummoning(val percent: Double) : ConsumableEffect(){ - override fun activate(p: Player?) { - var amt = (p!!.skills!!.getStaticLevel(Skills.SUMMONING) * percent).toInt() - if(amt + p.skills.getLevel(Skills.SUMMONING) > p.skills.getStaticLevel(Skills.SUMMONING)) amt = p.skills.getStaticLevel(Skills.SUMMONING) - p.skills.getLevel(Skills.SUMMONING) - p.skills.setLevel(Skills.SUMMONING, p.skills.getLevel(Skills.SUMMONING) + amt) - } -} \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/content/consumable/effects/RestoreSummoningSpecial.kt b/Server/src/main/kotlin/rs09/game/content/consumable/effects/RestoreSummoningSpecial.kt new file mode 100644 index 000000000..491d55a1a --- /dev/null +++ b/Server/src/main/kotlin/rs09/game/content/consumable/effects/RestoreSummoningSpecial.kt @@ -0,0 +1,11 @@ +package rs09.game.content.consumable.effects + +import core.game.content.consumable.ConsumableEffect +import core.game.node.entity.player.Player + +class RestoreSummoningSpecial : ConsumableEffect(){ + override fun activate(p: Player) { + val f = p.familiarManager.familiar + f?.updateSpecialPoints(-15) + } +} \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/content/dialogue/region/alkharid/AlKharidShopKeeperDialogue.kt b/Server/src/main/kotlin/rs09/game/content/dialogue/region/alkharid/AlKharidShopKeeperDialogue.kt index b67679281..02bfeb758 100644 --- a/Server/src/main/kotlin/rs09/game/content/dialogue/region/alkharid/AlKharidShopKeeperDialogue.kt +++ b/Server/src/main/kotlin/rs09/game/content/dialogue/region/alkharid/AlKharidShopKeeperDialogue.kt @@ -14,7 +14,7 @@ import rs09.tools.END_DIALOGUE */ @Initializable -class AlKharidShopKeeperDialogue(player: Player? = null) : DialoguePlugin() { +class AlKharidShopKeeperDialogue(player: Player? = null) : DialoguePlugin(player) { override fun newInstance(player: Player?): DialoguePlugin { return AlKharidShopKeeperDialogue(player) } diff --git a/Server/src/main/kotlin/rs09/game/content/global/EnchantedJewellery.kt b/Server/src/main/kotlin/rs09/game/content/global/EnchantedJewellery.kt index c5e879f32..c91d84341 100644 --- a/Server/src/main/kotlin/rs09/game/content/global/EnchantedJewellery.kt +++ b/Server/src/main/kotlin/rs09/game/content/global/EnchantedJewellery.kt @@ -249,7 +249,7 @@ enum class EnchantedJewellery( private fun replaceJewellery(player: Player, item: Item, nextJewellery: Item, isEquipped: Boolean) { if (isEquipped) { - replaceSlot(player, item.slot, nextJewellery, Container.EQUIPMENT) + replaceSlot(player, item.slot, nextJewellery, item, Container.EQUIPMENT) } else { replaceSlot(player, item.slot, nextJewellery) } diff --git a/Server/src/main/kotlin/rs09/game/content/global/action/PickupHandler.kt b/Server/src/main/kotlin/rs09/game/content/global/action/PickupHandler.kt index 32d2f5118..8ec35a606 100644 --- a/Server/src/main/kotlin/rs09/game/content/global/action/PickupHandler.kt +++ b/Server/src/main/kotlin/rs09/game/content/global/action/PickupHandler.kt @@ -6,14 +6,13 @@ import core.game.content.dialogue.FacialExpression import core.game.content.global.GodType import core.game.node.entity.player.Player import core.game.node.entity.player.link.audio.Audio -import core.game.node.entity.player.link.diary.DiaryType import core.game.node.entity.skill.runecrafting.RunePouch import core.game.node.item.GroundItem import core.game.node.item.GroundItemManager import core.game.node.item.Item import core.game.world.map.RegionManager import core.game.world.update.flag.context.Animation -import org.rs09.consts.Items +import rs09.game.node.entity.player.info.LogType import rs09.game.node.entity.player.info.PlayerMonitor import rs09.game.system.SystemLogger import rs09.game.system.config.GroundSpawnLoader @@ -58,7 +57,7 @@ object PickupHandler { } if (item.isActive && player.inventory.add(add)) { if (item.dropper is Player && item.dropper.details.uid != player.details.uid){ - PlayerMonitor.logMisc(item.dropper, "DropTrade", "${getItemName(item.id)} x${item.amount} picked up by ${player.name}.") + PlayerMonitor.log(item.dropper, LogType.DROP_TRADE, "${getItemName(item.id)} x${item.amount} picked up by ${player.name}.") } if (!RegionManager.isTeleportPermitted(item.location)) { player.animate(Animation.create(535)) diff --git a/Server/src/main/kotlin/rs09/game/interaction/item/ItemQuestRequirementListener.kt b/Server/src/main/kotlin/rs09/game/interaction/item/ItemQuestRequirementListener.kt index 4d0f49d3f..2dd206daf 100644 --- a/Server/src/main/kotlin/rs09/game/interaction/item/ItemQuestRequirementListener.kt +++ b/Server/src/main/kotlin/rs09/game/interaction/item/ItemQuestRequirementListener.kt @@ -83,7 +83,9 @@ class ItemQuestRequirementListener : InteractionListener { Items.ZAMORAK_PLATEBODY_2653, Items.SARADOMIN_PLATEBODY_2661, Items.GUTHIX_PLATEBODY_2669, - Items.GREEN_DHIDE_BODY_1135 + Items.GREEN_DHIDE_BODY_1135, + Items.DHIDE_BODYG_7370, //Green (g) + Items.DHIDE_BODY_T_7372 //Green (t) ) private val questCapes = intArrayOf(9813,9814) diff --git a/Server/src/main/kotlin/rs09/game/node/entity/combat/CombatPulse.kt b/Server/src/main/kotlin/rs09/game/node/entity/combat/CombatPulse.kt index 58ccb9d39..3c7356293 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/combat/CombatPulse.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/combat/CombatPulse.kt @@ -437,7 +437,7 @@ class CombatPulse( GameWorld.Pulser.submit(object : Pulse(delay - 1, entity, victim) { var impact = false override fun pulse(): Boolean { - if (DeathTask.isDead(victim)) { + if (DeathTask.isDead(victim) || DeathTask.isDead(entity)) { return true } if (impact || getDelay() == 0) { diff --git a/Server/src/main/kotlin/rs09/game/node/entity/player/info/PlayerMonitor.kt b/Server/src/main/kotlin/rs09/game/node/entity/player/info/PlayerMonitor.kt index 63ecac0c8..d5a6c3880 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/player/info/PlayerMonitor.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/player/info/PlayerMonitor.kt @@ -81,11 +81,11 @@ object PlayerMonitor { dispatch(event) } - @JvmStatic fun logMisc(player: Player, type: String, details: String) { + @JvmStatic fun log(player: Player, type: LogType, details: String) { val event = LogEvent.MiscLog( player.name, player.details.uid, - type, + type.token, details, System.currentTimeMillis() ) @@ -253,4 +253,13 @@ object PlayerMonitor { private const val MISC_LOG_INSERT = "INSERT INTO misc_logs(player,uid,type,details,timestamp) VALUES (?,?,?,?,?);" private const val WEALTH_LOG_INSERT = "INSERT INTO wealth_logs(player,uid,total,diff,timestamp) VALUES (?,?,?,?,?);" +} + +enum class LogType(val token: String) { + DUPE_ALERT("dupe_warning"), + DUEL_INFO("Duel"), + PK("PK"), + DROP_TRADE("DropTrade"), + COMMAND("CommandUsed"), + IP_LOG("login_ip") } \ No newline at end of file diff --git a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt index dfa79ead6..fc1bc6f6c 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/skill/farming/Patch.kt @@ -317,6 +317,16 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl return getCurrentState() - plantable!!.value - plantable!!.stages } + fun getStageGrowthMinutes() : Int { + var minutes = patch.type.stageGrowthTime + if(patch.type == PatchType.FRUIT_TREE && isGrown()) { + // Fruit trees take 160 minutes per stage to grow, but + // restocking their fruit should take 40 minutes per fruit + minutes = 40 + } + return minutes + } + fun isFlowerProtected(): Boolean{ if(patch.type != PatchType.ALLOTMENT) return false diff --git a/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/FarmingState.kt b/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/FarmingState.kt index 02abb37af..1784eae2c 100644 --- a/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/FarmingState.kt +++ b/Server/src/main/kotlin/rs09/game/node/entity/state/newsys/states/FarmingState.kt @@ -1,5 +1,6 @@ package rs09.game.node.entity.state.newsys.states +import core.Util.clamp import core.game.node.entity.player.Player import core.game.system.task.Pulse import kotlinx.coroutines.GlobalScope @@ -101,20 +102,6 @@ class FarmingState(player: Player? = null) : State(player) { patch.compost = CompostType.values()[compostOrdinal] patch.protectionPaid = protectionPaid patch.setCurrentState(savedState) - if((patch.currentGrowthStage < patch.plantable?.stages ?: 0) && !patch.isWeedy()){ - val startTime = (patch.nextGrowth - TimeUnit.MINUTES.toMillis(patch.patch.type.stageGrowthTime * (patch.currentGrowthStage + 1).toLong())) - var expectedStage = Math.floor((System.currentTimeMillis() - startTime.toDouble()) / TimeUnit.MINUTES.toMillis(patch.patch.type.stageGrowthTime.toLong())).toInt() - SystemLogger.logErr(this::class.java, "$expectedStage $startTime ${System.currentTimeMillis()}") - - if(!patchDiseased && !patchDead) { - if (expectedStage > patch.plantable?.stages ?: 0) { - expectedStage = patch.plantable?.stages ?: 0 - } - for(i in 0 until (expectedStage - patch.currentGrowthStage)){ - patch.update() - } - } - } if((savedState - (patch?.plantable?.value ?: 0)) > patch.currentGrowthStage){ patch.setCurrentState(savedState) @@ -122,6 +109,25 @@ class FarmingState(player: Player? = null) : State(player) { patch.setCurrentState((patch.plantable?.value ?: 0) + patch.currentGrowthStage) } + val type = patch.patch.type + val shouldPlayCatchup = !patch.isGrown() || (type == PatchType.BUSH && patch.getFruitOrBerryCount() < 4) || (type == PatchType.FRUIT_TREE && patch.getFruitOrBerryCount() < 6) + if(shouldPlayCatchup && patch.plantable != null && !patchDead){ + var stagesToSimulate = if (!patch.isGrown()) patch.plantable!!.stages - patch.currentGrowthStage else 0 + if (type == PatchType.BUSH) + stagesToSimulate += Math.min(4, 4 - patch.getFruitOrBerryCount()) + if (type == PatchType.FRUIT_TREE) + stagesToSimulate += Math.min(6, 6 - patch.getFruitOrBerryCount()) + + val nowTime = System.currentTimeMillis() + var simulatedTime = patch.nextGrowth + + while (simulatedTime < nowTime && stagesToSimulate-- > 0 && !patch.isDead) { + val timeToIncrement = TimeUnit.MINUTES.toMillis(patch.getStageGrowthMinutes().toLong()) + patch.update() + simulatedTime += timeToIncrement + } + } + if(patchMap[fPatch] == null) { patchMap[fPatch] = patch } @@ -148,13 +154,7 @@ class FarmingState(player: Player? = null) : State(player) { if(patch.nextGrowth < System.currentTimeMillis() && !patch.isDead){ patch.update() - var minutes = patch.patch.type.stageGrowthTime.toLong() - if(patch.patch.type == PatchType.FRUIT_TREE && patch.isGrown()) { - // Fruit trees take 160 minutes per stage to grow, but - // restocking their fruit should take 40 minutes per fruit - minutes = 40 - } - patch.nextGrowth = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(minutes) + patch.nextGrowth = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(patch.getStageGrowthMinutes().toLong()) } } diff --git a/Server/src/main/kotlin/rs09/net/packet/PacketProcessor.kt b/Server/src/main/kotlin/rs09/net/packet/PacketProcessor.kt index 48da3cddf..494b466ef 100644 --- a/Server/src/main/kotlin/rs09/net/packet/PacketProcessor.kt +++ b/Server/src/main/kotlin/rs09/net/packet/PacketProcessor.kt @@ -38,7 +38,6 @@ import core.net.amsc.MSPacketRepository import core.net.packet.PacketRepository import core.net.packet.context.PlayerContext import core.net.packet.out.ClearMinimapFlag -import discord.Discord import org.rs09.consts.Components import proto.management.ClanMessage import proto.management.JoinClanRequest @@ -53,6 +52,7 @@ import rs09.game.interaction.InteractionListeners import rs09.game.interaction.InterfaceListeners import rs09.game.interaction.QCRepository import rs09.game.interaction.inter.ge.StockMarket +import rs09.game.node.entity.player.info.LogType import rs09.game.node.entity.player.info.PlayerMonitor import rs09.game.node.entity.skill.magic.SpellListener import rs09.game.node.entity.skill.magic.SpellListeners @@ -199,7 +199,7 @@ object PacketProcessor { pkt.player.interfaceManager.closeChatbox() } is Packet.Command -> { - PlayerMonitor.logMisc(pkt.player, "CommandUse", pkt.commandLine) + PlayerMonitor.log(pkt.player, LogType.COMMAND, pkt.commandLine) CommandSystem.commandSystem.parse(pkt.player, pkt.commandLine) } is Packet.ChatMessage -> { @@ -404,7 +404,7 @@ object PacketProcessor { if (book != "none") SpellListeners.run(child, type, book, player, target) when (iface) { - 430,192 -> MagicSpell.castSpell(player, SpellBookManager.SpellBook.forInterface(iface), child, target) + 430,192,193 -> MagicSpell.castSpell(player, SpellBookManager.SpellBook.forInterface(iface), child, target) 662 -> { if (player.familiarManager.hasFamiliar()) player.familiarManager.familiar.executeSpecialMove(FamiliarSpecial(target, iface, child, target as? Item)) @@ -664,7 +664,7 @@ object PacketProcessor { player.debug("ID: ${wrapperChild.id}, Option: ${option.name}[${option.index}]") player.debug("Loc: ${scenery.location}, Dir: ${scenery.direction}") if (hasWrapper) { - player.debug("WrapperID: ${scenery.id}, Varbit: ${scenery.definition.configFile.id}") + player.debug("WrapperID: ${scenery.id}, ${scenery.definition.configFile?.let { "Varbit: ${it.id}"} ?: "Varp: ${scenery.definition.configId}"}") } player.debug("------------------------------------------------") diff --git a/Server/src/main/kotlin/rs09/net/packet/in/Login.kt b/Server/src/main/kotlin/rs09/net/packet/in/Login.kt index 080d3e07a..66f26a8ab 100644 --- a/Server/src/main/kotlin/rs09/net/packet/in/Login.kt +++ b/Server/src/main/kotlin/rs09/net/packet/in/Login.kt @@ -19,6 +19,7 @@ import rs09.ServerStore import rs09.ServerStore.Companion.addToList import rs09.ServerStore.Companion.getList import rs09.auth.AuthResponse +import rs09.game.node.entity.player.info.LogType import rs09.game.node.entity.player.info.PlayerMonitor import rs09.game.node.entity.player.info.login.LoginParser import rs09.game.system.SystemLogger @@ -132,7 +133,7 @@ object Login { } val player = Player(details) - PlayerMonitor.logMisc(player, "login_ip", details.ipAddress) + PlayerMonitor.log(player, LogType.IP_LOG, details.ipAddress) if (canBypassAccountLimitCheck(player)) { proceedWithAcceptableLogin(session, player, opcode) } else { diff --git a/Server/src/main/kotlin/rs09/worker/ManagementEvents.kt b/Server/src/main/kotlin/rs09/worker/ManagementEvents.kt index 3173316ec..1ee764f80 100644 --- a/Server/src/main/kotlin/rs09/worker/ManagementEvents.kt +++ b/Server/src/main/kotlin/rs09/worker/ManagementEvents.kt @@ -223,6 +223,7 @@ object ManagementEvents { sendMessage(p, "Error leaving clan. Please relog.") } else { clan.leave(p, true) + p.details.communication.clan = null } }