diff --git a/Server/src/main/content/global/bots/DoublingMoney.kt b/Server/src/main/content/global/bots/DoublingMoney.kt index c230879ea..785fd8690 100644 --- a/Server/src/main/content/global/bots/DoublingMoney.kt +++ b/Server/src/main/content/global/bots/DoublingMoney.kt @@ -9,7 +9,7 @@ import core.game.node.item.Item import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.update.flag.context.ChatMessage -import core.game.world.update.flag.player.ChatFlag +import core.game.world.update.flag.* import core.integrations.discord.Discord import org.json.simple.JSONArray import org.json.simple.JSONObject @@ -132,14 +132,14 @@ class DoublingMoney : Script() { val message = arrayOf("Doubling Money", "Doubling Money", "Doubling Money!", "Doubling moneyy").random() val messageEffect = arrayOf(0, 256).random() val ctx = ChatMessage(bot, message, messageEffect, message.length) - bot.updateMasks.register(ChatFlag(ctx)) + bot.updateMasks.register(EntityFlag.Chat, ctx) sleepTime = 8 } Effort.VERY_HIGH -> { val message = arrayOf("Doubling money!", "Doubling money").random() val messageEffect = arrayOf(771, 2818, 2562, 768, 512, 2304, 2560, 769, 1792).random() val ctx = ChatMessage(bot, message, messageEffect, message.length) - bot.updateMasks.register(ChatFlag(ctx)) + bot.updateMasks.register(EntityFlag.Chat, ctx) sleepTime = 9 } } @@ -198,7 +198,7 @@ class DoublingMoney : Script() { if (botTradeModule.getInterface() == TradeModule.ACCEPT_INTERFACE && coinsFromBot > 0 && effort == Effort.VERY_HIGH) { val message = "Payed ${(if (coinsFromBot < 1000) "${coinsFromBot}gp" else "${coinsFromBot / 1000}k")}" val ctx = ChatMessage(bot, message, 512, message.length) - bot.updateMasks.register(ChatFlag(ctx)) + bot.updateMasks.register(EntityFlag.Chat, ctx) sleepTime = 7 } @@ -325,7 +325,7 @@ class DoublingMoney : Script() { if (effort == Effort.VERY_HIGH) { val message = "Received ${(if (coins.amount < 1000) "${coins.amount}gp" else "${coins.amount / 1000}k")}" val ctx = ChatMessage(bot, message, 256, message.length) - bot.updateMasks.register(ChatFlag(ctx)) + bot.updateMasks.register(EntityFlag.Chat, ctx) } } diff --git a/Server/src/main/content/global/skill/agility/shortcuts/BasaltRockShortcut.kt b/Server/src/main/content/global/skill/agility/shortcuts/BasaltRockShortcut.kt index 793374a05..e0c1adba1 100644 --- a/Server/src/main/content/global/skill/agility/shortcuts/BasaltRockShortcut.kt +++ b/Server/src/main/content/global/skill/agility/shortcuts/BasaltRockShortcut.kt @@ -9,7 +9,6 @@ import core.game.system.task.Pulse import core.game.world.GameWorld import core.game.world.map.Location import core.game.world.update.flag.context.Animation -import core.game.world.update.flag.player.FaceLocationFlag import core.plugin.Initializable import core.plugin.Plugin @@ -136,7 +135,7 @@ class BasaltRockShortcut : AgilityShortcut { player.sendMessage(noJump) } else { player.lock(3) - player.faceLocation(FaceLocationFlag.getFaceLocation(player, Location.create(2518, 3611, 0))) + player.faceLocation(Location.create(2518, 3611, 0)) AgilityHandler.forceWalk(player, -1, Location.create(2516, 3611, 0), Location.create(2518, 3611, 0), Animation.create(769), 20, 0.0, null, 1) } return true @@ -147,7 +146,7 @@ class BasaltRockShortcut : AgilityShortcut { player.sendMessage(noJump) } else { player.lock(3) - player.faceLocation(FaceLocationFlag.getFaceLocation(player, Location.create(2516, 3611, 0))) + player.faceLocation(Location.create(2516, 3611, 0)) AgilityHandler.forceWalk(player, -1, Location.create(2518, 3611, 0), Location.create(2516, 3611, 0), Animation.create(769), 20, 0.0, null, 1) } return true @@ -199,4 +198,4 @@ class BasaltRockShortcut : AgilityShortcut { } }) } -} \ No newline at end of file +} diff --git a/Server/src/main/content/global/skill/firemaking/FireMakingPulse.java b/Server/src/main/content/global/skill/firemaking/FireMakingPulse.java index 6da6f4327..0f8ae1a66 100644 --- a/Server/src/main/content/global/skill/firemaking/FireMakingPulse.java +++ b/Server/src/main/content/global/skill/firemaking/FireMakingPulse.java @@ -12,7 +12,6 @@ import core.game.node.scenery.SceneryBuilder; import core.game.world.GameWorld; import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; -import core.game.world.update.flag.player.FaceLocationFlag; import core.tools.RandomFunction; /** @@ -129,7 +128,7 @@ public final class FireMakingPulse extends SkillPulse { SceneryBuilder.add(object, fire.getLife(), getAsh(player, fire, object)); GroundItemManager.destroy(groundItem); player.moveStep(); - player.faceLocation(FaceLocationFlag.getFaceLocation(player, object)); + player.faceLocation(object.getFaceLocation(player.getLocation())); player.getSkills().addExperience(Skills.FIREMAKING,fire.getXp()); int playerRegion = player.getViewport().getRegion().getId(); @@ -191,4 +190,4 @@ public final class FireMakingPulse extends SkillPulse { } return false; } -} \ No newline at end of file +} diff --git a/Server/src/main/content/global/skill/summoning/familiar/FamiliarNPCOptionPlugin.java b/Server/src/main/content/global/skill/summoning/familiar/FamiliarNPCOptionPlugin.java index cbaf1aa92..6801931b9 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/FamiliarNPCOptionPlugin.java +++ b/Server/src/main/content/global/skill/summoning/familiar/FamiliarNPCOptionPlugin.java @@ -4,7 +4,6 @@ import core.cache.def.impl.NPCDefinition; import core.game.interaction.OptionHandler; import core.game.node.Node; import core.game.node.entity.player.Player; -import core.game.world.update.flag.player.FaceLocationFlag; import core.plugin.Initializable; import core.plugin.Plugin; @@ -39,7 +38,7 @@ public final class FamiliarNPCOptionPlugin extends OptionHandler { } switch (option) { case "pick-up": - player.faceLocation(FaceLocationFlag.getFaceLocation(player, familiar)); + player.faceLocation(familiar.getFaceLocation(player.getLocation())); player.getFamiliarManager().pickup(); break; case "interact-with": diff --git a/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java b/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java index fddb9af88..3c560fc41 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/ForgeRegentNPC.java @@ -12,7 +12,6 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; -import core.game.world.update.flag.player.FaceLocationFlag; import core.plugin.Initializable; import core.plugin.Plugin; import core.plugin.ClassScanner; @@ -153,7 +152,7 @@ public class ForgeRegentNPC extends Familiar { familiar.moveStep(); GroundItemManager.destroy(ground); player.getSkills().addExperience(Skills.FIREMAKING, log.getXp() + 10); - familiar.faceLocation(FaceLocationFlag.getFaceLocation(familiar, object)); + familiar.faceLocation(object.getFaceLocation(familiar.getLocation())); SceneryBuilder.add(object, log.getLife(), FireMakingPulse.getAsh(player, log, object)); if (player.getViewport().getRegion().getId() == 10806) { player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 9); diff --git a/Server/src/main/content/global/skill/summoning/familiar/PyreLordNPC.java b/Server/src/main/content/global/skill/summoning/familiar/PyreLordNPC.java index 46f4b2aaf..c4672b643 100644 --- a/Server/src/main/content/global/skill/summoning/familiar/PyreLordNPC.java +++ b/Server/src/main/content/global/skill/summoning/familiar/PyreLordNPC.java @@ -21,7 +21,6 @@ import core.game.world.GameWorld; import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; -import core.game.world.update.flag.player.FaceLocationFlag; import core.plugin.Plugin; import core.plugin.ClassScanner; @@ -132,7 +131,7 @@ public class PyreLordNPC extends Familiar { familiar.moveStep(); GroundItemManager.destroy(ground); player.getSkills().addExperience(Skills.FIREMAKING, log.getXp() + 10); - familiar.faceLocation(FaceLocationFlag.getFaceLocation(familiar, object)); + familiar.faceLocation(object.getFaceLocation(familiar.getLocation())); SceneryBuilder.add(object, log.getLife(), FireMakingPulse.getAsh(player, log, object)); if (player.getViewport().getRegion().getId() == 10806) { player.getAchievementDiaryManager().finishTask(player, DiaryType.SEERS_VILLAGE, 1, 9); diff --git a/Server/src/main/content/minigame/puropuro/PuroPuroPlugin.java b/Server/src/main/content/minigame/puropuro/PuroPuroPlugin.java index 08a535fed..81651326d 100644 --- a/Server/src/main/content/minigame/puropuro/PuroPuroPlugin.java +++ b/Server/src/main/content/minigame/puropuro/PuroPuroPlugin.java @@ -38,6 +38,7 @@ import core.tools.RandomFunction; import static core.api.ContentAPIKt.animateScenery; import static core.api.ContentAPIKt.submitWorldPulse; import static core.api.ContentAPIKt.animationDuration; +import static core.api.ContentAPIKt.forceMove; /** * Handles the puro puro activity. @@ -161,13 +162,7 @@ public final class PuroPuroPlugin extends MapZone implements Plugin { player.sendMessage("You use your strength to push through the wheat. It's hard work though."); } player.setAttribute("cantMove", true); - GameWorld.getPulser().submit(new Pulse(1) { - @Override - public boolean pulse() { - ForceMovement.run(player, player.getLocation(), dest, Animation.create(6594), Animation.create(6594), Direction.getLogicalDirection(player.getLocation(), object.getLocation()), 3, 3); - return true; - } - }); + forceMove(player, player.getLocation(), dest, 0, 265, null, 6595, null); } /** diff --git a/Server/src/main/content/region/kandarin/quest/tree/TreeGnomeVillageListeners.kt b/Server/src/main/content/region/kandarin/quest/tree/TreeGnomeVillageListeners.kt index f3d6254d6..c753602c1 100644 --- a/Server/src/main/content/region/kandarin/quest/tree/TreeGnomeVillageListeners.kt +++ b/Server/src/main/content/region/kandarin/quest/tree/TreeGnomeVillageListeners.kt @@ -85,22 +85,7 @@ class TreeGnomeVillageListeners : InteractionListener { return@on true } on(looseRailing, IntType.SCENERY, "squeeze-through"){ player, _ -> - if(player.location != location(2516,3161,0)) { - squeezeThrough(player) - } else { - player.pulseManager.run(object : Pulse(0) { - var count = 0 - override fun pulse(): Boolean { - when (count) { - 0 -> ForceMovement.run(player,player.location,player.location.transform(Direction.WEST,1)) - 2 -> squeezeThrough(player) - 3 -> return true - } - count++ - return false - } - }) - } + squeezeThrough(player) return@on true } on(crumbledWall, IntType.SCENERY, "climb-over"){ player, _ -> @@ -132,71 +117,55 @@ class TreeGnomeVillageListeners : InteractionListener { return@on true } } -} -fun squeezeThrough(player: Player){ - val squeezeAnim = Animation.create(3844) - if(player.location.y >= 3161) { - AgilityHandler.forceWalk( - player, - -1, - player.location, - player.location.transform(Direction.SOUTH, 1), - squeezeAnim, - 5, - 0.0, - null - ) - } else { - AgilityHandler.forceWalk( - player, - -1, - player.location, - player.location.transform(Direction.NORTH, 1), - squeezeAnim, - 5, - 0.0, - null - ) + fun squeezeThrough(player: Player){ + val squeezeAnim = Animation.create(3844) + + var dest = if (player.location.y >= 3161) + player.location.transform(Direction.SOUTH, 1) + else + player.location.transform(Direction.NORTH, 1) + + forceMove(player, player.location, dest, 0, 80, anim = 3844) } -} -private class ClimbWall : DialogueFile() { - val climbAnimation = Animation(839) - val wallLoc = Location(2509,3253,0) - override fun handle(componentID: Int, buttonID: Int) { - if(questStage(player!!, TreeGnomeVillage.questName) > 30){ - val northSouth = if (player!!.location.y <= wallLoc.y) Direction.NORTH else Direction.SOUTH - when(stage){ - 0 -> sendDialogue(player!!,"The wall has been reduced to rubble. It should be possible to climb over the remains").also{ stage++ } - 1 -> AgilityHandler.forceWalk(player!!, -1, player!!.location, player!!.location.transform(northSouth, 2), climbAnimation, 20, 0.0, null).also { - end() - if(northSouth == Direction.SOUTH) return - val lowerGuard: NPC = RegionManager.getNpc(player!!.location, NPCs.KHAZARD_COMMANDER_478, 6) ?: return - GameWorld.Pulser.submit(object : Pulse(0) { - var count = 0 - override fun pulse(): Boolean { - when (count) { - 0 -> { - player!!.lock(4) - lowerGuard.sendChat("What? How did you manage to get in here.") - } - 2 -> { - player!!.sendChat("I've come for the orb.") - } - 3 -> { - lowerGuard.sendChat("I'll never let you take it.") - lowerGuard.attack(player) - player!!.unlock() - return true + private class ClimbWall : DialogueFile() { + val climbAnimation = Animation(839) + val wallLoc = Location(2509,3253,0) + override fun handle(componentID: Int, buttonID: Int) { + if(questStage(player!!, TreeGnomeVillage.questName) > 30){ + val northSouth = if (player!!.location.y <= wallLoc.y) Direction.NORTH else Direction.SOUTH + when(stage){ + 0 -> sendDialogue(player!!,"The wall has been reduced to rubble. It should be possible to climb over the remains").also{ stage++ } + 1 -> AgilityHandler.forceWalk(player!!, -1, player!!.location, player!!.location.transform(northSouth, 2), climbAnimation, 20, 0.0, null).also { + end() + if(northSouth == Direction.SOUTH) return + val lowerGuard: NPC = RegionManager.getNpc(player!!.location, NPCs.KHAZARD_COMMANDER_478, 6) ?: return + GameWorld.Pulser.submit(object : Pulse(0) { + var count = 0 + override fun pulse(): Boolean { + when (count) { + 0 -> { + player!!.lock(4) + lowerGuard.sendChat("What? How did you manage to get in here.") + } + 2 -> { + player!!.sendChat("I've come for the orb.") + } + 3 -> { + lowerGuard.sendChat("I'll never let you take it.") + lowerGuard.attack(player) + player!!.unlock() + return true + } } + count++ + return false } - count++ - return false - } - }) + }) + } } } } } -} \ No newline at end of file +} diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsDialogue.java b/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsDialogue.java index 509b3cfb3..4a6c28e70 100644 --- a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsDialogue.java +++ b/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsDialogue.java @@ -9,7 +9,6 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.update.flag.context.Animation; import core.plugin.Initializable; -import core.game.world.update.flag.player.FaceLocationFlag; /** * Represents the dialogue plugin used for mithril seeds. @@ -64,7 +63,7 @@ public final class MithrilSeedsDialogue extends DialoguePlugin { switch (buttonId) { case 1: // First option player.lock(2); - player.faceLocation(FaceLocationFlag.getFaceLocation(player, flower)); + player.faceLocation(flower.getFaceLocation(player.getLocation())); player.animate(ANIMATION); GameWorld.getPulser().submit(new Pulse(2, player, flower) { @Override diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsPlugin.java b/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsPlugin.java index 565e45593..b085e42e2 100644 --- a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsPlugin.java +++ b/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsPlugin.java @@ -11,7 +11,6 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.RegionManager; import core.game.world.update.flag.context.Animation; -import core.game.world.update.flag.player.FaceLocationFlag; import core.plugin.Initializable; import core.plugin.Plugin; import core.tools.RandomFunction; @@ -67,7 +66,7 @@ public final class MithrilSeedsPlugin extends OptionHandler { player.getPulseManager().run(new Pulse(1, player) { @Override public boolean pulse() { - player.faceLocation(FaceLocationFlag.getFaceLocation(player, object)); + player.faceLocation(object.getFaceLocation(player.getLocation())); player.getDialogueInterpreter().open(1 << 16 | 1, object); return true; } diff --git a/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java b/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java index 9abbe6e08..d7e442493 100644 --- a/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java +++ b/Server/src/main/content/region/karamja/tzhaar/handlers/TzhaarFightPitsPlugin.java @@ -29,7 +29,6 @@ import core.game.world.map.Location; import core.game.world.map.RegionManager; import core.game.world.map.zone.ZoneBorders; import core.game.world.map.zone.ZoneRestriction; -import core.game.world.update.flag.player.AppearanceFlag; import core.tools.RandomFunction; /** @@ -140,7 +139,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { lastVictor.getAchievementDiaryManager().finishTask(lastVictor, DiaryType.KARAMJA, 2, 0); addTokkul(lastVictor); lastVictor.getAppearance().setSkullIcon(SKULL_ID); - lastVictor.getUpdateMasks().register(new AppearanceFlag(lastVictor)); + lastVictor.updateAppearance(); lastVictor.getPacketDispatch().sendString("Current Champion: " + getChampionName(), INTERFACE_ID, 0); resetDamagePulse(lastVictor); } @@ -158,7 +157,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { player.getInteraction().remove(Option._P_ATTACK); if (player.getAppearance().getSkullIcon() == SKULL_ID) { player.getAppearance().setSkullIcon(-1); - player.getUpdateMasks().register(new AppearanceFlag(player)); + player.updateAppearance(); } } } @@ -190,7 +189,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { } if (lastVictor.getAppearance().getSkullIcon() == SKULL_ID) { player.getAppearance().setSkullIcon(-1); - player.getUpdateMasks().register(new AppearanceFlag(player)); + player.updateAppearance(); } } @@ -238,7 +237,7 @@ public final class TzhaarFightPitsPlugin extends ActivityPlugin { } if (e instanceof Player && (player = (Player) e).getAppearance().getSkullIcon() == SKULL_ID) { player.getAppearance().setSkullIcon(-1); - player.getUpdateMasks().register(new AppearanceFlag(player)); + player.updateAppearance(); } return super.leave(e, logout); } diff --git a/Server/src/main/core/api/ContentAPI.kt b/Server/src/main/core/api/ContentAPI.kt index cd1bc3955..3c9e6b0cd 100644 --- a/Server/src/main/core/api/ContentAPI.kt +++ b/Server/src/main/core/api/ContentAPI.kt @@ -41,8 +41,6 @@ import core.game.world.map.zone.MapZone import core.game.world.map.zone.ZoneBorders import core.game.world.map.zone.ZoneBuilder import core.game.world.update.flag.chunk.AnimateObjectUpdateFlag -import core.game.world.update.flag.context.Animation -import core.game.world.update.flag.context.Graphics import org.rs09.consts.Items import org.rs09.consts.NPCs import core.game.dialogue.DialogueFile @@ -55,9 +53,7 @@ import content.global.handlers.iface.ge.StockMarket import content.global.skill.slayer.SlayerManager import content.data.consumables.* import core.game.activity.Cutscene -import core.game.interaction.Clocks -import core.game.interaction.QueueStrength -import core.game.interaction.QueuedScript +import core.game.interaction.* import core.game.node.entity.player.info.LogType import core.game.node.entity.player.info.PlayerMonitor import core.tools.SystemLogger @@ -68,11 +64,13 @@ import core.game.world.GameWorld.Pulser import core.game.world.map.path.ProjectilePathfinder import core.game.world.repository.Repository import core.game.consumable.* -import core.tools.Log -import core.tools.tick import core.ServerConstants import core.api.utils.Vector +import core.tools.* +import core.game.world.update.flag.* +import core.game.world.update.flag.context.* import java.util.regex.* +import java.io.* import kotlin.math.* /** @@ -1082,6 +1080,68 @@ fun forceWalk(entity: Entity, dest: Location, type: String) { path.walk(entity) } +/** + * Force a player to move from the start location to the dest location + * @param player the player we are moving + * @param start the start location + * @param dest the end location + * @param startArrive the number of client cycles to take moving the player to the start location + * @param destArrive the number of client cycles to take moving the player to the end location from the start location + * @param direction (optional) the direction to face the player during the movement + * @param anim (optional) the animation to use throughout the movement + * @param callback (optional) a callback called when the forced movement completes + * @see NOTE: There are 30 client cycles per second. +*/ +fun forceMove (player: Player, start: Location, dest: Location, startArrive: Int, destArrive: Int, dir: Direction? = null, anim: Int = -1, callback: (()->Unit)? = null) { + var direction: Direction + + if (dir == null) { + var delta = Location.getDelta(start, dest) + var x = abs(delta.x) + var y = abs(delta.y) + + if (x > y) + direction = Direction.getDirection(delta.x, 0) + else + direction = Direction.getDirection(0, delta.y) + } else direction = dir + + val startLoc = Location.create(start) + val destLoc = Location.create(dest) + var startArriveTick = getWorldTicks() + cyclesToTicks (startArrive) + 1 + var destArriveTick = startArriveTick + cyclesToTicks (destArrive) + var maskSet = false + + delayEntity(player, (destArriveTick - getWorldTicks()) + 1) + queueScript (player, 0, QueueStrength.SOFT) { stage: Int -> + if (!finishedMoving(player)) + return@queueScript keepRunning(player) + if (!maskSet) { + var ctx = ForceMoveCtx (startLoc, destLoc, startArrive, destArrive, direction) + player.updateMasks.register(EntityFlag.ForceMove, ctx) + maskSet = true + } + + var tick = getWorldTicks() + if (tick < startArriveTick) { + return@queueScript keepRunning(player) + } else if (tick < destArriveTick) { + if (animationFinished(player)) + animate (player, anim) + return@queueScript keepRunning(player) + } else if (tick >= destArriveTick) { + try { + callback?.invoke() + } catch (e: Exception) { + e.printStackTrace() + } + player.properties.teleportLocation = dest + return@queueScript stopExecuting(player) + } + return@queueScript stopExecuting(player) + } +} + /** * Interrupts a given entity's walking queue * @param entity the entity to interrupt @@ -2382,6 +2442,24 @@ fun log(origin: Class<*>, type: Log, message: String) { SystemLogger.processLogEntry(origin, type, message) } +/** + * Logs a message to the server console along with a stack trace leading up to it. + * @param origin simply put (Kotlin) this::class.java or (Java) this.getClass() + * @param type the type of log: Log.FINE (default, visible on VERBOSE), Log.INFO (visible on DETAILED), Log.WARN (visible on CAUTIOUS), Log.ERR (always visible) + * @param message the actual message to log. +*/ +fun logWithStack(origin: Class<*>, type: Log, message: String) { + try { + throw Exception(message) + } catch (e: Exception) { + val sw = StringWriter() + val pw = PrintWriter(sw) + e.printStackTrace(pw) + + log(origin, type, "$sw") + } +} + /** * Used by content handlers to check if the entity is done moving yet */ @@ -2403,7 +2481,7 @@ fun delayScript(entity: Entity, ticks: Int): Boolean { */ fun delayEntity(entity: Entity, ticks: Int) { entity.scripts.delay = GameWorld.ticks + ticks - lock(entity, 5) //TODO: REMOVE WHEN EVERYTHING IMPORTANT USES PROPER QUEUES - THIS IS INCORRECT BEHAVIOR + lock(entity, ticks) //TODO: REMOVE WHEN EVERYTHING IMPORTANT USES PROPER QUEUES - THIS IS INCORRECT BEHAVIOR } fun apRange(entity: Entity, apRange: Int) { diff --git a/Server/src/main/core/game/bots/ScriptAPI.kt b/Server/src/main/core/game/bots/ScriptAPI.kt index 4400f66e5..11bde4dd7 100644 --- a/Server/src/main/core/game/bots/ScriptAPI.kt +++ b/Server/src/main/core/game/bots/ScriptAPI.kt @@ -26,7 +26,7 @@ import core.game.world.map.path.Pathfinder import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.ChatMessage import core.game.world.update.flag.context.Graphics -import core.game.world.update.flag.player.ChatFlag +import core.game.world.update.flag.* import core.tools.RandomFunction import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch @@ -90,7 +90,7 @@ class ScriptAPI(private val bot: Player) { fun sendChat(message: String) { bot.sendChat(message) - bot.updateMasks.register(ChatFlag(ChatMessage(bot, message, 0, 0))) + bot.updateMasks.register(EntityFlag.Chat, ChatMessage(bot, message, 0, 0)) } /** diff --git a/Server/src/main/core/game/container/impl/EquipmentContainer.java b/Server/src/main/core/game/container/impl/EquipmentContainer.java index a059a0be9..70aa7b678 100644 --- a/Server/src/main/core/game/container/impl/EquipmentContainer.java +++ b/Server/src/main/core/game/container/impl/EquipmentContainer.java @@ -8,7 +8,6 @@ import core.game.node.entity.combat.equipment.WeaponInterface; import core.game.node.entity.player.Player; import core.game.node.entity.skill.Skills; import core.game.node.item.Item; -import core.game.world.update.flag.player.AppearanceFlag; import core.net.packet.PacketRepository; import core.net.packet.context.ContainerContext; import core.net.packet.out.ContainerPacket; @@ -306,7 +305,7 @@ public final class EquipmentContainer extends Container { } } player.getAppearance().setAnimations(); - player.getUpdateMasks().register(new AppearanceFlag(player)); + player.updateAppearance(); player.getSettings().updateWeight(); updateBonuses(player); } diff --git a/Server/src/main/core/game/interaction/InteractPlugin.java b/Server/src/main/core/game/interaction/InteractPlugin.java index c82d65691..d5057980e 100644 --- a/Server/src/main/core/game/interaction/InteractPlugin.java +++ b/Server/src/main/core/game/interaction/InteractPlugin.java @@ -9,7 +9,6 @@ import core.game.node.entity.player.Player; import core.game.node.item.Item; import core.game.node.scenery.Scenery; import core.game.system.task.Pulse; -import core.game.world.update.flag.player.FaceLocationFlag; import core.net.packet.PacketRepository; import core.net.packet.context.InteractionOptionContext; import core.net.packet.out.InteractionOption; @@ -145,7 +144,7 @@ public class InteractPlugin { @Override public boolean pulse() { try { - player.faceLocation(FaceLocationFlag.getFaceLocation(player, node)); + player.faceLocation(node.getFaceLocation(player.getLocation())); if (player.getLocks().isInteractionLocked() || player.getZoneMonitor().interact(node, option)) { return true; } @@ -181,7 +180,7 @@ public class InteractPlugin { @Override public boolean pulse() { try { - player.faceLocation(FaceLocationFlag.getFaceLocation(player, node)); + player.faceLocation(node.getFaceLocation(player.getLocation())); if (player.getLocks().isInteractionLocked() || player.getZoneMonitor().interact(node, option)) { return true; } @@ -344,4 +343,4 @@ public class InteractPlugin { this.initialized = initialized; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/interaction/UseWithHandler.java b/Server/src/main/core/game/interaction/UseWithHandler.java index ff80e7e84..c38a5e6bc 100644 --- a/Server/src/main/core/game/interaction/UseWithHandler.java +++ b/Server/src/main/core/game/interaction/UseWithHandler.java @@ -12,7 +12,6 @@ import core.tools.Log; import core.tools.SystemLogger; import core.game.system.task.Pulse; import core.game.world.map.Location; -import core.game.world.update.flag.player.FaceLocationFlag; import core.plugin.Plugin; import java.util.ArrayList; @@ -175,7 +174,7 @@ public abstract class UseWithHandler implements Plugin { @Override public boolean pulse() { event.getPlayer().dispatch(new UseWithEvent(event.getUsed().getId(), event.getUsedWith().getId())); - event.getPlayer().faceLocation(FaceLocationFlag.getFaceLocation(event.getPlayer(), event.getUsedWith())); + event.getPlayer().faceLocation(event.getUsedWith().getFaceLocation(event.getPlayer().getLocation())); boolean handled = false; Item used = (Item) event.getUsed(); for (UseWithHandler h : handlers) { @@ -273,4 +272,4 @@ public abstract class UseWithHandler implements Plugin { public boolean isDynamic() { return false; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/node/entity/Entity.java b/Server/src/main/core/game/node/entity/Entity.java index 34b74010c..5da08ee16 100644 --- a/Server/src/main/core/game/node/entity/Entity.java +++ b/Server/src/main/core/game/node/entity/Entity.java @@ -27,6 +27,7 @@ import core.game.world.map.path.Pathfinder; import core.game.world.map.zone.ZoneMonitor; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; +import core.game.world.update.flag.*; import core.game.node.entity.combat.CombatSwingHandler; import core.game.world.update.UpdateMasks; @@ -48,7 +49,7 @@ public abstract class Entity extends Node { /** * The entity's update masks. */ - private final UpdateMasks updateMasks = new UpdateMasks(); + private final UpdateMasks updateMasks = new UpdateMasks(this); /** * The walking queue. @@ -631,21 +632,39 @@ public abstract class Entity extends Node { * @param entity The entity to face. * @return {@code True} if succesful. */ - public abstract boolean face(Entity entity); + public boolean face(Entity entity) { + if (entity == null) { + int ordinal = EntityFlags.getOrdinal(EFlagType.of(this), EntityFlag.FaceEntity); + if (getUpdateMasks().unregisterSynced(ordinal)) { + return getUpdateMasks().register(EntityFlag.FaceEntity, null); + } + return true; + } + return getUpdateMasks().register(EntityFlag.FaceEntity, entity, true); + } /** * Registers a new face location update flag to the update masks. * @param location The location to face. * @return {@code True} if succesful. */ - public abstract boolean faceLocation(Location location); + public boolean faceLocation(Location location) { + if (location == null) { + int ordinal = EntityFlags.getOrdinal(EFlagType.of(this), EntityFlag.FaceLocation); + getUpdateMasks().unregisterSynced(ordinal); + return true; + } + return getUpdateMasks().register(EntityFlag.FaceLocation, location, true); + } /** * Registers a new force chat update flag to the update masks. * @param string The string. * @return {@code True} if succesful. */ - public abstract boolean sendChat(String string); + public boolean sendChat(String string) { + return getUpdateMasks().register(EntityFlag.ForceChat, string); + } /** * Gets the current combat swing handler. diff --git a/Server/src/main/core/game/node/entity/impl/Animator.java b/Server/src/main/core/game/node/entity/impl/Animator.java index 42e201f63..3afafb41b 100644 --- a/Server/src/main/core/game/node/entity/impl/Animator.java +++ b/Server/src/main/core/game/node/entity/impl/Animator.java @@ -6,10 +6,7 @@ import core.game.node.entity.npc.NPC; import core.game.world.GameWorld; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; -import core.game.world.update.flag.npc.NPCAnimation; -import core.game.world.update.flag.npc.NPCGraphic; -import core.game.world.update.flag.player.AnimationFlag; -import core.game.world.update.flag.player.GraphicFlag; +import core.game.world.update.flag.EntityFlag; /** * Handles the animating of an Entity. @@ -128,12 +125,12 @@ public final class Animator { ticks = 0; } entity.clocks[Clocks.getANIMATION_END()] = ticks; - entity.getUpdateMasks().register(entity instanceof NPC ? new NPCAnimation(animation) : new AnimationFlag(animation)); + entity.getUpdateMasks().register(EntityFlag.Animate, animation); priority = animation.getPriority(); } if (graphic != null) { this.graphics = graphic; - entity.getUpdateMasks().register(entity instanceof NPC ? new NPCGraphic(graphic) : new GraphicFlag(graphic)); + entity.getUpdateMasks().register(EntityFlag.SpotAnim, graphic); } return true; } @@ -212,4 +209,4 @@ public final class Animator { public void setPriority(Priority priority) { this.priority = priority; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/node/entity/impl/ForceMovement.java b/Server/src/main/core/game/node/entity/impl/ForceMovement.java index e3ef1eb1e..8cfc7efd6 100644 --- a/Server/src/main/core/game/node/entity/impl/ForceMovement.java +++ b/Server/src/main/core/game/node/entity/impl/ForceMovement.java @@ -6,8 +6,8 @@ import core.game.system.task.Pulse; import core.game.world.GameWorld; import core.game.world.map.Direction; import core.game.world.map.Location; -import core.game.world.update.flag.context.Animation; -import core.game.world.update.flag.player.ForceMovementFlag; +import core.game.world.update.flag.context.*; +import core.game.world.update.flag.*; /** * The force movement handler. @@ -91,8 +91,9 @@ public class ForceMovement extends Pulse { * @param commenceSpeed The commencing speed. * @param pathSpeed The path speed. * @param unlockAfter Whether to unlock the entity after the ForceMovement completes - * + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public ForceMovement(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction, int commenceSpeed, int pathSpeed, boolean unlockAfter) { super(1, e); this.entity = e; @@ -113,11 +114,17 @@ public class ForceMovement extends Pulse { * @param end the destination. * @param animation the animation. * @param speed The path speed. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public ForceMovement(Entity e, Location start, Location end, Animation animation, int speed) { this(e, start, end, WALK_ANIMATION, animation, direction(start, end), WALKING_SPEED, speed, true); } + /** + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. + */ + @Deprecated public ForceMovement(Entity e, Location destination, int startSpeed, int animSpeed){ this(e,e.getLocation(),destination,WALK_ANIMATION,WALK_ANIMATION,direction(e.getLocation(),destination),startSpeed,animSpeed, true); } @@ -128,7 +135,9 @@ public class ForceMovement extends Pulse { * @param start the start location. * @param destination the destination. * @param animation the animation. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public ForceMovement(Entity e, Location start, Location destination, Animation animation) { this(e, start, destination, WALK_ANIMATION, animation, direction(start, destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -138,7 +147,9 @@ public class ForceMovement extends Pulse { * @param start the start loc. * @param destination the destination. * @param animation the animation. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public ForceMovement(Location start, Location destination, Animation animation) { this(null, start, destination, WALK_ANIMATION, animation, direction(start, destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -148,7 +159,9 @@ public class ForceMovement extends Pulse { * @param e The entity. * @param destination The destination location. * @return The created ForceMovement object. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public static ForceMovement run(Entity e, Location destination) { return run(e, e.getLocation(), destination, WALK_ANIMATION, WALK_ANIMATION, direction(e.getLocation(), destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -159,7 +172,9 @@ public class ForceMovement extends Pulse { * @param start The start location. * @param destination The destination location. * @return The created ForceMovement object. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination) { return run(e, start, destination, WALK_ANIMATION, WALK_ANIMATION, direction(e.getLocation(), destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -171,7 +186,9 @@ public class ForceMovement extends Pulse { * @param destination The destination location. * @param animation The animation. * @return The created ForceMovement object. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation animation) { return run(e, start, destination, WALK_ANIMATION, animation, direction(start, destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -184,7 +201,9 @@ public class ForceMovement extends Pulse { * @param animation The animation. * @param speed The path speed. * @return The created ForceMovement object. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation animation, int speed) { return run(e, start, destination, WALK_ANIMATION, animation, direction(start, destination), WALKING_SPEED, speed, true); } @@ -196,7 +215,9 @@ public class ForceMovement extends Pulse { * @param destination The destination location. * @param animation The animation. * @return The created ForceMovement object. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation) { return run(e, start, destination, startAnim, animation, direction(start, destination), WALKING_SPEED, WALKING_SPEED, true); } @@ -209,7 +230,9 @@ public class ForceMovement extends Pulse { * @param animation The animation. * @param direction The direction. * @return The created ForceMovement object. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction) { return run(e, start, destination, startAnim, animation, direction, WALKING_SPEED, WALKING_SPEED, true); } @@ -223,11 +246,17 @@ public class ForceMovement extends Pulse { * @param direction The direction. * @param pathSpeed The speed (in ticks). * @return The created ForceMovement object. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction, int pathSpeed) { return run(e, start, destination, startAnim, animation, direction, WALKING_SPEED, pathSpeed, true); } + /** + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. + */ + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction, int commenceSpeed, int pathSpeed) { return run(e, start, destination, startAnim, animation, direction, commenceSpeed, pathSpeed, true); } @@ -240,7 +269,9 @@ public class ForceMovement extends Pulse { * @param animation The animation. * @param direction The direction. * @return The created ForceMovement object. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public static ForceMovement run(Entity e, Location start, Location destination, Animation startAnim, Animation animation, Direction direction, int commenceSpeed, int pathSpeed, boolean unlockAfter) { if (startAnim != null) { startAnim.setPriority(Animator.Priority.VERY_HIGH); @@ -254,7 +285,10 @@ public class ForceMovement extends Pulse { GameWorld.getPulser().submit(fm); return fm; } - + /* + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. + */ + @Deprecated public static ForceMovement run(Entity e, Location destination, int commenceSpeed, int pathSpeed){ return run(e,e.getLocation(),destination,WALK_ANIMATION,WALK_ANIMATION,direction(e.getLocation(),destination),commenceSpeed,pathSpeed, true); } @@ -262,7 +296,9 @@ public class ForceMovement extends Pulse { /** * Method used to run the force movement. * @param e the entity. + * @deprecated this is no longer the preferred way to use force movement. Use the ContentAPI forceMove method instead, please. */ + @Deprecated public void run(final Entity e, final int speed) { this.entity = e; int commence = (int) start.getDistance(e.getLocation()); @@ -321,7 +357,7 @@ public class ForceMovement extends Pulse { } int ticks = 1 + commenceSpeed + pathSpeed; entity.getImpactHandler().setDisabledTicks(ticks); - entity.getUpdateMasks().register(new ForceMovementFlag(this)); + entity.getUpdateMasks().register(EntityFlag.ForceMove, new ForceMoveCtx(start, destination, commenceSpeed * 30, pathSpeed * 30, direction)); if(entity instanceof Player) { entity.getWalkingQueue().updateRegion(destination, false); } diff --git a/Server/src/main/core/game/node/entity/npc/NPC.java b/Server/src/main/core/game/node/entity/npc/NPC.java index 696f5c6dc..aa77b04a7 100644 --- a/Server/src/main/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/core/game/node/entity/npc/NPC.java @@ -26,10 +26,7 @@ import core.game.world.map.build.DynamicRegion; import core.game.world.map.path.Pathfinder; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; -import core.game.world.update.flag.npc.NPCFaceEntity; -import core.game.world.update.flag.npc.NPCFaceLocation; -import core.game.world.update.flag.npc.NPCForceChat; -import core.game.world.update.flag.npc.NPCSwitchId; +import core.game.world.update.flag.*; import core.tools.RandomFunction; import core.api.utils.GlobalKillCounter; import core.api.utils.Vector; @@ -579,31 +576,6 @@ public class NPC extends Entity { super.reset(); } - @Override - public boolean face(Entity entity) { - if (entity == null) { - if (getUpdateMasks().unregisterSynced(NPCFaceEntity.getOrdinal())) { - return getUpdateMasks().register(new NPCFaceEntity(null)); - } - return true; - } - return getUpdateMasks().register(new NPCFaceEntity(entity), true); - } - - @Override - public boolean faceLocation(Location location) { - if (location == null) { - getUpdateMasks().unregisterSynced(NPCFaceLocation.getOrdinal()); - return true; - } - return getUpdateMasks().register(new NPCFaceLocation(location), true); - } - - @Override - public boolean sendChat(String string) { - return getUpdateMasks().register(new NPCForceChat(string)); - } - @Override public CombatSwingHandler getSwingHandler(boolean swing) { CombatSwingHandler original = getProperties().getCombatPulse().getStyle().getSwingHandler(); @@ -703,9 +675,10 @@ public class NPC extends Entity { configure(); interactPlugin.setDefault(); if (id == originalId) { - getUpdateMasks().unregisterSynced(NPCSwitchId.getOrdinal()); + int ordinal = EntityFlags.getOrdinal (EFlagType.NPC, EntityFlag.TypeSwap); + getUpdateMasks().unregisterSynced(ordinal); } - getUpdateMasks().register(new NPCSwitchId(id), id != originalId); + getUpdateMasks().register(EntityFlag.TypeSwap, id, id != originalId); return this; } diff --git a/Server/src/main/core/game/node/entity/player/Player.java b/Server/src/main/core/game/node/entity/player/Player.java index c773bd1bb..f0481e9e8 100644 --- a/Server/src/main/core/game/node/entity/player/Player.java +++ b/Server/src/main/core/game/node/entity/player/Player.java @@ -43,11 +43,7 @@ import core.game.world.map.build.DynamicRegion; import core.game.world.map.path.Pathfinder; import core.game.world.map.zone.ZoneType; import core.game.world.update.flag.PlayerFlags; -import core.game.world.update.flag.context.Animation; -import core.game.world.update.flag.context.Graphics; -import core.game.world.update.flag.player.FaceEntityFlag; -import core.game.world.update.flag.player.FaceLocationFlag; -import core.game.world.update.flag.player.ForceChatFlag; +import core.game.world.update.flag.*; import core.net.IoSession; import core.net.packet.PacketRepository; import core.net.packet.context.DynamicSceneContext; @@ -81,6 +77,7 @@ import core.game.ge.GrandExchangeRecords; import core.game.ge.GrandExchangeOffer; import core.cache.def.impl.ItemDefinition; import core.worker.ManagementEvents; +import core.game.world.update.flag.context.*; import java.util.*; import java.util.concurrent.TimeUnit; @@ -549,31 +546,6 @@ public class Player extends Entity { Arrays.fill(opCounts, (byte) 0); } - @Override - public boolean face(Entity entity) { - if (entity == null) { - if (getUpdateMasks().unregisterSynced(FaceEntityFlag.getOrdinal())) { - return getUpdateMasks().register(new FaceEntityFlag(entity)); - } - return true; - } - return getUpdateMasks().register(new FaceEntityFlag(entity), true); - } - - @Override - public boolean faceLocation(Location location) { - if (location == null) { - getUpdateMasks().unregisterSynced(FaceLocationFlag.getOrdinal()); - return true; - } - return getUpdateMasks().register(new FaceLocationFlag(location), true); - } - - @Override - public boolean sendChat(String string) { - return getUpdateMasks().register(new ForceChatFlag(string)); - } - @Override public int getClientIndex() { return this.getIndex() | 0x8000; @@ -1393,4 +1365,8 @@ public class Player extends Entity { } states.remove(key); } + + public void updateAppearance() { + getUpdateMasks().register(EntityFlag.Appearance, this); + } } diff --git a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java index addc10d9e..e35124a1b 100644 --- a/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java +++ b/Server/src/main/core/game/node/entity/player/info/login/LoginConfiguration.java @@ -6,7 +6,6 @@ import core.game.node.entity.player.Player; import core.game.node.entity.player.link.emote.Emotes; import core.game.node.item.Item; import core.game.world.map.RegionManager; -import core.game.world.update.flag.player.AppearanceFlag; import core.net.packet.PacketRepository; import core.net.packet.context.InterfaceContext; import core.net.packet.out.Interface; @@ -136,7 +135,7 @@ public final class LoginConfiguration { UpdateSequence.getRenderablePlayers().add(player); RegionManager.move(player); player.getMusicPlayer().init(); - player.getUpdateMasks().register(new AppearanceFlag(player)); + player.updateAppearance(); player.getPlayerFlags().setUpdateSceneGraph(true); player.getStateManager().init(); player.getPacketDispatch().sendInterfaceConfig(226, 1, true); @@ -303,4 +302,4 @@ public final class LoginConfiguration { return LOGIN_PLUGINS; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java b/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java index b0c890b5c..dac34f170 100644 --- a/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java +++ b/Server/src/main/core/game/node/entity/player/link/PacketDispatch.java @@ -12,8 +12,7 @@ import core.game.world.map.RegionManager; import core.game.world.update.flag.chunk.AnimateObjectUpdateFlag; import core.game.world.update.flag.context.Animation; import core.game.world.update.flag.context.Graphics; -import core.game.world.update.flag.player.AnimationFlag; -import core.game.world.update.flag.player.GraphicFlag; +import core.game.world.update.flag.EntityFlag; import core.net.packet.PacketRepository; import core.net.packet.context.*; import core.net.packet.context.DisplayModelContext.ModelType; @@ -300,7 +299,7 @@ public final class PacketDispatch { * @param id The animation id. */ public void sendAnimation(int id) { - player.getUpdateMasks().register(new AnimationFlag(new Animation(id))); + player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id)); } /** @@ -309,7 +308,7 @@ public final class PacketDispatch { * @param delay The animation delay. */ public void sendAnimation(int id, int delay) { - player.getUpdateMasks().register(new AnimationFlag(new Animation(id, delay))); + player.getUpdateMasks().register(EntityFlag.Animate, new Animation(id, delay)); } /** @@ -317,7 +316,7 @@ public final class PacketDispatch { * @param id The graphic id. */ public void sendGraphic(int id) { - player.getUpdateMasks().register(new GraphicFlag(new Graphics(id))); + player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id)); } /** @@ -383,7 +382,7 @@ public final class PacketDispatch { * @param height The graphic height. */ public void sendGraphic(int id, int height) { - player.getUpdateMasks().register(new GraphicFlag(new Graphics(id, height))); + player.getUpdateMasks().register(EntityFlag.SpotAnim, new Graphics(id, height)); } public void sendVarClient(int id, int value, boolean cs2) { PacketRepository.send(Config.class, new ConfigContext(player, id, value, cs2)); diff --git a/Server/src/main/core/game/node/entity/player/link/SkullManager.java b/Server/src/main/core/game/node/entity/player/link/SkullManager.java index 5a6ec9efa..2bba76e78 100644 --- a/Server/src/main/core/game/node/entity/player/link/SkullManager.java +++ b/Server/src/main/core/game/node/entity/player/link/SkullManager.java @@ -3,7 +3,6 @@ package core.game.node.entity.player.link; import core.game.node.entity.Entity; import core.game.node.entity.player.Player; import core.game.node.entity.state.EntityState; -import core.game.world.update.flag.player.AppearanceFlag; import java.util.ArrayList; import java.util.List; @@ -86,7 +85,7 @@ public final class SkullManager { */ public void setSkullIcon(int skullIcon) { player.getAppearance().setSkullIcon(skullIcon); - player.getUpdateMasks().register(new AppearanceFlag(player)); + player.updateAppearance(); } /** diff --git a/Server/src/main/core/game/node/entity/player/link/appearance/Appearance.java b/Server/src/main/core/game/node/entity/player/link/appearance/Appearance.java index b639477b5..981d6b024 100644 --- a/Server/src/main/core/game/node/entity/player/link/appearance/Appearance.java +++ b/Server/src/main/core/game/node/entity/player/link/appearance/Appearance.java @@ -8,7 +8,6 @@ import core.game.node.entity.impl.Animator.Priority; import core.game.node.entity.player.Player; import core.game.node.item.Item; import core.game.world.update.flag.context.Animation; -import core.game.world.update.flag.player.AppearanceFlag; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import core.game.system.config.ItemConfigParser; @@ -190,7 +189,7 @@ public final class Appearance { * Method used to sync this appearance with the client. */ public void sync() { - player.getUpdateMasks().register(new AppearanceFlag(player)); + player.updateAppearance(); } /** diff --git a/Server/src/main/core/game/node/entity/skill/Skills.java b/Server/src/main/core/game/node/entity/skill/Skills.java index 134ab86ff..274bd9343 100644 --- a/Server/src/main/core/game/node/entity/skill/Skills.java +++ b/Server/src/main/core/game/node/entity/skill/Skills.java @@ -11,7 +11,6 @@ import core.game.node.entity.npc.NPC; import core.game.node.entity.player.Player; import core.game.node.entity.player.link.request.assist.AssistSession; import core.game.node.item.Item; -import core.game.world.update.flag.player.AppearanceFlag; import core.net.packet.PacketRepository; import core.net.packet.context.SkillContext; import core.net.packet.out.SkillLevel; @@ -279,10 +278,8 @@ public final class Skills { staticLevels[slot] = newLevel; if (entity instanceof Player) { - if (updateCombatLevel()) { - player.getUpdateMasks().register(new AppearanceFlag(player)); - } - LevelUp.levelup(player, slot, amount); + player.updateAppearance(); + LevelUp.levelup(player, slot, amount); } } if (entity instanceof Player) { diff --git a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt index 1f74393b7..0ec29e6d5 100644 --- a/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt +++ b/Server/src/main/core/game/system/command/sets/DevelopmentCommandSet.kt @@ -27,6 +27,10 @@ import java.io.FileWriter import java.util.Arrays import core.net.packet.PacketWriteQueue import core.tools.Log +import core.game.world.update.flag.* +import core.game.world.update.flag.context.* +import core.game.node.entity.impl.* +import core.game.world.map.Location @Initializable class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { @@ -239,5 +243,34 @@ class DevelopmentCommandSet : CommandSet(Privilege.ADMIN) { define("drawroute", Privilege.ADMIN, "", "Visualizes the path your player is taking") {player, _ -> setAttribute (player, "routedraw", !getAttribute(player, "routedraw", false)) } + + define ("fmstart", Privilege.ADMIN, "", "") {player, _ -> + setAttribute(player, "fmstart", Location.create(player.location)) + } + + define ("fmend", Privilege.ADMIN, "", "") {player, _ -> + setAttribute(player, "fmend", Location.create(player.location)) + } + + define ("fmspeed", Privilege.ADMIN, "", "") {player, args -> + setAttribute(player, "fmspeed", args[1].toIntOrNull() ?: 10) + } + + define ("fmspeedend", Privilege.ADMIN, "", "") {player, args -> + setAttribute(player, "fmspeedend", args[1].toIntOrNull() ?: 10) + } + + define("testfm", Privilege.ADMIN, "", "") { player, _ -> + val start = getAttribute(player, "fmstart", Location.create(player.location)) + val end = getAttribute(player, "fmend", Location.create(player.location)) + val speed = getAttribute(player, "fmspeed", 10) + val speedEnd = getAttribute(player, "fmspeedend", 10) + val ani = getAttribute(player, "fmanim", -1) + forceMove(player, start, end, speed, speedEnd, anim = ani) + } + + define("fmanim", Privilege.ADMIN, "", "") {player, args -> + setAttribute(player, "fmanim", args[1].toIntOrNull() ?: -1) + } } } diff --git a/Server/src/main/core/game/world/update/UpdateMasks.kt b/Server/src/main/core/game/world/update/UpdateMasks.kt index feb8eddc5..072148a1c 100644 --- a/Server/src/main/core/game/world/update/UpdateMasks.kt +++ b/Server/src/main/core/game/world/update/UpdateMasks.kt @@ -5,82 +5,42 @@ import core.game.node.entity.combat.ImpactHandler import core.game.node.entity.player.Player import core.game.world.update.flag.UpdateFlag import core.game.world.update.flag.context.HitMark -import core.game.world.update.flag.npc.NPCHitFlag -import core.game.world.update.flag.npc.NPCHitFlag1 -import core.game.world.update.flag.player.AppearanceFlag -import core.game.world.update.flag.player.HitUpdateFlag -import core.game.world.update.flag.player.HitUpdateFlag1 +import core.game.world.update.flag.* import core.net.packet.IoBuffer +import core.api.* +import core.tools.* import java.util.concurrent.atomic.AtomicBoolean -/** - * Holds an entity's update masks. - * @author Emperor - */ -class UpdateMasks { - /** - * The mask data. - */ - private var maskData = 0 - - /** - * The update masks array. - */ - private val masks = arrayOfNulls?>(SIZE) - - /** - * Gets the appearanceStamp. - * @return The appearanceStamp. - */ - /** - * Sets the appearanceStamp. - * @param appearanceStamp The appearanceStamp to set. - */ - /** - * The appearance time stamp. - */ +class UpdateMasks (val owner: Entity) { var appearanceStamp: Long = 0 - - /** - * The synced mask data. - */ - private var syncedMask = 0 - - /** - * The update masks array. - */ - private val syncedMasks = arrayOfNulls?>(SIZE) - - /** - * If the update masks are being updated. - */ + private val type = EFlagType.of (owner) private val updating = AtomicBoolean() - /** - * Registers an update flag. - * @param flag The update flag. - * @return `True` if successful. - */ - /** - * Registers an update flag. - * @param flag The update flag. - * @return `True` if successful. - */ + private var presenceFlags = 0 + private var syncedPresenceFlags = 0 + private val elements = arrayOfNulls(SIZE) + private val syncedElements = arrayOfNulls(SIZE) + private data class MaskElement (val encoder: EFlagProvider, val context: Any?) + @JvmOverloads - fun register(flag: UpdateFlag<*>, synced: Boolean = false): Boolean { - var synced = synced - if (updating.get()) { + fun register(flag: EntityFlag, context: Any?, sync: Boolean = false) : Boolean { + var synced = sync + var provider = EntityFlags.getFlagFor (type, flag) + if (provider == null) { + logWithStack(this::class.java, Log.ERR, "Tried to use flag ${flag.name} which is not available for ${type.name} in this revision.") return false } - if (flag is AppearanceFlag) { + if (updating.get()) + return false + if (flag == EntityFlag.Appearance) { appearanceStamp = System.currentTimeMillis() synced = true } if (synced) { - syncedMasks[flag.ordinal()] = flag - syncedMask = syncedMask or flag.data() + syncedElements[provider.ordinal] = MaskElement (provider, context) + syncedPresenceFlags = syncedPresenceFlags or provider.presenceFlag } - maskData = maskData or flag.data() - masks[flag.ordinal()] = flag + elements[provider.ordinal] = MaskElement (provider, context) + presenceFlags = presenceFlags or provider.presenceFlag return true } @@ -90,9 +50,9 @@ class UpdateMasks { * @return `True` if the mask got removed. */ fun unregisterSynced(ordinal: Int): Boolean { - if (syncedMasks[ordinal] != null) { - syncedMask = syncedMask and syncedMasks[ordinal]!!.data().inv() - syncedMasks[ordinal] = null + if (syncedElements[ordinal] != null) { + syncedPresenceFlags = syncedPresenceFlags and syncedElements[ordinal]!!.encoder.presenceFlag.inv() + syncedElements[ordinal] = null return true } return false @@ -105,16 +65,16 @@ class UpdateMasks { * @param buffer The buffer to write on. */ fun write(p: Player?, e: Entity?, buffer: IoBuffer) { - var maskData = maskData + var maskData = presenceFlags if (maskData >= 0x100) { maskData = maskData or if (e is Player) 0x10 else 0x8 buffer.put(maskData).put(maskData shr 8) } else { buffer.put(maskData) } - for (i in masks.indices) { - val flag = masks[i] - flag?.writeDynamic(buffer, p) + for (i in elements.indices) { + val element = elements[i] + element?.encoder?.writeToDynamic(buffer, element.context, p!!) } } @@ -126,10 +86,11 @@ class UpdateMasks { * @param appearance If the appearance mask should be written. */ fun writeSynced(p: Player?, e: Entity?, buffer: IoBuffer, appearance: Boolean) { - var maskData = maskData - var synced = syncedMask - if (!appearance && synced and AppearanceFlag.getData() != 0) { - synced = synced and AppearanceFlag.getData().inv() + var maskData = presenceFlags + var synced = syncedPresenceFlags + var appearanceFlag = EntityFlags.getPresenceFlag(type, EntityFlag.Appearance) + if (!appearance && synced and appearanceFlag != 0) { + synced = synced and appearanceFlag.inv() } maskData = maskData or synced if (maskData >= 0x100) { @@ -138,15 +99,15 @@ class UpdateMasks { } else { buffer.put(maskData) } - for (i in masks.indices) { - var flag = masks[i] - if (flag == null) { - flag = syncedMasks[i] - if (!appearance && flag is AppearanceFlag) { + for (i in elements.indices) { + var element = elements[i] + if (element == null) { + element = syncedElements[i] + if (!appearance && element != null && element.encoder.flag == EntityFlag.Appearance) { continue } } - flag?.writeDynamic(buffer, p) + element?.encoder?.writeToDynamic(buffer, element.context, p!!) } } @@ -173,13 +134,8 @@ class UpdateMasks { * @param secondary If the hit update is secondary. */ private fun registerHitUpdate(e: Entity, impact: ImpactHandler.Impact, secondary: Boolean): HitMark { - val player = e is Player val mark = HitMark(impact.amount, impact.type.ordinal, e) - if (player) { - register(if (secondary) HitUpdateFlag1(mark) else HitUpdateFlag(mark)) - } else { - register(if (secondary) NPCHitFlag1(mark) else NPCHitFlag(mark)) - } + register(if (secondary) EntityFlag.SecondaryHit else EntityFlag.PrimaryHit, mark) return mark } @@ -187,10 +143,10 @@ class UpdateMasks { * Resets the update masks. */ fun reset() { - for (i in masks.indices) { - masks[i] = null + for (i in elements.indices) { + elements[i] = null } - maskData = 0 + presenceFlags = 0 updating.set(false) } @@ -203,14 +159,14 @@ class UpdateMasks { * @return `True` if so. */ val isUpdateRequired: Boolean - get() = maskData != 0 + get() = presenceFlags != 0 /** * Checks if synced update masks have been registered. * @return `True` if so. */ fun hasSynced(): Boolean { - return syncedMask != 0 + return syncedPresenceFlags != 0 } companion object { @@ -219,4 +175,4 @@ class UpdateMasks { */ const val SIZE = 11 } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/world/update/flag/EFlagProvider.kt b/Server/src/main/core/game/world/update/flag/EFlagProvider.kt new file mode 100644 index 000000000..4c11308b9 --- /dev/null +++ b/Server/src/main/core/game/world/update/flag/EFlagProvider.kt @@ -0,0 +1,29 @@ +package core.game.world.update.flag + +import core.net.packet.IoBuffer +import core.game.node.entity.Entity +import kotlin.reflect.* +import core.api.* +import core.tools.* + +enum class EFlagType { + Player, + NPC; + companion object { + @JvmStatic fun of (e: Entity) : EFlagType { + if (e is core.game.node.entity.player.Player) return EFlagType.Player + else return EFlagType.NPC + } + } +} + +open class EFlagProvider (val revision: Int, val type: EFlagType, val presenceFlag: Int, val ordinal: Int, val flag: EntityFlag) { + open fun writeTo (buffer: IoBuffer, context: Any?) {} + open fun writeToDynamic (buffer: IoBuffer, context: Any?, e: Entity) { + writeTo (buffer, context) + } + + fun logInvalidType (context: Any?, expected: KType) { + logWithStack(this::class.java, Log.ERR, "Invalid context of type ${context?.let { it::class.java.simpleName } ?: "null"} passed to ${this::class.simpleName} flag which expects $expected.") + } +} diff --git a/Server/src/main/core/game/world/update/flag/EntityFlag.kt b/Server/src/main/core/game/world/update/flag/EntityFlag.kt new file mode 100644 index 000000000..85fcb8429 --- /dev/null +++ b/Server/src/main/core/game/world/update/flag/EntityFlag.kt @@ -0,0 +1,16 @@ +package core.game.world.update.flag + +enum class EntityFlag { + Chat, + ForceChat, + PrimaryHit, + SecondaryHit, + Animate, + SpotAnim, + Appearance, + FaceEntity, + FaceLocation, + ForceMove, + AnimSeq, + TypeSwap +} diff --git a/Server/src/main/core/game/world/update/flag/EntityFlags.kt b/Server/src/main/core/game/world/update/flag/EntityFlags.kt new file mode 100644 index 000000000..3d3c2bf42 --- /dev/null +++ b/Server/src/main/core/game/world/update/flag/EntityFlags.kt @@ -0,0 +1,42 @@ +package core.game.world.update.flag + +import core.api.* +import core.ServerConstants +import kotlin.reflect.* +import kotlin.reflect.full.* + +object EntityFlags { + lateinit var flagProviders : HashMap + + init { + flagProviders = HashMap() + registerFlagProviders (PlayerFlags530::class) + registerFlagProviders (NPCFlags530::class) + } + + fun registerFlagProviders (parent: KClass<*>) { + val clazzes = parent.sealedSubclasses + for (clazz in clazzes) { + val p = clazz.primaryConstructor?.call() as? EFlagProvider ?: continue + flagProviders[getMapToken(p.revision, p.type, p.flag)] = p + } + } + + fun getFlagFor (type: EFlagType, flag: EntityFlag) : EFlagProvider? { + val revision = 530 + return flagProviders[getMapToken(revision, type, flag)] + } + + @JvmStatic fun getOrdinal (type: EFlagType, flag: EntityFlag) : Int { + return getFlagFor(type, flag)?.ordinal ?: -1 + } + + @JvmStatic fun getPresenceFlag (type: EFlagType, flag: EntityFlag) : Int { + return getFlagFor(type, flag)?.presenceFlag ?: 0 + } + + private fun getMapToken (revision: Int, type: EFlagType, flag: EntityFlag) : Int { + var token = ((revision shl 8) + (type.ordinal shl 4) + flag.ordinal) + return token + } +} diff --git a/Server/src/main/core/game/world/update/flag/NPCFlags530.kt b/Server/src/main/core/game/world/update/flag/NPCFlags530.kt new file mode 100644 index 000000000..4a8e98745 --- /dev/null +++ b/Server/src/main/core/game/world/update/flag/NPCFlags530.kt @@ -0,0 +1,108 @@ +package core.game.world.update.flag + +import core.net.packet.IoBuffer +import core.game.world.update.flag.context.* +import core.game.world.update.flag.* +import core.game.world.map.Location +import core.game.node.entity.Entity +import core.game.node.entity.impl.ForceMovement +import core.game.node.entity.player.Player +import core.tools.* +import core.api.* + +import java.nio.charset.StandardCharsets +import kotlin.reflect.* + +sealed class NPCFlags530 (p: Int, o: Int, f: EntityFlag) : EFlagProvider (530, EFlagType.NPC, p, o, f) { + class PrimaryHit : NPCFlags530 (0x40, 0, EntityFlag.PrimaryHit) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is HitMark) { + logInvalidType (context, typeOf()) + return + } + buffer.p1 (context.damage) + buffer.p1neg (context.type) + + val e = context.entity + var ratio = 255 + val max = e.skills.maximumLifepoints + if (e.skills.lifepoints < max) + ratio = e.skills.lifepoints * 255 / max + buffer.p1sub (ratio) + } + } + class SecondaryHit : NPCFlags530 (0x2, 1, EntityFlag.SecondaryHit) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is HitMark) { + logInvalidType (context, typeOf()) + return + } + buffer.p1neg (context.damage) + buffer.p1sub (context.type) + } + } + class Animate : NPCFlags530 (0x10, 2, EntityFlag.Animate) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Animation) { + logInvalidType (context, typeOf()) + return + } + buffer.p2 (context.id) + buffer.p1 (context.delay) + } + } + class FaceEntity : NPCFlags530 (0x4, 3, EntityFlag.FaceEntity) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Entity?) { + logInvalidType (context, typeOf()) + return + } + if (context == null) { + buffer.p2add (-1) + } else { + buffer.p2add (context.getClientIndex()) + } + } + } + class SpotAnim : NPCFlags530 (0x80, 4, EntityFlag.SpotAnim) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Graphics) { + logInvalidType (context, typeOf()) + return + } + buffer.p2add (context.id) + buffer.ip4 ((context.height shl 16) + context.delay) + } + } + class TypeSwap : NPCFlags530 (0x1, 5, EntityFlag.TypeSwap) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Int) { + logInvalidType (context, typeOf()) + return + } + buffer.ip2 (context) + } + } + class ForceChat : NPCFlags530 (0x20, 6, EntityFlag.ForceChat) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is String) { + logInvalidType (context, typeOf()) + return + } + buffer.putString (context) + } + } + class AnimationSequence : NPCFlags530 (0x100, 7, EntityFlag.AnimSeq) { + //TODO + } + class FaceLocation : NPCFlags530 (0x200, 8, EntityFlag.FaceLocation) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Location) { + logInvalidType (context, typeOf()) + return + } + buffer.p2add ((context.x shl 1) + 1) + buffer.p2 ((context.y shl 1) + 1) + } + } +} diff --git a/Server/src/main/core/game/world/update/flag/PlayerFlags530.kt b/Server/src/main/core/game/world/update/flag/PlayerFlags530.kt new file mode 100644 index 000000000..4fb0eddfc --- /dev/null +++ b/Server/src/main/core/game/world/update/flag/PlayerFlags530.kt @@ -0,0 +1,195 @@ +package core.game.world.update.flag + +import core.net.packet.IoBuffer +import core.game.world.update.flag.context.* +import core.game.world.update.flag.* +import core.game.world.map.Location +import core.game.node.entity.Entity +import core.game.node.entity.impl.ForceMovement +import core.game.node.entity.player.Player +import core.tools.* +import core.api.* + +import java.nio.charset.StandardCharsets +import kotlin.reflect.* + +sealed class PlayerFlags530 (p: Int, o: Int, f: EntityFlag) : EFlagProvider (530, EFlagType.Player, p, o, f) { + class Chat : PlayerFlags530 (0x80, 0, EntityFlag.Chat) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is ChatMessage) { + logInvalidType (context, typeOf()) + return + } + buffer.ip2 (context.effects) + if (context.isQuickChat) + buffer.p1 (4) + else + buffer.p1 (context.chatIcon) + val chatBuf = ByteArray(256) + chatBuf[0] = context.text.length.toByte() + val offset = 1 + StringUtils.encryptPlayerChat ( + chatBuf, + 0, 1, + context.text.length, + context.text.toByteArray(StandardCharsets.UTF_8) + ) + buffer.p1 (offset + 1) + buffer.putReverse (chatBuf, 0, offset) + } + } + class PrimaryHit : PlayerFlags530 (0x1, 1, EntityFlag.PrimaryHit) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is HitMark) { + logInvalidType (context, typeOf()) + return + } + buffer.psmarts (context.damage) + buffer.p1add (context.type) + + var ratio = 255 + var e = context.entity + var max = e.skills.maximumLifepoints + if (max > e.skills.lifepoints) + ratio = e.skills.lifepoints * 255 / max + buffer.p1sub (ratio) + } + } + class Animate : PlayerFlags530 (0x8, 2, EntityFlag.Animate) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Animation) { + logInvalidType (context, typeOf()) + return + } + buffer.p2 (context.id) + buffer.p1 (context.delay) + } + } + class Appearance : PlayerFlags530 (0x4, 3, EntityFlag.Appearance) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Player) { + logInvalidType (context, typeOf()) + return + } + val appearance = context.appearance + appearance.prepareBodyData(context) + var settings = appearance.gender.toByte().toInt() + val nonPvp = context.skullManager.isWilderness && context.skullManager.isWildernessDisabled + if (context.size() > 1) + settings += (context.size() - 1) shl 3 + if (nonPvp) + settings += 0x4 //flag the player as being non-pvp, which shows skill level instead of combat level. + + buffer.p1 (0) //stand-in for size. + val startPos = buffer.toByteBuffer().position() + + buffer.p1 (settings) + buffer.p1 (appearance.skullIcon) + buffer.p1 (appearance.headIcon) + val npcId = appearance.npcId + if (npcId == -1) { + val parts = appearance.bodyParts + for (i in 0 until 12) { + if (parts[i] == 0) buffer.p1 (0) + else buffer.p2 (parts[i]) + } + } else { + buffer.p2 (-1) + buffer.p2 (npcId) + buffer.p1 (255) + } + arrayOf ( appearance.hair, appearance.torso, appearance.legs, appearance.feet, appearance.skin ).forEach { part -> + buffer.p1 (part.color) + } + buffer.p2 (appearance.renderAnimation) + buffer.p8 (StringUtils.stringToLong(context.username)) + if (nonPvp) { + buffer.p1 (context.properties.currentCombatLevel) //with summoning + buffer.p2 (context.skills.getTotalLevel()) + } else { + buffer.p1 (context.properties.currentCombatLevel) //without summoning + buffer.p1 (context.properties.combatLevel) //with summoning + buffer.p1 (context.skullManager.level) //combat range + } + buffer.p1 (0) //this is the sound radius, and if set, 4 shorts need to be set as well which include the sound IDs + //to play to everyone in that radius when the player is rendered onscreen for the first time. + buffer.psizeadd (buffer.toByteBuffer().position() - startPos) + } + } + class FaceEntity : PlayerFlags530 (0x2, 4, EntityFlag.FaceEntity) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Entity?) { + logInvalidType (context, typeOf()) + return + } + if (context == null) + buffer.p2add (-1) + else + buffer.p2add (context.getClientIndex()) + } + } + class ForceMove : PlayerFlags530 (0x400, 5, EntityFlag.ForceMove) { + override fun writeToDynamic (buffer: IoBuffer, context: Any?, e: Entity) { + if (context !is ForceMoveCtx) { + logInvalidType (context, typeOf()) + return + } + if (e !is Player) { + logInvalidType (context, typeOf()) + return + } + val l = e.playerFlags.getLastSceneGraph() + //start location + buffer.p1neg (context.start.getSceneX(l)) + buffer.p1 (context.start.getSceneY(l)) + //end location + buffer.p1add (context.dest.getSceneX(l)) + buffer.p1 (context.dest.getSceneY(l)) + //arrival times (in client cycles) + buffer.ip2 (context.startArrive) //# of client cycles to start location + buffer.ip2 (context.startArrive + context.destArrive) //# of client cycles to end location + buffer.p1neg (context.direction.toInteger()) //direction of movement + } + } + class ForceChat : PlayerFlags530 (0x20, 6, EntityFlag.ForceChat) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is String) { + logInvalidType (context, typeOf()) + return + } + buffer.putString(context) + } + } + class SecondaryHit : PlayerFlags530 (0x200, 7, EntityFlag.SecondaryHit) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is HitMark) { + logInvalidType (context, typeOf()) + return + } + buffer.psmarts (context.damage) + buffer.p1sub (context.type) + } + } + class AnimationSequence : PlayerFlags530 (0x800, 8, EntityFlag.AnimSeq) { + //TODO + } + class SpotAnim : PlayerFlags530 (0x100, 9, EntityFlag.SpotAnim) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Graphics) { + logInvalidType (context, typeOf()) + return + } + buffer.ip2 (context.id) + buffer.mp4 ((context.height shl 16) + context.delay) + } + } + class FaceLocation : PlayerFlags530 (0x40, 10, EntityFlag.FaceLocation) { + override fun writeTo (buffer: IoBuffer, context: Any?) { + if (context !is Location) { + logInvalidType (context, typeOf()) + return + } + buffer.p2 ((context.x shl 1) + 1) + buffer.ip2add ((context.y shl 1) + 1) + } + } +} diff --git a/Server/src/main/core/game/world/update/flag/context/ChatMessage.kt b/Server/src/main/core/game/world/update/flag/context/ChatMessage.kt index e1f6c7819..c7ee24fa1 100644 --- a/Server/src/main/core/game/world/update/flag/context/ChatMessage.kt +++ b/Server/src/main/core/game/world/update/flag/context/ChatMessage.kt @@ -1,6 +1,7 @@ package core.game.world.update.flag.context import core.game.node.entity.player.Player +import core.game.node.entity.player.info.Rights /** * Represents a chat message. @@ -35,6 +36,8 @@ class ChatMessage var numChars = numChars private set + var chatIcon = Rights.getChatIcon(player) + @JvmField var isQuickChat = false -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/world/update/flag/context/ForceMoveCtx.kt b/Server/src/main/core/game/world/update/flag/context/ForceMoveCtx.kt new file mode 100644 index 000000000..2c28531c8 --- /dev/null +++ b/Server/src/main/core/game/world/update/flag/context/ForceMoveCtx.kt @@ -0,0 +1,5 @@ +package core.game.world.update.flag.context + +import core.game.world.map.* + +data class ForceMoveCtx (val start: Location, val dest: Location, val startArrive: Int, val destArrive: Int, val direction: Direction) diff --git a/Server/src/main/core/game/world/update/flag/context/HitMark.java b/Server/src/main/core/game/world/update/flag/context/HitMark.java index ea6428624..7df5c73f7 100644 --- a/Server/src/main/core/game/world/update/flag/context/HitMark.java +++ b/Server/src/main/core/game/world/update/flag/context/HitMark.java @@ -27,6 +27,8 @@ public class HitMark { */ private final Entity entity; + public boolean showHealthBar = true; + /** * Constructs a new {@code HitMark} {@code Object}. * @param damage The amount of damage. @@ -39,6 +41,13 @@ public class HitMark { this.entity = entity; } + public HitMark(int damage, int type, Entity entity, boolean showHealthBar) { + this.damage = damage; + this.type = type; + this.entity = entity; + this.showHealthBar = showHealthBar; + } + /** * Gets the damage. * @return The damage. @@ -77,4 +86,4 @@ public class HitMark { public void setLifepoints(int lifepoints) { this.lifepoints = lifepoints; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/world/update/flag/npc/NPCAnimation.java b/Server/src/main/core/game/world/update/flag/npc/NPCAnimation.java deleted file mode 100644 index b87ae5dd9..000000000 --- a/Server/src/main/core/game/world/update/flag/npc/NPCAnimation.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.game.world.update.flag.npc; - -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.Animation; -import core.net.packet.IoBuffer; - -/** - * The NPC animation update flag. - * @author Emperor - * - */ -public final class NPCAnimation extends UpdateFlag { - - /** - * Constructs a new {@code NPCAnimation} {@code Object}. - * @param context The animation. - */ - public NPCAnimation(Animation context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putShort(context.getId()).put(context.getDelay()); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 2; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x10; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/npc/NPCFaceEntity.java b/Server/src/main/core/game/world/update/flag/npc/NPCFaceEntity.java deleted file mode 100644 index 5f4098db3..000000000 --- a/Server/src/main/core/game/world/update/flag/npc/NPCFaceEntity.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.game.world.update.flag.npc; - -import core.game.node.entity.Entity; -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; - -/** - * The face entity update flag for NPCs. - * @author Emperor - * - */ -public final class NPCFaceEntity extends UpdateFlag { - - /** - * Constructs a new {@code NPCFaceEntity} {@code Object}. - * @param context The context. - */ - public NPCFaceEntity(Entity context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putShortA(context == null ? -1 : context.getClientIndex()); - } - - @Override - public int data() { - return 0x4; - } - - @Override - public int ordinal() { - return getOrdinal(); - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int getOrdinal() { - return 3; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/npc/NPCFaceLocation.java b/Server/src/main/core/game/world/update/flag/npc/NPCFaceLocation.java deleted file mode 100644 index 922d14258..000000000 --- a/Server/src/main/core/game/world/update/flag/npc/NPCFaceLocation.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.game.world.update.flag.npc; - -import core.game.world.map.Location; -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; - -/** - * The NPC face coordinates update flag. - * @author Emperor - * - */ -public final class NPCFaceLocation extends UpdateFlag { - - /** - * Constructs a new {@code NPCFaceLocation} {@code Object}. - * @param context The location to face. - */ - public NPCFaceLocation(Location context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putShortA((context.getX() << 1) + 1).putShort((context.getY() << 1) + 1); - } - - @Override - public int data() { - return 0x200; - } - - @Override - public int ordinal() { - return getOrdinal(); - } - - /** - * Gets the mask ordinal. - * @return The ordinal. - */ - public static int getOrdinal() { - return 8; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/npc/NPCForceChat.java b/Server/src/main/core/game/world/update/flag/npc/NPCForceChat.java deleted file mode 100644 index 1a6b66658..000000000 --- a/Server/src/main/core/game/world/update/flag/npc/NPCForceChat.java +++ /dev/null @@ -1,43 +0,0 @@ -package core.game.world.update.flag.npc; - -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; - -/** - * The NPC force chat update flag. - * @author Emperor - * - */ -public final class NPCForceChat extends UpdateFlag { - - /** - * Constructs a new {@code NPCForceChat} {@code Object}. - * @param context The chat message. - */ - public NPCForceChat(String context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putString(context); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 6; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x20; - } -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/npc/NPCGraphic.java b/Server/src/main/core/game/world/update/flag/npc/NPCGraphic.java deleted file mode 100644 index f15c01fa6..000000000 --- a/Server/src/main/core/game/world/update/flag/npc/NPCGraphic.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.game.world.update.flag.npc; - -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.Graphics; -import core.net.packet.IoBuffer; - -/** - * Handles an NPC's graphic update flag. - * @author Emperor - * - */ -public final class NPCGraphic extends UpdateFlag { - - /** - * Constructs a new {@code NPCGraphic} {@code Object}. - * @param context The graphics. - */ - public NPCGraphic(Graphics context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putShortA(context.getId()).putLEInt(context.getHeight() << 16 | context.getDelay()); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 4; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x80; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/npc/NPCHitFlag.java b/Server/src/main/core/game/world/update/flag/npc/NPCHitFlag.java deleted file mode 100644 index 7fbde01ac..000000000 --- a/Server/src/main/core/game/world/update/flag/npc/NPCHitFlag.java +++ /dev/null @@ -1,56 +0,0 @@ -package core.game.world.update.flag.npc; - -import core.game.node.entity.Entity; -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.HitMark; -import core.net.packet.IoBuffer; - -/** - * The NPC's main hit update flag. - * @author Emperor - * - */ -public final class NPCHitFlag extends UpdateFlag { - - /** - * Constructs a new {@code NPCHitFlag} {@code Object}. - * @param context The hit mark. - */ - public NPCHitFlag(HitMark context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - Entity e = context.getEntity(); - int max = e.getSkills().getMaximumLifepoints(); - int ratio = 0; - if (max > 0) { - if (max < e.getSkills().getLifepoints()) { - ratio = 255; - } else { - ratio = e.getSkills().getLifepoints() * 255 / max; - } - } - buffer.put(context.getDamage()).putC(context.getType()).putS(ratio); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 0; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x40; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/npc/NPCHitFlag1.java b/Server/src/main/core/game/world/update/flag/npc/NPCHitFlag1.java deleted file mode 100644 index e443f6f0f..000000000 --- a/Server/src/main/core/game/world/update/flag/npc/NPCHitFlag1.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.game.world.update.flag.npc; - -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.HitMark; -import core.net.packet.IoBuffer; - -/** - * The NPC's supporting hit update flag. - * @author Emperor - * - */ -public class NPCHitFlag1 extends UpdateFlag { - - /** - * Constructs a new {@code NPCHitFlag1} {@code Object}. - * @param context The hit mark. - */ - public NPCHitFlag1(HitMark context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putC(context.getDamage()).putS(context.getType()); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 1; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x2; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/npc/NPCSwitchId.java b/Server/src/main/core/game/world/update/flag/npc/NPCSwitchId.java deleted file mode 100644 index a72c45f1e..000000000 --- a/Server/src/main/core/game/world/update/flag/npc/NPCSwitchId.java +++ /dev/null @@ -1,44 +0,0 @@ -package core.game.world.update.flag.npc; - -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; - -/** - * The switch NPC id update flag. - * @author Emperor - * - */ -public final class NPCSwitchId extends UpdateFlag { - - /** - * Constructs a new {@code NPCSwitchId} {@code Object}. - * @param context The new NPC id. - */ - public NPCSwitchId(int context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putLEShort(context); - } - - @Override - public int data() { - return 0x1; - } - - @Override - public int ordinal() { - return getOrdinal(); - } - - /** - * Gets the mask ordinal. - * @return The ordinal. - */ - public static int getOrdinal() { - return 5; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/AnimationFlag.java b/Server/src/main/core/game/world/update/flag/player/AnimationFlag.java deleted file mode 100644 index 925602e21..000000000 --- a/Server/src/main/core/game/world/update/flag/player/AnimationFlag.java +++ /dev/null @@ -1,43 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.Animation; -import core.net.packet.IoBuffer; - -/** - * Handles the animation update flag. - * @author Emperor - */ -public final class AnimationFlag extends UpdateFlag { - - /** - * Constructs a new {@code AnimationFlag} {@code Object}. - */ - public AnimationFlag(Animation context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putShort(context.getId()); - buffer.put(context.getDelay()); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 2; - } - - /** - * Gets the mask data of the animation update flag. - * @return The mask data. - */ - public static int maskData() { - return 0x8; - } -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/AppearanceFlag.java b/Server/src/main/core/game/world/update/flag/player/AppearanceFlag.java deleted file mode 100644 index 3fb42f2bb..000000000 --- a/Server/src/main/core/game/world/update/flag/player/AppearanceFlag.java +++ /dev/null @@ -1,91 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.appearance.Appearance; -import core.game.node.entity.player.link.appearance.BodyPart; -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; -import core.tools.StringUtils; - -/** - * Handles the appearance update flag. - * @author Emperor - * - */ -public final class AppearanceFlag extends UpdateFlag { - - /** - * Constructs a new {@code AppearanceFlag} {@code Object}. - * @param player The player. - */ - public AppearanceFlag(Player player) { - super(player); - } - - @Override - public void write(IoBuffer buffer) { - Appearance appearance = context.getAppearance(); - appearance.prepareBodyData(context); - IoBuffer block = new IoBuffer(); - int settings = appearance.getGender().toByte(); - if (context.size() > 1) { - settings |= (context.size() - 1) << 3; - } - block.put(settings); // settings hash. - block.put(appearance.getSkullIcon()); // Skull icon - block.put(appearance.getHeadIcon()); // Head icon - int npcId = appearance.getNpcId(); - if (npcId == -1) { - int[] parts = appearance.getBodyParts(); - for (int i = 0; i < 12; i++) { - int value = parts[i]; - if (value == 0) { - block.put(0); - } else { - block.putShort(value); - } - } - } else { - block.putShort(-1); - block.putShort(npcId); - block.put(255); - } - final BodyPart[] colors = new BodyPart[] { appearance.getHair(), appearance.getTorso(), appearance.getLegs(), appearance.getFeet(), appearance.getSkin() }; - for (int i = 0; i < colors.length; i++) {// colours - block.put(colors[i].getColor()); - } - block.putShort(appearance.getRenderAnimation()); - block.putLong(StringUtils.stringToLong(context.getUsername())); - block.put(context.getProperties().getCurrentCombatLevel()); - block.putShort(0); - block.put(0); - buffer.putA(block.toByteBuffer().position()); - buffer.put(block); - } - - @Override - public int data() { - return getData(); - } - - @Override - public int ordinal() { - return getOrdinal(); - } - - /** - * Gets the ordinal for this flag. - * @return The flag ordinal. - */ - public static int getOrdinal() { - return 3; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int getData() { - return 0x4; - } -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/ChatFlag.java b/Server/src/main/core/game/world/update/flag/player/ChatFlag.java deleted file mode 100644 index cdefd314d..000000000 --- a/Server/src/main/core/game/world/update/flag/player/ChatFlag.java +++ /dev/null @@ -1,59 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.node.entity.player.info.Rights; -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.ChatMessage; -import core.net.packet.IoBuffer; -import core.tools.StringUtils; - -import java.nio.charset.StandardCharsets; - -/** - * Handles the chat flag. - * @author Emperor - */ -public class ChatFlag extends UpdateFlag { - - /** - * Constructs a new {@code ChatFlag.java} {@code Object}. - * @param context The context. - */ - public ChatFlag(ChatMessage context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - byte[] chatStr = new byte[256]; - chatStr[0] = (byte) context.getText().length(); - int offset = 1 + StringUtils.encryptPlayerChat(chatStr, 0, 1, context.getText().length(), context.getText().getBytes(StandardCharsets.UTF_8)); - buffer.putLEShort(context.getEffects()); // 0x8000 does something (you'd - // need to send something - // extra. - if(context.isQuickChat){ - buffer.put((byte) 4); - } else { - buffer.put((byte) Rights.getChatIcon(context.getPlayer())); - } - buffer.put(offset + 1); - buffer.putReverse(chatStr, 0, offset); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 0; - } - - /** - * Gets the mask data of the chat update flag. - * @return The mask data. - */ - public static int maskData() { - return 0x80; - } -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/FaceEntityFlag.java b/Server/src/main/core/game/world/update/flag/player/FaceEntityFlag.java deleted file mode 100644 index fa2327027..000000000 --- a/Server/src/main/core/game/world/update/flag/player/FaceEntityFlag.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.node.entity.Entity; -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; - -/** - * The face entity update flag. - * @author Emperor - * - */ -public final class FaceEntityFlag extends UpdateFlag { - - /** - * Constructs a new {@code FaceEntityFlag} {@code Object}. - * @param context The entity to face. - */ - public FaceEntityFlag(Entity context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putShortA(context == null ? -1 : context.getClientIndex()); - } - - @Override - public int data() { - return 0x2; - } - - @Override - public int ordinal() { - return getOrdinal(); - } - - /** - * Gets the mask ordinal. - * @return The ordinal. - */ - public static int getOrdinal() { - return 4; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/FaceLocationFlag.java b/Server/src/main/core/game/world/update/flag/player/FaceLocationFlag.java deleted file mode 100644 index 022d33a71..000000000 --- a/Server/src/main/core/game/world/update/flag/player/FaceLocationFlag.java +++ /dev/null @@ -1,84 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.node.Node; -import core.game.node.scenery.Scenery; -import core.game.world.map.Location; -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; - -/** - * Handles the face coordinates update flag. - * @author Emperor - */ -public class FaceLocationFlag extends UpdateFlag { - - /** - * Constructs a new {@code FaceLocationFlag} {@code Object}. - * @param location The location to face. - */ - public FaceLocationFlag(Location location) { - super(location); - } - - /** - * Gets the face location of the node. - * @param n The facing node. - * @param node The node to face. - * @return The location. - */ - public static Location getFaceLocation(Node n, Node node) { - int x = node.size() >> 1; - int y = node.size() >> 1; - if (node instanceof Scenery) { - Scenery o = (Scenery) node; - x = o.getDefinition().sizeX >> 1; - y = o.getDefinition().sizeY >> 1; - if (o.getRotation() % 2 != 0) { - x = y; - y = o.getDefinition().sizeX >> 1; - } - if (n.getLocation().equals(o.getLocation()) && node.size() == 1) { - switch (o.getRotation()) { - case 0: - x -= 1; - break; - case 1: - y += 1; - break; - case 2: - x += 1; - break; - case 3: - y -= 1; - break; - } - } - } - return node.getLocation().transform(x, y, 0); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putShort((context.getX() << 1) + 1); - buffer.putLEShortA((context.getY() << 1) + 1); - } - - @Override - public int data() { - return 0x40; - } - - @Override - public int ordinal() { - return getOrdinal(); - } - - /** - * Gets the mask ordinal. - * @return The ordinal. - */ - public static int getOrdinal() { - return 10; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/ForceChatFlag.java b/Server/src/main/core/game/world/update/flag/player/ForceChatFlag.java deleted file mode 100644 index 318d008ed..000000000 --- a/Server/src/main/core/game/world/update/flag/player/ForceChatFlag.java +++ /dev/null @@ -1,44 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; - -/** - * The force chat update flag. - * @author Emperor - * - */ -public final class ForceChatFlag extends UpdateFlag { - - /** - * Constructs a new {@code ForceChatFlag} {@code Object}. - * @param context The chat message. - */ - public ForceChatFlag(String context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putString(context); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 6; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x20; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/ForceMovementFlag.java b/Server/src/main/core/game/world/update/flag/player/ForceMovementFlag.java deleted file mode 100644 index 5625e51a0..000000000 --- a/Server/src/main/core/game/world/update/flag/player/ForceMovementFlag.java +++ /dev/null @@ -1,60 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.node.entity.Entity; -import core.game.node.entity.impl.ForceMovement; -import core.game.node.entity.player.Player; -import core.game.world.map.Location; -import core.game.world.update.flag.UpdateFlag; -import core.net.packet.IoBuffer; - -/** - * Handles the force movement player update flag. - * @author Emperor - * - */ -public final class ForceMovementFlag extends UpdateFlag { - - /** - * Constructs a new {@code ForceMovementFlag} {@code Object}. - * @param forceMovement The force movement data. - */ - public ForceMovementFlag(ForceMovement forceMovement) { - super(forceMovement); - } - - @Override - public void write(IoBuffer buffer) { - } - - @Override - public void writeDynamic(IoBuffer buffer, Entity e) { - Location l = ((Player) e).getPlayerFlags().getLastSceneGraph(); - buffer.putC(context.getStart().getSceneX(l)) // Start location - .put(context.getStart().getSceneY(l)).putA(context.getDestination().getSceneX(l)) // Destination - // location - .put(context.getDestination().getSceneY(l)).putLEShort(context.getCommenceSpeed() * 30)// Commencing - // speed - .putLEShort((context.getCommenceSpeed() * 30) + (context.getPathSpeed() * 30 + 1)) // Path - // speed - .putC(context.getDirection().toInteger()); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 5; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x400; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/GraphicFlag.java b/Server/src/main/core/game/world/update/flag/player/GraphicFlag.java deleted file mode 100644 index 661a9472b..000000000 --- a/Server/src/main/core/game/world/update/flag/player/GraphicFlag.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.Graphics; -import core.net.packet.IoBuffer; - -/** - * Handles the graphic update flag. - * @author Emperor - * - */ -public final class GraphicFlag extends UpdateFlag { - - /** - * Constructs a new {@code GraphicFlag} {@code Object}. - * @param context The context. - */ - public GraphicFlag(Graphics context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putLEShort(context.getId()); - buffer.putIntB(context.getHeight() << 16 | context.getDelay()); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 9; - } - - /** - * Gets the mask data of the graphic update flag. - * @return The mask data. - */ - public static int maskData() { - return 0x100; - } -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/HitUpdateFlag.java b/Server/src/main/core/game/world/update/flag/player/HitUpdateFlag.java deleted file mode 100644 index 702befba9..000000000 --- a/Server/src/main/core/game/world/update/flag/player/HitUpdateFlag.java +++ /dev/null @@ -1,52 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.node.entity.Entity; -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.HitMark; -import core.net.packet.IoBuffer; - -/** - * The main hit update flag. - * @author Emperor - * - */ -public final class HitUpdateFlag extends UpdateFlag { - - /** - * Constructs a new {@code HitUpdateFlag} {@code Object}. - * @param context The hit mark. - */ - public HitUpdateFlag(HitMark context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - Entity e = context.getEntity(); - int max = e.getSkills().getMaximumLifepoints(); - int ratio = 255; - if (max > e.getSkills().getLifepoints()) { - ratio = e.getSkills().getLifepoints() * 255 / max; - } - buffer.putSmart(context.getDamage()).putA(context.getType()).putS(ratio); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 1; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x1; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/game/world/update/flag/player/HitUpdateFlag1.java b/Server/src/main/core/game/world/update/flag/player/HitUpdateFlag1.java deleted file mode 100644 index a4f35bb4e..000000000 --- a/Server/src/main/core/game/world/update/flag/player/HitUpdateFlag1.java +++ /dev/null @@ -1,45 +0,0 @@ -package core.game.world.update.flag.player; - -import core.game.world.update.flag.UpdateFlag; -import core.game.world.update.flag.context.HitMark; -import core.net.packet.IoBuffer; - -/** - * The supportive hit update flag. - * @author Emperor - * - */ -public final class HitUpdateFlag1 extends UpdateFlag { - - /** - * Constructs a new {@code HitUpdateFlag1} {@code Object}. - * @param context The hit mark. - */ - public HitUpdateFlag1(HitMark context) { - super(context); - } - - @Override - public void write(IoBuffer buffer) { - buffer.putSmart(context.getDamage()).putS(context.getType()); - } - - @Override - public int data() { - return maskData(); - } - - @Override - public int ordinal() { - return 7; - } - - /** - * Gets the mask data. - * @return The mask data. - */ - public static int maskData() { - return 0x200; - } - -} \ No newline at end of file diff --git a/Server/src/main/core/net/packet/IoBuffer.java b/Server/src/main/core/net/packet/IoBuffer.java index 219d9c1a0..a08375c6f 100644 --- a/Server/src/main/core/net/packet/IoBuffer.java +++ b/Server/src/main/core/net/packet/IoBuffer.java @@ -92,6 +92,219 @@ public class IoBuffer { return this; } + /** + * What follows are put/get methods using authentic naming. + * The older methods are kept for the sake of backwards compatibility within the codebase. + */ + public IoBuffer p1 (int value) { + buf.put((byte) value); + return this; + } + + public IoBuffer p1add (int value) { + buf.put((byte) (value + 128)); + return this; + } + + public IoBuffer p1sub (int value) { + buf.put((byte) (128 - value)); + return this; + } + + public IoBuffer p1neg (int value) { + buf.put ((byte) -value); + return this; + } + + public IoBuffer p2 (int value) { + buf.put((byte) (value >> 8)); + buf.put((byte) value); + return this; + } + + public IoBuffer p2add (int value) { + buf.put((byte) (value >> 8)); + buf.put((byte) (value + 128)); + return this; + } + + public IoBuffer ip2 (int value) { + buf.put((byte) value); + buf.put((byte) (value >> 8)); + return this; + } + + public IoBuffer ip2add (int value) { + buf.put((byte) (value + 128)); + buf.put((byte) (value >> 8)); + return this; + } + + public IoBuffer p3 (int value) { + buf.put((byte) (value >> 16)); + buf.put((byte) (value >> 8)); + buf.put((byte) value); + return this; + } + + public IoBuffer ip3 (int value) { + buf.put((byte) value); + buf.put((byte) (value >> 8)); + buf.put((byte) (value >> 16)); + return this; + } + + public IoBuffer p4 (int value) { + buf.put((byte) (value >> 24)); + buf.put((byte) (value >> 16)); + buf.put((byte) (value >> 8)); + buf.put((byte) value); + return this; + } + + public IoBuffer ip4 (int value) { + buf.put((byte) value); + buf.put((byte) (value >> 8)); + buf.put((byte) (value >> 16)); + buf.put((byte) (value >> 24)); + return this; + } + + public IoBuffer mp4 (int value) { + buf.put((byte) (value >> 16)); + buf.put((byte) (value >> 24)); + buf.put((byte) value); + buf.put((byte) (value >> 8)); + return this; + } + + public IoBuffer imp4 (int value) { + buf.put((byte) (value >> 8)); + buf.put((byte) value); + buf.put((byte) (value >> 24)); + buf.put((byte) (value >> 16)); + return this; + } + + public IoBuffer p8 (long value) { + buf.put((byte) (value >> 56)); + buf.put((byte) (value >> 48)); + buf.put((byte) (value >> 40)); + buf.put((byte) (value >> 32)); + buf.put((byte) (value >> 24)); + buf.put((byte) (value >> 16)); + buf.put((byte) (value >> 8)); + buf.put((byte) value); + return this; + } + + public IoBuffer pVarInt (int value) { + if ((value & 0xffffff80) != 0) { + if ((value & 0xffffc000) != 0) { + if ((value & 0xFFE00000) != 0) { + if ((value & 0xF0000000) != 0) { + this.p1(value >>> 28 | 0x80); + } + this.p1(value >>> 21 | 0x80); + } + this.p1(value >>> 14 | 0x80); + } + this.p1(value >>> 7 | 0x80); + } + return this.p1(value & 0x7F); + } + + public IoBuffer pVarLong (int size, long value) { + int bytes = size - 1; + if (bytes < 0 || bytes > 7) + throw new IllegalArgumentException(); + for (int shift = bytes * 8; shift >= 0; shift -= 8) + this.p1 ((byte) (value >> shift)); + return this; + } + + public IoBuffer psmarts (int value) { + if (value >= 0 && value < 128) + this.p1(value); + else if (value >= 0 && value < 0x8000) + this.p2(value + 0x8000); + else + throw new IllegalArgumentException("smart out of range: $value"); + return this; + } + + public IoBuffer psize (int length) { + buf.put (buf.position() - length - 1, (byte) length); + return this; + } + + public IoBuffer psizeadd (int length) { + buf.put (buf.position() - length - 1, (byte) (length + 128)); + return this; + } + + public int g1() { + return buf.get() & 0xFF; + } + + public int g1add() { + return (buf.get() - 128) & 0xFF; + } + + public int g1neg() { + return -(buf.get() & 0xFF); + } + + public int g1sub() { + return (128 - buf.get()) & 0xFF; + } + + public int g2() { + return ((buf.get() & 0xFF) << 8) + (buf.get() & 0xFF); + } + + public int g2add() { + return ((buf.get() & 0xff) << 8) + ((buf.get() - 128) & 0xFF); + } + + public int ig2() { + return (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8); + } + + public int ig2add() { + return ((buf.get() - 128) & 0xFF) + ((buf.get() & 0xFF) << 8); + } + + public int g3() { + return ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 8) + (buf.get() & 0xFF); + } + + public int ig3() { + return (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8) + ((buf.get() & 0xFF) << 16); + } + + public int g4() { + return ((buf.get() & 0xFF) << 24) + ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 8) + (buf.get() & 0xFF); + } + + public int ig4() { + return (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8) + ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 24); + } + + public int m4() { + return ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 24) + (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8); + } + + public int im4() { + return ((buf.get() & 0xFF) << 8) + (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 24) + ((buf.get() & 0xFF) << 16); + } + + public long g8() { + long low = (long) this.g4() & 0xFFFFFFFFL; + long high = (long) this.g4() & 0xFFFFFFFFL; + return high + (low << 32); + } + /** * @param val * @return @@ -635,4 +848,4 @@ public class IoBuffer { return bitPosition; } -} \ No newline at end of file +} diff --git a/Server/src/main/core/net/packet/PacketProcessor.kt b/Server/src/main/core/net/packet/PacketProcessor.kt index be0c04150..3d0ef5d3c 100644 --- a/Server/src/main/core/net/packet/PacketProcessor.kt +++ b/Server/src/main/core/net/packet/PacketProcessor.kt @@ -25,7 +25,7 @@ import core.game.system.task.Pulse import core.game.world.map.Location import core.game.world.map.RegionManager import core.game.world.update.flag.context.ChatMessage -import core.game.world.update.flag.player.ChatFlag +import core.game.world.update.flag.* import core.net.amsc.MSPacketRepository import core.net.packet.context.PlayerContext import core.net.packet.out.ClearMinimapFlag @@ -229,7 +229,7 @@ object PacketProcessor { } PlayerMonitor.logChat(pkt.player, "public", pkt.message) val ctx = ChatMessage(pkt.player, pkt.message, pkt.effects, pkt.message.length) - pkt.player.updateMasks.register(ChatFlag(ctx)) + pkt.player.updateMasks.register(EntityFlag.Chat, ctx) } } is Packet.ChatSetting -> { diff --git a/Server/src/main/core/net/packet/QCRepository.kt b/Server/src/main/core/net/packet/QCRepository.kt index ac9a25ccb..b2b1ccb2a 100644 --- a/Server/src/main/core/net/packet/QCRepository.kt +++ b/Server/src/main/core/net/packet/QCRepository.kt @@ -11,7 +11,7 @@ import core.game.node.entity.player.Player import core.game.node.entity.skill.Skills import core.game.system.task.Pulse import core.game.world.update.flag.context.ChatMessage -import core.game.world.update.flag.player.ChatFlag +import core.game.world.update.flag.* import proto.management.ClanMessage import core.game.world.GameWorld.Pulser import core.net.packet.`in`.QCPacketType @@ -54,7 +54,7 @@ object QCRepository { ctx.isQuickChat = true Pulser.submit(object : Pulse(0, player) { override fun pulse(): Boolean { - player.updateMasks.register(ChatFlag(ctx)) + player.updateMasks.register(EntityFlag.Chat, ctx) return true } }) diff --git a/Server/src/main/core/tools/TickUtils.kt b/Server/src/main/core/tools/TickUtils.kt index a9c0d0755..8f9f9045b 100644 --- a/Server/src/main/core/tools/TickUtils.kt +++ b/Server/src/main/core/tools/TickUtils.kt @@ -2,6 +2,7 @@ package core.tools const val tick = 600 //ms const val second = 1000 //ms +const val cycle = 20 //ms fun secondsToTicks(seconds: Int): Int { val seconds = seconds * second //seconds -> ms @@ -13,6 +14,11 @@ fun ticksToSeconds(ticks: Int): Int { return ticksMs / 1000 } +fun cyclesToTicks (cycles: Int) : Int { + val cyclesPerTick = tick / cycle + return kotlin.math.ceil (cycles / cyclesPerTick.toDouble()).toInt() +} + fun minutesToTicks(minutes: Int): Int { val minutesMs = minutes * 60 * 1000 return minutesMs / tick @@ -24,4 +30,4 @@ fun ticksToMinutes(ticks: Int): Int { } const val ticksPerSecond = second / tick -const val ticksPerMinute = 60 * ticksPerSecond \ No newline at end of file +const val ticksPerMinute = 60 * ticksPerSecond