Merge remote-tracking branch 'upstream/master'

This commit is contained in:
skelsoft
2021-07-31 12:31:53 +10:00
24 changed files with 303 additions and 147 deletions
@@ -204,6 +204,7 @@ public final class DialogueInterpreter {
public boolean close() { public boolean close() {
if (dialogue != null || dialogueStage != null) { if (dialogue != null || dialogueStage != null) {
actions.clear(); actions.clear();
if (player.getInterfaceManager().getChatbox() != null && player.getInterfaceManager().getChatbox().getCloseEvent() != null) { if (player.getInterfaceManager().getChatbox() != null && player.getInterfaceManager().getChatbox().getCloseEvent() != null) {
return true; return true;
} }
@@ -211,8 +212,10 @@ public final class DialogueInterpreter {
dialogueStage = null; dialogueStage = null;
player.getInterfaceManager().closeChatbox(); player.getInterfaceManager().closeChatbox();
} }
if (dialogue != null && dialogue.close()) { if (dialogue != null) {
DialoguePlugin d = dialogue;
dialogue = null; dialogue = null;
d.close();
} }
} }
return dialogue == null && dialogueStage == null; return dialogue == null && dialogueStage == null;
@@ -122,6 +122,7 @@ public abstract class DialoguePlugin implements Plugin<Player> {
public boolean close() { public boolean close() {
player.getInterfaceManager().closeChatbox(); player.getInterfaceManager().closeChatbox();
player.getInterfaceManager().openChatbox(137); player.getInterfaceManager().openChatbox(137);
if(file != null) file.end();
finished = true; finished = true;
return true; return true;
} }
@@ -1,54 +0,0 @@
package core.game.system.task;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/**
* A class holding methods to execute tasks.
* @author Emperor
*/
public final class TaskExecutor {
/**
* The executor to use.
*/
private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor();
/**
* The SQL task executor.
*/
private static final ScheduledExecutorService SQL_EXECUTOR = Executors.newSingleThreadScheduledExecutor();
/**
* Constructs a new {@code TaskExecutor} {@code Object}.
*/
private TaskExecutor() {
/*
* empty.
*/
}
/**
* Executes an SQL handling task.
* @param task The task.
*/
public static void executeSQL(Runnable task) {
SQL_EXECUTOR.execute(task);
}
/**
* Executes the task.
* @param task The task to execute.
*/
public static void execute(Runnable task) {
EXECUTOR.execute(task);
}
/**
* Gets the executor.
* @return The executor.
*/
public static ScheduledExecutorService getExecutor() {
return EXECUTOR;
}
}
@@ -0,0 +1,33 @@
package core.game.system.task
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
/**
* A class holding methods to execute tasks.
* @author Emperor
*/
object TaskExecutor {
/**
* Executes an SQL handling task.
* @param task The task.
*/
@JvmStatic
fun executeSQL(task: () -> Unit) {
GlobalScope.launch {
task.invoke()
}
}
/**
* Executes the task.
* @param task The task to execute.
*/
@JvmStatic
fun execute(task: () -> Unit) {
GlobalScope.launch {
task.invoke()
}
}
}
@@ -10,6 +10,7 @@ import core.gui.ConsoleFrame;
import core.gui.ConsoleTab; import core.gui.ConsoleTab;
import core.tools.PlayerLoader; import core.tools.PlayerLoader;
import core.tools.StringUtils; import core.tools.StringUtils;
import kotlin.Unit;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.EtchedBorder; import javax.swing.border.EtchedBorder;
@@ -417,6 +418,7 @@ public final class UtilityTab extends ConsoleTab {
populating = true; populating = true;
players.clear(); players.clear();
TaskExecutor.execute(() -> { TaskExecutor.execute(() -> {
Thread.currentThread().setName("Utility Tab");
ConsoleFrame.getInstance().getPlayerTab().getPlayerNames().clear(); ConsoleFrame.getInstance().getPlayerTab().getPlayerNames().clear();
ConsoleFrame.getInstance().getPlayerTab().populatePlayerSearch(); ConsoleFrame.getInstance().getPlayerTab().populatePlayerSearch();
for (String name : ConsoleFrame.getInstance().getPlayerTab().getPlayerNames()) { for (String name : ConsoleFrame.getInstance().getPlayerTab().getPlayerNames()) {
@@ -435,6 +437,7 @@ public final class UtilityTab extends ConsoleTab {
populating = false; populating = false;
System.gc(); System.gc();
lblPlayersLoaded.setText("Players loaded: " + players.size()); lblPlayersLoaded.setText("Players loaded: " + players.size());
return Unit.INSTANCE;
}); });
} }
@@ -7,6 +7,7 @@ import core.net.EventProducer;
import core.net.IoSession; import core.net.IoSession;
import core.net.NioReactor; import core.net.NioReactor;
import core.net.producer.MSHSEventProducer; import core.net.producer.MSHSEventProducer;
import kotlin.Unit;
import rs09.game.node.entity.player.info.login.LoginParser; import rs09.game.node.entity.player.info.login.LoginParser;
import rs09.game.system.SystemLogger; import rs09.game.system.SystemLogger;
import rs09.game.world.GameWorld; import rs09.game.world.GameWorld;
@@ -76,15 +77,13 @@ public final class WorldCommunicator {
return; return;
} }
loginAttempts.put(parser.getDetails().getUsername(), parser); loginAttempts.put(parser.getDetails().getUsername(), parser);
TaskExecutor.executeSQL(new Runnable() { TaskExecutor.executeSQL(() -> {
@Override if (!parser.getDetails().parse()) {
public void run() { parser.getDetails().getSession().write(Response.INVALID_LOGIN_SERVER, true);
if (!parser.getDetails().parse()) { return Unit.INSTANCE;
parser.getDetails().getSession().write(Response.INVALID_LOGIN_SERVER, true);
return;
}
MSPacketRepository.sendPlayerRegistry(parser);
} }
MSPacketRepository.sendPlayerRegistry(parser);
return Unit.INSTANCE;
}); });
} }
@@ -8,6 +8,7 @@ import core.game.system.mysql.SQLManager;
import core.game.system.task.TaskExecutor; import core.game.system.task.TaskExecutor;
import core.net.Constants; import core.net.Constants;
import core.net.IoSession; import core.net.IoSession;
import kotlin.Unit;
import rs09.ServerConstants; import rs09.ServerConstants;
import rs09.game.system.SystemLogger; import rs09.game.system.SystemLogger;
import rs09.game.world.GameWorld; import rs09.game.world.GameWorld;
@@ -76,19 +77,17 @@ public class AccountRegister extends SQLEntryHandler<RegistryDetails> {
break; break;
} }
System.out.println(username); System.out.println(username);
TaskExecutor.executeSQL(new Runnable() { TaskExecutor.executeSQL(() -> {
@Override try {
public void run() { if (PlayerSQLManager.hasSqlAccount(username, "username")) {
try { response(session, RegistryResponse.NOT_AVAILBLE_USER);
if (PlayerSQLManager.hasSqlAccount(username, "username")) { return Unit.INSTANCE;
response(session, RegistryResponse.NOT_AVAILBLE_USER);
return;
}
response(session, RegistryResponse.SUCCESS);
} catch (SQLException e) {
e.printStackTrace();
} }
response(session, RegistryResponse.SUCCESS);
} catch (SQLException e) {
e.printStackTrace();
} }
return Unit.INSTANCE;
}); });
break; break;
case 36://Register details case 36://Register details
@@ -129,21 +128,19 @@ public class AccountRegister extends SQLEntryHandler<RegistryDetails> {
buffer.getInt(); buffer.getInt();
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
final RegistryDetails details = new RegistryDetails(name, SystemManager.getEncryption().hashPassword(password), new Date(year, month, day), country); final RegistryDetails details = new RegistryDetails(name, SystemManager.getEncryption().hashPassword(password), new Date(year, month, day), country);
TaskExecutor.execute(new Runnable() { TaskExecutor.execute(() -> {
@Override try {
public void run() { if (PlayerSQLManager.hasSqlAccount(name, "username")) {
try {
if (PlayerSQLManager.hasSqlAccount(name, "username")) {
response(session, RegistryResponse.CANNOT_CREATE);
return;
}
SQLEntryHandler.write(new AccountRegister(details));
response(session, RegistryResponse.SUCCESS);
} catch (SQLException e) {
e.printStackTrace();
response(session, RegistryResponse.CANNOT_CREATE); response(session, RegistryResponse.CANNOT_CREATE);
return Unit.INSTANCE;
} }
SQLEntryHandler.write(new AccountRegister(details));
response(session, RegistryResponse.SUCCESS);
} catch (SQLException e) {
e.printStackTrace();
response(session, RegistryResponse.CANNOT_CREATE);
} }
return Unit.INSTANCE;
}); });
break; break;
default: default:
+23 -2
View File
@@ -167,6 +167,26 @@ object ContentAPI {
if(!player.inventory.add(item)) GroundItemManager.create(item,player) if(!player.inventory.add(item)) GroundItemManager.create(item,player)
} }
/**
* Clears an NPC with the "poof" smoke graphics commonly seen with random event NPCs.
* @param npc the NPC object to initialize
*/
@JvmStatic
fun poofClear(npc: NPC){
submitWorldPulse(object : Pulse(){
var counter = 0
override fun pulse(): Boolean {
when(counter++){
2 -> {
npc.isInvisible = true; Graphics.send(Graphics(86), npc.location)
}
3 -> npc.clear().also { return true }
}
return false
}
})
}
/** /**
* Check if an item exists in a player's bank * Check if an item exists in a player's bank
* @param player the player whose bank to check * @param player the player whose bank to check
@@ -545,9 +565,10 @@ object ContentAPI {
*/ */
@JvmStatic @JvmStatic
fun openDialogue(player: Player, dialogue: Any, vararg args: Any) { fun openDialogue(player: Player, dialogue: Any, vararg args: Any) {
player.dialogueInterpreter.close()
when (dialogue) { when (dialogue) {
is Int -> player.dialogueInterpreter.open(dialogue, args) is Int -> player.dialogueInterpreter.open(dialogue, *args)
is DialogueFile -> player.dialogueInterpreter.open(dialogue, args) is DialogueFile -> player.dialogueInterpreter.open(dialogue, *args)
else -> SystemLogger.logErr("Invalid object type passed to openDialogue() -> ${dialogue.javaClass.simpleName}") else -> SystemLogger.logErr("Invalid object type passed to openDialogue() -> ${dialogue.javaClass.simpleName}")
} }
} }
@@ -340,7 +340,7 @@ class ScriptAPI(private val bot: Player) {
*/ */
fun walkTo(loc: Location){ fun walkTo(loc: Location){
if(!bot.walkingQueue.isMoving) { if(!bot.walkingQueue.isMoving) {
Executors.newSingleThreadExecutor().execute { GlobalScope.launch {
walkToIterator(loc) walkToIterator(loc)
} }
} }
@@ -645,7 +645,7 @@ class ScriptAPI(private val bot: Player) {
* @return true if item was successfully bought, false if not. * @return true if item was successfully bought, false if not.
*/ */
fun buyFromGE(bot: Player, itemID: Int, amount: Int){ fun buyFromGE(bot: Player, itemID: Int, amount: Int){
Executors.newSingleThreadExecutor().execute{ GlobalScope.launch {
val offer = GrandExchangeOffer() val offer = GrandExchangeOffer()
offer.itemID = itemID offer.itemID = itemID
offer.sell = false offer.sell = false
@@ -7,6 +7,8 @@ import core.game.world.map.Location
import core.game.world.map.RegionManager import core.game.world.map.RegionManager
import core.game.world.map.path.Pathfinder import core.game.world.map.path.Pathfinder
import core.tools.RandomFunction import core.tools.RandomFunction
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import rs09.game.content.activity.pestcontrol.PestControlHelper.GATE_ENTRIES import rs09.game.content.activity.pestcontrol.PestControlHelper.GATE_ENTRIES
import rs09.game.content.activity.pestcontrol.PestControlHelper.getMyPestControlSession1 import rs09.game.content.activity.pestcontrol.PestControlHelper.getMyPestControlSession1
import rs09.game.world.GameWorld import rs09.game.world.GameWorld
@@ -100,7 +102,7 @@ class CombatState(val bot: PestControlTestBot) {
fun randomWalkTo(loc: Location, radius: Int) { fun randomWalkTo(loc: Location, radius: Int) {
if(!bot.walkingQueue.isMoving) { if(!bot.walkingQueue.isMoving) {
Executors.newSingleThreadExecutor().execute { GlobalScope.launch {
var newloc = loc.transform(RandomFunction.random(radius, -radius), var newloc = loc.transform(RandomFunction.random(radius, -radius),
RandomFunction.random(radius, -radius), 0) RandomFunction.random(radius, -radius), 0)
walkToIterator(newloc) walkToIterator(newloc)
@@ -7,6 +7,8 @@ import core.game.world.map.Location
import core.game.world.map.RegionManager import core.game.world.map.RegionManager
import core.game.world.map.path.Pathfinder import core.game.world.map.path.Pathfinder
import core.tools.RandomFunction import core.tools.RandomFunction
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import rs09.game.content.activity.pestcontrol.PestControlHelper.GATE_ENTRIES import rs09.game.content.activity.pestcontrol.PestControlHelper.GATE_ENTRIES
import rs09.game.content.activity.pestcontrol.PestControlHelper.getMyPestControlSession2 import rs09.game.content.activity.pestcontrol.PestControlHelper.getMyPestControlSession2
import rs09.game.world.GameWorld import rs09.game.world.GameWorld
@@ -99,7 +101,8 @@ class CombatStateIntermediate(val bot: PestControlTestBot2) {
fun randomWalkTo(loc: Location, radius: Int) { fun randomWalkTo(loc: Location, radius: Int) {
if(!bot.walkingQueue.isMoving) { if(!bot.walkingQueue.isMoving) {
Executors.newSingleThreadExecutor().execute { GlobalScope.launch {
Thread.currentThread().name = "RandomWalkToIteratorBot"
var newloc = loc.transform(RandomFunction.random(radius, -radius), var newloc = loc.transform(RandomFunction.random(radius, -radius),
RandomFunction.random(radius, -radius), 0) RandomFunction.random(radius, -radius), 0)
walkToIterator(newloc) walkToIterator(newloc)
@@ -1,5 +1,6 @@
package rs09.game.content.ame package rs09.game.content.ame
import api.ContentAPI
import core.game.interaction.MovementPulse import core.game.interaction.MovementPulse
import core.game.node.entity.npc.NPC import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
@@ -36,18 +37,7 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
open fun terminate(){ open fun terminate(){
player.antiMacroHandler.event = null player.antiMacroHandler.event = null
if(initialized){ if(initialized){
Pulser.submit(object : Pulse(){ ContentAPI.poofClear(this)
var counter = 0
override fun pulse(): Boolean {
when(counter++){
2 -> {
isInvisible = true; Graphics.send(SMOKE_GRAPHICS, location)
}
3 -> clear().also { return true }
}
return false
}
})
} }
} }
@@ -73,9 +63,9 @@ abstract class RandomEventNPC(id: Int) : NPC(id) {
} }
override fun init() { override fun init() {
initialized = true
spawnLocation ?: terminate() spawnLocation ?: terminate()
location = spawnLocation location = spawnLocation
initialized = true
super.init() super.init()
} }
@@ -1,6 +1,8 @@
package rs09.game.content.ame.events.certer package rs09.game.content.ame.events.certer
import api.ContentAPI
import core.game.component.Component import core.game.component.Component
import core.game.node.item.GroundItemManager
import rs09.game.content.dialogue.DialogueFile import rs09.game.content.dialogue.DialogueFile
import rs09.tools.END_DIALOGUE import rs09.tools.END_DIALOGUE
@@ -21,7 +23,7 @@ class CerterDialogue(val initial: Boolean) : DialogueFile() {
0 -> if(!isCorrect) npc("Sorry, I don't think so.").also { stage = END_DIALOGUE; player!!.antiMacroHandler.event?.terminate() } else npc("Oh yes! That's right.").also { stage++ } 0 -> if(!isCorrect) npc("Sorry, I don't think so.").also { stage = END_DIALOGUE; player!!.antiMacroHandler.event?.terminate() } else npc("Oh yes! That's right.").also { stage++ }
1 -> { 1 -> {
npc("Please, take this as a thanks.") npc("Please, take this as a thanks.")
player!!.antiMacroHandler.event?.loot!!.roll(player!!).forEach { player!!.inventory.add(it) } player!!.antiMacroHandler.event?.loot!!.roll().forEach { ContentAPI.addItemOrDrop(player!!, it.id, it.amount) }
player!!.antiMacroHandler.event?.terminate() player!!.antiMacroHandler.event?.terminate()
stage = END_DIALOGUE stage = END_DIALOGUE
} }
@@ -75,7 +75,7 @@ abstract class DialogueFile {
return player(expr, *splitLines(msg!!)) return player(expr, *splitLines(msg!!))
} }
fun end(){ open fun end(){
if(interpreter != null) interpreter!!.close() if(interpreter != null) interpreter!!.close()
} }
@@ -0,0 +1,98 @@
package rs09.game.content.zone
import api.ContentAPI
import core.game.content.dialogue.FacialExpression
import core.game.node.entity.Entity
import core.game.node.entity.npc.NPC
import core.game.node.entity.player.Player
import core.game.node.entity.skill.Skills
import core.game.system.task.Pulse
import core.game.world.map.zone.MapZone
import core.game.world.map.zone.ZoneBorders
import core.game.world.map.zone.ZoneBuilder
import core.plugin.Initializable
import core.plugin.Plugin
import org.rs09.consts.NPCs
import rs09.game.content.dialogue.DialogueFile
import rs09.tools.secondsToTicks
import java.util.concurrent.TimeUnit
@Initializable
class FarmingPatchZone : MapZone("farming patch", true), Plugin<Any> {
val playersInZone = hashMapOf<Player,Int>()
override fun configure() {
registerRegion(12083)
registerRegion(10548)
register(ZoneBorders(3594,3521,3608,3532))
ContentAPI.submitWorldPulse(zonePulse)
}
override fun newInstance(arg: Any?): Plugin<Any> {
ZoneBuilder.configure(this)
return this
}
override fun fireEvent(identifier: String?, vararg args: Any?): Any {
return Unit
}
override fun enter(e: Entity?): Boolean {
if(e is Player && playersInZone[e] == null && ContentAPI.getStatLevel(e, Skills.FARMING) <= 15) {
playersInZone[e] = 0
}
return super.enter(e)
}
override fun leave(e: Entity?, logout: Boolean): Boolean {
if(e is Player){
playersInZone.remove(e)
}
return super.enter(e)
}
val zonePulse = object : Pulse(){
override fun pulse(): Boolean {
playersInZone.toList().forEach { (player, ticks) ->
if(ticks == secondsToTicks(TimeUnit.MINUTES.toSeconds(5).toInt())){
val npc = NPC(NPCs.GITHAN_7122)
npc.location = player.location
npc.init()
npc.moveStep()
npc.face(player)
ContentAPI.openDialogue(player, SpiritDialogue(true), npc)
} else if (ticks == secondsToTicks(TimeUnit.MINUTES.toSeconds(10).toInt())){
val npc = NPC(NPCs.GITHAN_7122)
npc.location = player.location
npc.init()
npc.moveStep()
npc.face(player)
ContentAPI.openDialogue(player, SpiritDialogue(false), npc)
playersInZone.remove(player)
}
playersInZone[player] = ticks + 1
}
return false
}
}
internal class SpiritDialogue(val is5: Boolean) : DialogueFile(){
override fun handle(componentID: Int, buttonID: Int) {
when(stage){
0 -> {
if(is5) npcl(FacialExpression.NEUTRAL, "In case you didn't know, you don't have to stand by your Farming patch. Your crops will grow even if you're not around.").also { stage++ }
else npcl(FacialExpression.NEUTRAL, " Did you know that if your Farming patch has fully grown, it will never catch disease or die? It will be perfectly safe until you choose to harvest it.").also { stage++ }
}
1 -> end()
}
}
override fun end(){
super.end()
ContentAPI.poofClear(npc ?: return)
}
}
}
@@ -1,5 +1,6 @@
package rs09.game.node.entity.skill.farming package rs09.game.node.entity.skill.farming
import api.ContentAPI
import core.cache.def.impl.SceneryDefinition import core.cache.def.impl.SceneryDefinition
import core.game.interaction.OptionHandler import core.game.interaction.OptionHandler
import core.game.node.Node import core.game.node.Node
@@ -66,12 +67,8 @@ class CropHarvester : OptionHandler() {
delay = 2 delay = 2
player.inventory.add(Item(plantable.harvestItem,1)) player.inventory.add(Item(plantable.harvestItem,1))
player.skills.addExperience(Skills.FARMING,plantable.harvestXP) player.skills.addExperience(Skills.FARMING,plantable.harvestXP)
patch.harvestAmt-- patch.rollLivesDecrement(ContentAPI.getDynLevel(player, Skills.FARMING), requiredItem == Items.MAGIC_SECATEURS_7409)
return patch.cropLives <= 0
if(patch.harvestAmt <= 0){
patch.clear()
}
return patch.harvestAmt <= 0
} }
}) })
@@ -4,6 +4,8 @@ import core.game.node.entity.player.Player
import core.tools.RandomFunction import core.tools.RandomFunction
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.ceil
import kotlin.math.min
class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantable?, var currentGrowthStage: Int, var isDiseased: Boolean, var isDead: Boolean, var isWatered: Boolean, var nextGrowth: Long, var harvestAmt: Int, var isCheckHealth: Boolean) { class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantable?, var currentGrowthStage: Int, var isDiseased: Boolean, var isDead: Boolean, var isWatered: Boolean, var nextGrowth: Long, var harvestAmt: Int, var isCheckHealth: Boolean) {
constructor(player: Player, patch: FarmingPatch) : this(player,patch,null,0,false,false,false,0L,0,false) constructor(player: Player, patch: FarmingPatch) : this(player,patch,null,0,false,false,false,0L,0,false)
@@ -11,22 +13,58 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
var diseaseMod = 0 var diseaseMod = 0
var compost = CompostType.NONE var compost = CompostType.NONE
var protectionPaid = false var protectionPaid = false
var cropLives = 3
fun setNewHarvestAmount() { fun setNewHarvestAmount() {
if(patch.type == PatchType.ALLOTMENT){ cropLives = 3
harvestAmt = RandomFunction.random(4,17) }
} else if(patch.type == PatchType.FLOWER || patch.type == PatchType.EVIL_TURNIP) {
harvestAmt = when (plantable) { fun rollLivesDecrement(farmingLevel: Int, magicSecateurs: Boolean){
Plantable.LIMPWURT_SEED, Plantable.WOAD_SEED -> 3 if(patch.type == PatchType.HERB){
else -> 1 //authentic formula thanks to released data.
var herbSaveLow = when(plantable){
Plantable.GUAM_SEED -> min(24 + farmingLevel, 80)
Plantable.MARRENTILL_SEED -> min(28 + farmingLevel, 80)
Plantable.TARROMIN_SEED -> min(31 + farmingLevel, 80)
Plantable.HARRALANDER_SEED -> min(36 + farmingLevel, 80)
Plantable.GOUT_TUBER -> min(39 + farmingLevel, 80)
Plantable.RANARR_SEED -> min(39 + farmingLevel, 80)
Plantable.SPIRIT_WEED_SEED -> min(43 + farmingLevel, 80)
Plantable.TOADFLAX_SEED -> min(43 + farmingLevel, 80)
Plantable.IRIT_SEED -> min(46 + farmingLevel, 80)
Plantable.AVANTOE_SEED -> min(50 + farmingLevel, 80)
Plantable.KWUARM_SEED -> min(54 + farmingLevel, 80)
Plantable.SNAPDRAGON_SEED -> min(57 + farmingLevel, 80)
Plantable.CADANTINE_SEED -> min(60 + farmingLevel, 80)
Plantable.LANTADYME_SEED -> min(64 + farmingLevel, 80)
Plantable.DWARF_WEED_SEED -> min(67 + farmingLevel, 80)
Plantable.TORSTOL_SEED -> min(71 + farmingLevel, 80)
else -> -1
}
if(magicSecateurs) herbSaveLow = ceil(1.10 * herbSaveLow).toInt()
val rand = RandomFunction.random(256)
if(rand > herbSaveLow){
cropLives -= 1
} }
} else if(patch.type == PatchType.HOPS){
harvestAmt = RandomFunction.random(3,35)
} else { } else {
harvestAmt = RandomFunction.random(3,5) //inauthentic formulae based on reported averages due to lack of formula
var chance = when(patch.type){
PatchType.ALLOTMENT -> 8 //average of 8 per life times 3 lives = average 24
PatchType.HOPS -> 6 //average of 6 per life times 3 lives = 18
PatchType.BELLADONNA -> 2 //average of 2 per life times 3 lives = 6
PatchType.CACTUS -> 3 //average of 3 per life times 3 lives = 9
else -> return
}
if(magicSecateurs) chance += ceil(1.10 * chance).toInt() //will increase average yield by roughly 3.
if(RandomFunction.roll(chance)) cropLives -= 1
} }
if(compost == CompostType.NORMAL) harvestAmt += 1
if(compost == CompostType.SUPER) harvestAmt += 2 if(cropLives <= 0) clear()
} }
fun isWeedy(): Boolean { fun isWeedy(): Boolean {
@@ -82,6 +120,11 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getCactusDeathValue()) if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getCactusDeathValue())
else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getCactusDiseaseValue()) else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getCactusDiseaseValue())
} }
PatchType.HERB -> {
if(isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getHerbDeathValue())
else if(isDiseased && !isDead) player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, getHerbDiseaseValue())
else player.varpManager.get(patch.varpIndex).setVarbit(patch.varpOffset, (plantable?.value ?: 0) + currentGrowthStage)
}
else -> {} else -> {}
} }
} }
@@ -144,6 +187,22 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
return (plantable?.value ?: 0) + currentGrowthStage + 16 return (plantable?.value ?: 0) + currentGrowthStage + 16
} }
private fun getHerbDiseaseValue(): Int {
return if (plantable?.value ?: -1 <= 103) {
128 + (((plantable?.ordinal ?: 0) - Plantable.GUAM_SEED.ordinal) * 3) + currentGrowthStage - 1
} else if (plantable == Plantable.SPIRIT_WEED_SEED) {
211 + currentGrowthStage - 1
} else {
198 + currentGrowthStage -1
}
}
private fun getHerbDeathValue(): Int {
return if(plantable == Plantable.GOUT_TUBER){
201 + currentGrowthStage - 1
} else 170 + currentGrowthStage - 1
}
private fun grow(){ private fun grow(){
if(isWeedy() && getCurrentState() > 0) { if(isWeedy() && getCurrentState() > 0) {
nextGrowth = System.currentTimeMillis() + 60000 nextGrowth = System.currentTimeMillis() + 60000
@@ -164,8 +223,8 @@ class Patch(val player: Player, val patch: FarmingPatch, var plantable: Plantabl
} }
if(RandomFunction.random(128) <= (17 - diseaseMod) && !isWatered && !isGrown() && !protectionPaid && !isFlowerProtected() && patch.type != PatchType.EVIL_TURNIP){ if(RandomFunction.random(128) <= (17 - diseaseMod) && !isWatered && !isGrown() && !protectionPaid && !isFlowerProtected() && patch.type != PatchType.EVIL_TURNIP){
//bush, tree, fruit tree and cactus can not disease on stage 1(0) of growth. //bush, tree, fruit tree, herb and cactus can not disease on stage 1(0) of growth.
if(!((patch.type == PatchType.BUSH || patch.type == PatchType.TREE || patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.CACTUS) && currentGrowthStage == 0)) { if(!((patch.type == PatchType.BUSH || patch.type == PatchType.TREE || patch.type == PatchType.FRUIT_TREE || patch.type == PatchType.CACTUS || patch.type == PatchType.HERB) && currentGrowthStage == 0)) {
isDiseased = true isDiseased = true
return return
} }
@@ -63,17 +63,18 @@ enum class Plantable(val itemID: Int, val value: Int, val stages: Int, val plant
MARRENTILL_SEED(5292,11,4,13.5,15.0,0.0,14,PatchType.HERB,Items.GRIMY_MARRENTILL_201), MARRENTILL_SEED(5292,11,4,13.5,15.0,0.0,14,PatchType.HERB,Items.GRIMY_MARRENTILL_201),
TARROMIN_SEED(5293,18,4,16.0,18.0,0.0,19,PatchType.HERB,Items.GRIMY_TARROMIN_203), TARROMIN_SEED(5293,18,4,16.0,18.0,0.0,19,PatchType.HERB,Items.GRIMY_TARROMIN_203),
HARRALANDER_SEED(5294,25,4,21.5,24.0,0.0,26,PatchType.HERB,Items.GRIMY_HARRALANDER_205), HARRALANDER_SEED(5294,25,4,21.5,24.0,0.0,26,PatchType.HERB,Items.GRIMY_HARRALANDER_205),
GOUT_TUBER(6311,32,4,105.0,45.0,0.0,29,PatchType.HERB,Items.GOUTWEED_3261), RANARR_SEED(5295,32,4,27.0,30.5,0.0,32,PatchType.HERB,Items.GRIMY_RANARR_207),
RANARR_SEED(5295,39,4,27.0,30.5,0.0,32,PatchType.HERB,Items.GRIMY_RANARR_207), AVANTOE_SEED(5298,39,4,54.5,61.5,0.0,50,PatchType.HERB,Items.GRIMY_AVANTOE_211),
TOADFLAX_SEED(5296,47,4,34.0,38.5,0.0,38,PatchType.HERB,Items.GRIMY_TOADFLAX_3049), TOADFLAX_SEED(5296,46,4,34.0,38.5,0.0,38,PatchType.HERB,Items.GRIMY_TOADFLAX_3049),
IRIT_SEED(5297,54,4,43.0,48.5,0.0,44,PatchType.HERB,Items.GRIMY_IRIT_209), IRIT_SEED(5297,53,4,43.0,48.5,0.0,44,PatchType.HERB,Items.GRIMY_IRIT_209),
AVANTOE_SEED(5298,204,4,54.5,61.5,0.0,50,PatchType.HERB,Items.GRIMY_AVANTOE_211),
KWUARM_SEED(5299,68,4,69.0,78.0,0.0,56,PatchType.HERB,Items.GRIMY_KWUARM_213), KWUARM_SEED(5299,68,4,69.0,78.0,0.0,56,PatchType.HERB,Items.GRIMY_KWUARM_213),
SNAPDRAGON_SEED(5300,75,4,87.5,98.5,0.0,62,PatchType.HERB,Items.GRIMY_SNAPDRAGON_3051), SNAPDRAGON_SEED(5300,75,4,87.5,98.5,0.0,62,PatchType.HERB,Items.GRIMY_SNAPDRAGON_3051),
CADANTINE_SEED(5301,82,4,106.5,120.0,0.0,67,PatchType.HERB,Items.GRIMY_CADANTINE_215), CADANTINE_SEED(5301,82,4,106.5,120.0,0.0,67,PatchType.HERB,Items.GRIMY_CADANTINE_215),
LANTADYME_SEED(5302,89,4,134.5,151.5,0.0,73,PatchType.HERB,Items.GRIMY_LANTADYME_2485), LANTADYME_SEED(5302,89,4,134.5,151.5,0.0,73,PatchType.HERB,Items.GRIMY_LANTADYME_2485),
DWARF_WEED_SEED(5303,96,4,170.5,192.0,0.0,79,PatchType.HERB,Items.GRIMY_DWARF_WEED_217), DWARF_WEED_SEED(5303,96,4,170.5,192.0,0.0,79,PatchType.HERB,Items.GRIMY_DWARF_WEED_217),
TORSTOL_SEED(5304,103,4,199.5,224.5,0.0,85,PatchType.HERB,Items.GRIMY_TORSTOL_219), TORSTOL_SEED(5304,103,4,199.5,224.5,0.0,85,PatchType.HERB,Items.GRIMY_TORSTOL_219),
GOUT_TUBER(6311,192,4,105.0,45.0,0.0,29,PatchType.HERB,Items.GOUTWEED_3261),
SPIRIT_WEED_SEED(12176, 204, 4, 32.0, 36.0, 0.0, 36, PatchType.HERB, Items.GRIMY_SPIRIT_WEED_12174),
//Other //Other
BELLADONNA_SEED(5281, 4, 4, 91.0, 128.0, 0.0, 63, PatchType.BELLADONNA, Items.CAVE_NIGHTSHADE_2398), BELLADONNA_SEED(5281, 4, 4, 91.0, 128.0, 0.0, 63, PatchType.BELLADONNA, Items.CAVE_NIGHTSHADE_2398),
@@ -128,6 +128,7 @@ object UseWithPatchHandler{
if(p.plantable != null){ if(p.plantable != null){
p.harvestAmt += if(p.compost == CompostType.NORMAL) 1 else if(p.compost == CompostType.SUPER) 2 else 0 p.harvestAmt += if(p.compost == CompostType.NORMAL) 1 else if(p.compost == CompostType.SUPER) 2 else 0
} }
p.cropLives += if(p.compost == CompostType.SUPER) 2 else 1
player.inventory.add(Item(Items.BUCKET_1925)) player.inventory.add(Item(Items.BUCKET_1925))
} }
return true return true
@@ -50,6 +50,7 @@ class FarmingState(player: Player? = null) : State(player) {
p.put("patch-checkHealth",patch.isCheckHealth) p.put("patch-checkHealth",patch.isCheckHealth)
p.put("patch-compost",patch.compost.ordinal) p.put("patch-compost",patch.compost.ordinal)
p.put("patch-paidprot",patch.protectionPaid) p.put("patch-paidprot",patch.protectionPaid)
p.put("patch-croplives", patch.cropLives)
patches.add(p) patches.add(p)
} }
val bins = JSONArray() val bins = JSONArray()
@@ -91,10 +92,12 @@ class FarmingState(player: Player? = null) : State(player) {
val savedState = p["patch-state"].toString().toInt() val savedState = p["patch-state"].toString().toInt()
val compostOrdinal = p["patch-compost"].toString().toInt() val compostOrdinal = p["patch-compost"].toString().toInt()
val protectionPaid = p["patch-paidprot"] as Boolean val protectionPaid = p["patch-paidprot"] as Boolean
val cropLives = if(p["patch-croplives"] != null) p["patch-croplives"].toString().toInt() else 3
val fPatch = FarmingPatch.values()[patchOrdinal] val fPatch = FarmingPatch.values()[patchOrdinal]
val plantable = if(patchPlantableOrdinal != -1) Plantable.values()[patchPlantableOrdinal] else null val plantable = if(patchPlantableOrdinal != -1) Plantable.values()[patchPlantableOrdinal] else null
val patch = Patch(player,fPatch,plantable,patchStage,patchDiseased,patchDead,patchWatered,nextGrowth,harvestAmt,checkHealth) val patch = Patch(player,fPatch,plantable,patchStage,patchDiseased,patchDead,patchWatered,nextGrowth,harvestAmt,checkHealth)
patch.cropLives = cropLives
patch.compost = CompostType.values()[compostOrdinal] patch.compost = CompostType.values()[compostOrdinal]
patch.protectionPaid = protectionPaid patch.protectionPaid = protectionPaid
patch.setCurrentState(savedState) patch.setCurrentState(savedState)
@@ -15,6 +15,7 @@ object ImmerseWorld {
@JvmStatic @JvmStatic
fun init() { fun init() {
Executors.newSingleThreadExecutor().execute { Executors.newSingleThreadExecutor().execute {
Thread.currentThread().name = "BotSpawner"
immerseSeersAndCatherby() immerseSeersAndCatherby()
immerseLumbridgeDraynor() immerseLumbridgeDraynor()
immerseVarrock() immerseVarrock()
@@ -2,9 +2,6 @@ package rs09.game.world.repository
import core.game.node.entity.player.Player import core.game.node.entity.player.Player
import core.game.node.entity.player.info.login.PlayerParser import core.game.node.entity.player.info.login.PlayerParser
import core.game.system.mysql.SQLEntryHandler
import core.game.system.mysql.impl.HighscoreSQLHandler
import core.game.system.mysql.impl.PlayerLogSQLHandler
import core.game.system.task.TaskExecutor import core.game.system.task.TaskExecutor
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import rs09.game.world.GameWorld import rs09.game.world.GameWorld
@@ -71,7 +68,10 @@ class DisconnectionQueue {
return true return true
} }
if (!force) { if (!force) {
TaskExecutor.executeSQL { save(player, true) } TaskExecutor.executeSQL {
Thread.currentThread().name = "PlayerSave SQL"
save(player, true)
}
return true return true
} }
save(player, false) save(player, false)
@@ -8,6 +8,8 @@ import core.game.world.repository.InitializingNodeList
import core.net.packet.PacketRepository import core.net.packet.PacketRepository
import core.net.packet.context.PlayerContext import core.net.packet.context.PlayerContext
import core.net.packet.out.ClearMinimapFlag import core.net.packet.out.ClearMinimapFlag
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import rs09.game.world.repository.Repository import rs09.game.world.repository.Repository
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executors import java.util.concurrent.Executors
@@ -58,7 +60,7 @@ class UpdateSequence
fun run() { fun run() {
val latch = CountDownLatch(renderablePlayers.size) val latch = CountDownLatch(renderablePlayers.size)
playersList!!.forEach(Consumer { player: Player -> playersList!!.forEach(Consumer { player: Player ->
EXECUTOR.execute { GlobalScope.launch {
try { try {
player.update() player.update()
} catch (t: Throwable) { } catch (t: Throwable) {
@@ -89,7 +91,6 @@ class UpdateSequence
* Terminates the update sequence. * Terminates the update sequence.
*/ */
fun terminate() { fun terminate() {
EXECUTOR.shutdown()
} }
companion object { companion object {
@@ -103,11 +104,5 @@ class UpdateSequence
@JvmStatic @JvmStatic
val renderablePlayers = InitializingNodeList<Player>() val renderablePlayers = InitializingNodeList<Player>()
/**
* The executor used.
*/
@JvmStatic
private val EXECUTOR = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())
} }
} }
@@ -103,21 +103,22 @@ class LoginReadEvent
session.isaacPair = ISAACPair(inCipher, outCipher) session.isaacPair = ISAACPair(inCipher, outCipher)
session.clientInfo = ClientInfo(displayMode, windowMode, screenWidth, screenHeight) session.clientInfo = ClientInfo(displayMode, windowMode, screenWidth, screenHeight)
val b = buffer val b = buffer
TaskExecutor.executeSQL(Runnable { TaskExecutor.executeSQL {
Thread.currentThread().name = "Login Password Response"
try { try {
val username = StringUtils.longToString(b.long) val username = StringUtils.longToString(b.long)
val password = ByteBufferUtils.getString(b) val password = ByteBufferUtils.getString(b)
val response = PlayerSQLManager.getCredentialResponse(username, password) val response = PlayerSQLManager.getCredentialResponse(username, password)
if (response != Response.SUCCESSFUL) { if (response != Response.SUCCESSFUL) {
session.write(response, true) session.write(response, true)
return@Runnable return@executeSQL
} }
login(PlayerDetails(username, password), session, b, opcode) login(PlayerDetails(username, password), session, b, opcode)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
session.write(Response.COULD_NOT_LOGIN) session.write(Response.COULD_NOT_LOGIN)
} }
}) }
} }
/** /**
@@ -138,7 +139,7 @@ class LoginReadEvent
if (WorldCommunicator.isEnabled()) { if (WorldCommunicator.isEnabled()) {
WorldCommunicator.register(parser) WorldCommunicator.register(parser)
} else { } else {
TaskExecutor.executeSQL(parser) TaskExecutor.executeSQL {parser.run()}
} }
} }