Merge branch 'ge-improvements' into 'master'

GE Improvements

See merge request 2009scape/2009scape!158
This commit is contained in:
Ceikry 2021-07-13 15:26:20 +00:00
commit bdaf707983
10 changed files with 523 additions and 486 deletions

View file

@ -3,6 +3,7 @@ package core.game.ge;
import core.game.component.Component; import core.game.component.Component;
import core.game.node.entity.player.Player; import core.game.node.entity.player.Player;
import core.tools.StringUtils; import core.tools.StringUtils;
import rs09.game.ge.OfferManager;
/** /**
* Represents the glass used to open the guide prices for the different type of * Represents the glass used to open the guide prices for the different type of
@ -139,7 +140,7 @@ public final class GEGuidePrice {
player.getPacketDispatch().sendInterfaceConfig(642, i, false); player.getPacketDispatch().sendInterfaceConfig(642, i, false);
} }
for (GuideItem item : getItems()) { for (GuideItem item : getItems()) {
player.getPacketDispatch().sendString("" + GrandExchangeDatabase.getDatabase().get(item.getItem()).getValue() + " gp", COMPONENT.getId(), item.getChildData()[0]); player.getPacketDispatch().sendString("" + OfferManager.getRecommendedPrice(item.item, false) + " gp", COMPONENT.getId(), item.getChildData()[0]);
} }
} }
} }

View file

@ -22,6 +22,7 @@ import core.plugin.Initializable;
import core.plugin.Plugin; import core.plugin.Plugin;
import kotlin.Unit; import kotlin.Unit;
import rs09.game.ge.GrandExchangeOffer; import rs09.game.ge.GrandExchangeOffer;
import rs09.game.ge.OfferManager;
import rs09.game.ge.PlayerGrandExchange; import rs09.game.ge.PlayerGrandExchange;
import rs09.game.interaction.npc.BogrogPouchSwapper; import rs09.game.interaction.npc.BogrogPouchSwapper;
import rs09.game.world.GameWorld; import rs09.game.world.GameWorld;
@ -69,7 +70,7 @@ public class GrandExchangeInterface extends ComponentPlugin {
if (offer == null || value < 1 || offer.getOfferState() != OfferState.PENDING) { if (offer == null || value < 1 || offer.getOfferState() != OfferState.PENDING) {
return; return;
} }
if (value == GrandExchangeDatabase.getDatabase().get(offer.getItemID()).getValue()) { if (value == OfferManager.getRecommendedPrice(offer.getItemID(), false)) {
player.getAudioManager().send(new Audio(4043, 1, 1)); player.getAudioManager().send(new Audio(4043, 1, 1));
} else if (value > offer.getOfferedValue()) { } else if (value > offer.getOfferedValue()) {
player.getAudioManager().send(new Audio(4041, 1, 1)); player.getAudioManager().send(new Audio(4041, 1, 1));
@ -77,7 +78,7 @@ public class GrandExchangeInterface extends ComponentPlugin {
player.getAudioManager().send(new Audio(4045, 1, 1)); player.getAudioManager().send(new Audio(4045, 1, 1));
} }
offer.setOfferedValue(value); offer.setOfferedValue(value);
player.getConfigManager().send(1111, offer.getOfferedValue()); player.varpManager.get(1111).setVarbit(0,offer.getOfferedValue()).send(player);
} }
@Override @Override
@ -348,14 +349,14 @@ public class GrandExchangeInterface extends ComponentPlugin {
return false; return false;
case 180: case 180:
if (offer != null) { if (offer != null) {
setOfferValue(player, offer, GrandExchangeDatabase.getDatabase().get(offer.getItemID()).getValue()); setOfferValue(player, offer, OfferManager.getRecommendedPrice(offer.getItemID(), false));
return true; return true;
} }
return false; return false;
case 177: // mid - 5% value case 177: // mid - 5% value
case 183: // mid + 5% value case 183: // mid + 5% value
if (offer != null) { if (offer != null) {
setOfferValue(player, offer, (int) (GrandExchangeDatabase.getDatabase().get(offer.getItemID()).getValue() * (button == 177 ? 0.95 : 1.05))); setOfferValue(player, offer, (int) (OfferManager.getRecommendedPrice(offer.getItemID(), false) * (button == 177 ? 0.95 : 1.05)));
return true; return true;
} }
return false; return false;

View file

@ -19,6 +19,7 @@ import rs09.game.ai.AIPlayer;
import rs09.game.ai.AIRepository; import rs09.game.ai.AIRepository;
import rs09.game.ai.general.GeneralBotCreator; import rs09.game.ai.general.GeneralBotCreator;
import rs09.game.content.global.NPCDropTable; import rs09.game.content.global.NPCDropTable;
import rs09.game.ge.OfferManager;
import rs09.game.system.config.ItemConfigParser; import rs09.game.system.config.ItemConfigParser;
import rs09.game.world.repository.Repository; import rs09.game.world.repository.Repository;
@ -177,7 +178,7 @@ public final class NPCDropTables {
} }
} }
player.sendMessage(player.getInterfaceManager().isResizable()+""); player.sendMessage(player.getInterfaceManager().isResizable()+"");
int price = item.getName().endsWith("charm") ? 100 : GrandExchangeDatabase.getDatabase().get(itemId).getValue(); int price = item.getName().endsWith("charm") ? 100 : OfferManager.getRecommendedPrice(itemId, false);
looter.getGlobalData().setLootSharePoints(looter.getGlobalData().getLootSharePoints() - (price) + ((price / looters.size()))); looter.getGlobalData().setLootSharePoints(looter.getGlobalData().getLootSharePoints() - (price) + ((price / looters.size())));
looter.sendMessage((player.getInterfaceManager().isResizable() ? "<col=32CD32>" : "<col=009900>") + "You received: " + item.getAmount() + " " + item.getName()); looter.sendMessage((player.getInterfaceManager().isResizable() ? "<col=32CD32>" : "<col=009900>") + "You received: " + item.getAmount() + " " + item.getName());
for (Player p : looters) { for (Player p : looters) {

View file

@ -8,6 +8,7 @@ import core.game.interaction.Interaction;
import core.game.interaction.OptionHandler; import core.game.interaction.OptionHandler;
import core.game.node.Node; import core.game.node.Node;
import core.game.node.entity.combat.equipment.DegradableEquipment; import core.game.node.entity.combat.equipment.DegradableEquipment;
import rs09.game.ge.OfferManager;
/** /**
* Represents an item. * Represents an item.
@ -99,10 +100,7 @@ public class Item extends Node{
*/ */
public long getValue() { public long getValue() {
long value = 1; long value = 1;
GrandExchangeEntry entry = GrandExchangeDatabase.getDatabase().get(getId()); value = OfferManager.getRecommendedPrice(getId(), false);
if (entry != null) {
value = entry.getValue();
}
if (definition.getValue() > value) { if (definition.getValue() > value) {
value = definition.getValue(); value = definition.getValue();
} }

View file

@ -161,7 +161,7 @@ public class GrandExchangeTab extends ConsoleTab {
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
} }
for (GrandExchangeOffer o : OfferManager.Companion.getOffersForItem(itemId)) { for (GrandExchangeOffer o : OfferManager.getOffersForItem(itemId)) {
if (o == null) { if (o == null) {
continue; continue;
} }
@ -184,7 +184,7 @@ public class GrandExchangeTab extends ConsoleTab {
JOptionPane.showMessageDialog(null, "Error! No data in DB yet. Press load."); JOptionPane.showMessageDialog(null, "Error! No data in DB yet. Press load.");
return; return;
} }
for (GrandExchangeOffer offer : OfferManager.Companion.getOFFER_MAPPING().values()) { for (GrandExchangeOffer offer : OfferManager.getOFFER_MAPPING().values()) {
model.addElement(offer); model.addElement(offer);
} }
} }

View file

@ -0,0 +1,46 @@
package rs09.game.ge
import core.game.world.callback.CallBack
import rs09.game.system.SystemLogger
import rs09.tools.secondsToTicks
object GrandExchange : CallBack {
/**
* Fallback safety check to make sure we don't start the GE twice under any circumstance
*/
var isRunning = false
/**
* Initializes the offer manager and spawns an update thread.
* @param local whether or not the GE should be the local in-code server rather than some hypothetical remote implementation.
*/
fun boot(local: Boolean){
if(isRunning) return
if(!local){
TODO("Remote GE server stuff")
}
SystemLogger.logGE("Initializing GE...")
OfferManager.init()
SystemLogger.logGE("GE Initialized.")
SystemLogger.logGE("Initializing GE Update Worker")
val t = Thread {
Thread.currentThread().name = "GE Update Worker"
while(true) {
SystemLogger.logGE("Updating offers...")
OfferManager.update()
Thread.sleep(60_000) //sleep for 60 seconds
}
}.start()
isRunning = true
}
override fun call(): Boolean {
boot(true)
return true
}
}

View file

@ -1,5 +1,6 @@
package rs09.game.ge package rs09.game.ge
import api.ContentAPI
import rs09.ServerConstants import rs09.ServerConstants
import core.cache.def.impl.ItemDefinition import core.cache.def.impl.ItemDefinition
import core.game.content.eco.EcoStatus import core.game.content.eco.EcoStatus
@ -23,54 +24,19 @@ import org.json.simple.JSONArray
import org.json.simple.JSONObject import org.json.simple.JSONObject
import org.json.simple.parser.JSONParser import org.json.simple.parser.JSONParser
import rs09.game.ai.AIPlayer import rs09.game.ai.AIPlayer
import rs09.game.system.config.ItemConfigParser
import java.io.File import java.io.File
import java.io.FileReader import java.io.FileReader
import java.io.FileWriter import java.io.FileWriter
import java.io.IOException import java.io.IOException
import java.lang.Integer.max
import java.lang.Integer.min import java.lang.Integer.min
import java.util.* import java.util.*
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
import javax.script.ScriptEngineManager import javax.script.ScriptEngineManager
import kotlin.collections.ArrayList
class OfferManager : Pulse(), CallBack { object OfferManager {
/**
* How often in ticks should ge offers that hit the buying limit be reprocessed?
*/
private val RESET_BUYING_LIMIT_INTERVAL = 24000
/**
* How often should the database be saved to disk?
*/
private val SAVE_EVERY = ServerConstants.GE_AUTOSAVE_FREQUENCY
override fun call(): Boolean {
init()
delay = 1
GameWorld.Pulser.submit(this)
return true
}
override fun pulse(): Boolean {
// TODO: Update offers code
if (GameWorld.ticks % RESET_BUYING_LIMIT_INTERVAL == 0) {
BuyingLimitation.clear()
for (offer in OFFER_MAPPING.values) {
if (offer.isActive && offer.isLimitation) {
updateOffer(offer)
}
}
}
if (dumpDatabase && (GameWorld.ticks % SAVE_EVERY == 0)) {
//save()
dumpDatabase = false
}
return false
}
companion object {
/** /**
* The update notification. * The update notification.
*/ */
@ -98,6 +64,7 @@ class OfferManager : Pulse(), CallBack {
* Second is itemID, offsetID, Offer * Second is itemID, offsetID, Offer
* Final is playerID, offsetID, Offer * Final is playerID, offsetID, Offer
*/ */
@JvmStatic
val OFFER_MAPPING: MutableMap<Long, GrandExchangeOffer> = HashMap() val OFFER_MAPPING: MutableMap<Long, GrandExchangeOffer> = HashMap()
val OFFERS_BY_ITEMID: MutableMap<Int, MutableList<GrandExchangeOffer>> = HashMap() val OFFERS_BY_ITEMID: MutableMap<Int, MutableList<GrandExchangeOffer>> = HashMap()
private val GE_OFFER_LOCK = ReentrantLock() private val GE_OFFER_LOCK = ReentrantLock()
@ -175,11 +142,19 @@ class OfferManager : Pulse(), CallBack {
GE_OFFER_LOCK.unlock() GE_OFFER_LOCK.unlock()
} }
fun update(){
for (offer in OFFER_MAPPING.values) {
if (offer.isActive) {
updateOffer(offer)
}
}
}
fun buyFromBots(offer: GrandExchangeOffer) { fun buyFromBots(offer: GrandExchangeOffer) {
if (BOT_OFFERS[offer.itemID] == null) { if (BOT_OFFERS[offer.itemID] == null) {
return return
} }
val botPrice = BotPrices.getPrice(offer.itemID) val botPrice = getRecommendedPrice(offer.itemID, true)
if (offer.offeredValue < botPrice) { if (offer.offeredValue < botPrice) {
return return
} }
@ -272,6 +247,7 @@ class OfferManager : Pulse(), CallBack {
return qty return qty
} }
@JvmStatic
fun getOffersForItem(item: Int): MutableList<GrandExchangeOffer> { fun getOffersForItem(item: Int): MutableList<GrandExchangeOffer> {
if (OFFERS_BY_ITEMID.containsKey(item)) { if (OFFERS_BY_ITEMID.containsKey(item)) {
return OFFERS_BY_ITEMID[item]!! return OFFERS_BY_ITEMID[item]!!
@ -540,7 +516,15 @@ class OfferManager : Pulse(), CallBack {
nextUID() nextUID()
} else id } else id
} }
private fun getItemDefPrice(itemID: Int): Int {
return max(ContentAPI.itemDefinition(itemID).getConfiguration(ItemConfigParser.GE_PRICE) ?: 0, ContentAPI.itemDefinition(itemID).value)
} }
@JvmStatic
fun getRecommendedPrice(itemID: Int, from_bot: Boolean = false): Int {
val base = max(GrandExchangeDatabase.getDatabase()[itemID]?.value ?: 0, getItemDefPrice(itemID))
return if(from_bot) (base + (base * 0.1).toInt())
else base
}
} }

View file

@ -1,5 +1,6 @@
package rs09.game.ge package rs09.game.ge
import api.ContentAPI
import core.cache.def.impl.ItemDefinition import core.cache.def.impl.ItemDefinition
import core.game.component.CloseEvent import core.game.component.CloseEvent
import core.game.component.Component import core.game.component.Component
@ -27,8 +28,6 @@ import core.net.packet.out.GrandExchangePacket
import org.json.simple.JSONArray import org.json.simple.JSONArray
import org.json.simple.JSONObject import org.json.simple.JSONObject
import org.rs09.consts.Components import org.rs09.consts.Components
import rs09.game.ge.OfferManager.Companion.dispatch
import rs09.game.ge.OfferManager.Companion.updateOffer
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.NumberFormat import java.text.NumberFormat
@ -319,13 +318,13 @@ class PlayerGrandExchange(private val player: Player) {
temporaryOffer!!.itemID = itemId temporaryOffer!!.itemID = itemId
temporaryOffer!!.sell = false temporaryOffer!!.sell = false
var itemDb = GrandExchangeDatabase.getDatabase()[itemId] var itemDb = GrandExchangeDatabase.getDatabase()[itemId]
if (itemDb == null) { if (itemDb == null || !ContentAPI.itemDefinition(itemId).isTradeable) {
player.packetDispatch.sendMessage("This item has been blacklisted from the Grand Exchange.") player.packetDispatch.sendMessage("This item has been blacklisted from the Grand Exchange.")
return return
} }
temporaryOffer!!.player = player temporaryOffer!!.player = player
temporaryOffer!!.amount = 1 temporaryOffer!!.amount = 1
temporaryOffer!!.offeredValue = itemDb.value temporaryOffer!!.offeredValue = OfferManager.getRecommendedPrice(itemId)
temporaryOffer!!.index = openedIndex temporaryOffer!!.index = openedIndex
sendConfiguration(temporaryOffer, false) sendConfiguration(temporaryOffer, false)
} }
@ -350,7 +349,7 @@ class PlayerGrandExchange(private val player: Player) {
id = item.noteChange id = item.noteChange
} }
var itemDb = GrandExchangeDatabase.getDatabase()[id] var itemDb = GrandExchangeDatabase.getDatabase()[id]
if (itemDb == null) { if (itemDb == null || !item.definition.isTradeable) {
player.packetDispatch.sendMessage("This item can't be sold on the Grand Exchange.") player.packetDispatch.sendMessage("This item can't be sold on the Grand Exchange.")
return return
} }
@ -358,7 +357,7 @@ class PlayerGrandExchange(private val player: Player) {
temporaryOffer!!.itemID = id temporaryOffer!!.itemID = id
temporaryOffer!!.sell = true temporaryOffer!!.sell = true
temporaryOffer!!.player = player temporaryOffer!!.player = player
temporaryOffer!!.offeredValue = itemDb.value temporaryOffer!!.offeredValue = OfferManager.getRecommendedPrice(id)
temporaryOffer!!.amount = item.amount temporaryOffer!!.amount = item.amount
temporaryOffer!!.index = openedIndex temporaryOffer!!.index = openedIndex
sendConfiguration(temporaryOffer, true) sendConfiguration(temporaryOffer, true)
@ -425,9 +424,9 @@ class PlayerGrandExchange(private val player: Player) {
return return
} }
} }
if (dispatch(player, temporaryOffer!!)) { if (OfferManager.dispatch(player, temporaryOffer!!)) {
offers[openedIndex] = temporaryOffer offers[openedIndex] = temporaryOffer
updateOffer(temporaryOffer!!) OfferManager.updateOffer(temporaryOffer!!)
} }
} else { } else {
val total: Int = temporaryOffer!!.amount * temporaryOffer!!.offeredValue val total: Int = temporaryOffer!!.amount * temporaryOffer!!.offeredValue
@ -436,9 +435,9 @@ class PlayerGrandExchange(private val player: Player) {
player.packetDispatch.sendMessage("You do not have enough coins to cover the offer.") player.packetDispatch.sendMessage("You do not have enough coins to cover the offer.")
return return
} }
if (dispatch(player, temporaryOffer!!) && player.inventory.remove(Item(995, total))) { if (OfferManager.dispatch(player, temporaryOffer!!) && player.inventory.remove(Item(995, total))) {
offers[openedIndex] = temporaryOffer offers[openedIndex] = temporaryOffer
updateOffer(temporaryOffer!!) OfferManager.updateOffer(temporaryOffer!!)
} }
} }
player.monitor.log( player.monitor.log(
@ -546,7 +545,7 @@ class PlayerGrandExchange(private val player: Player) {
val botSales = OfferManager.amtBotsSelling(offer.itemID) val botSales = OfferManager.amtBotsSelling(offer.itemID)
if (botSales > 0) { if (botSales > 0) {
foundAmounts.add(botSales) foundAmounts.add(botSales)
foundOffers.add(BotPrices.getPrice(offer.itemID)) foundOffers.add(OfferManager.getRecommendedPrice(offer.itemID, true))
count++ count++
} }
if (foundOffers.isNotEmpty()) { if (foundOffers.isNotEmpty()) {
@ -564,16 +563,17 @@ class PlayerGrandExchange(private val player: Player) {
player.packetDispatch.sendString(if (offer != null && !offer.sell) text.toString() else examine, 105, 142) player.packetDispatch.sendString(if (offer != null && !offer.sell) text.toString() else examine, 105, 142)
var lowPrice = 0 var lowPrice = 0
var highPrice = 0 var highPrice = 0
val recommendedPrice = OfferManager.getRecommendedPrice(entry?.itemId ?: 0)
if (entry != null) { if (entry != null) {
lowPrice = (entry.value * 0.95).toInt() lowPrice = (recommendedPrice * 0.95).toInt()
highPrice = (entry.value * 1.05).toInt() highPrice = (recommendedPrice * 1.05).toInt()
} }
player.varpManager.get(1109).setVarbit(0, offer?.itemID ?: -1).send(player) player.varpManager.get(1109).setVarbit(0, offer?.itemID ?: -1).send(player)
player.varpManager.get(1110).setVarbit(0, offer?.amount ?: 0).send(player) player.varpManager.get(1110).setVarbit(0, offer?.amount ?: 0).send(player)
player.varpManager.get(1111).setVarbit(0, offer?.offeredValue ?: 0).send(player) player.varpManager.get(1111).setVarbit(0, offer?.offeredValue ?: 0).send(player)
player.varpManager.get(1112).setVarbit(0, openedIndex).send(player) player.varpManager.get(1112).setVarbit(0, openedIndex).send(player)
player.varpManager.get(1113).setVarbit(0, if (sell) 1 else 0).send(player) player.varpManager.get(1113).setVarbit(0, if (sell) 1 else 0).send(player)
player.varpManager.get(1114).setVarbit(0, entry?.value ?: 0).send(player) player.varpManager.get(1114).setVarbit(0, recommendedPrice).send(player)
player.varpManager.get(1115).setVarbit(0, lowPrice).send(player) player.varpManager.get(1115).setVarbit(0, lowPrice).send(player)
player.varpManager.get(1116).setVarbit(0, highPrice).send(player) player.varpManager.get(1116).setVarbit(0, highPrice).send(player)
if (offer != null) { if (offer != null) {

View file

@ -69,6 +69,11 @@ object SystemLogger {
if(message.isNotBlank()) t.println("${getTime()}: ${TextColors.gray("[RAND] $message")}") if(message.isNotBlank()) t.println("${getTime()}: ${TextColors.gray("[RAND] $message")}")
} }
@JvmStatic
fun logGE(message: String){
if(message.isNotBlank()) t.println("${getTime()}: ${TextColors.gray("[ GE] $message")}")
}
@JvmStatic @JvmStatic
fun logTrade(message: String){ fun logTrade(message: String){
if(message.isNotBlank()){ if(message.isNotBlank()){

View file

@ -3,6 +3,7 @@ package rs09.game.world.callback
import core.game.node.entity.skill.hunter.ImpetuousImpulses import core.game.node.entity.skill.hunter.ImpetuousImpulses
import core.game.world.callback.CallBack import core.game.world.callback.CallBack
import core.game.world.map.zone.ZoneBuilder import core.game.world.map.zone.ZoneBuilder
import rs09.game.ge.GrandExchange
import rs09.game.ge.OfferManager import rs09.game.ge.OfferManager
import rs09.game.system.SystemLogger import rs09.game.system.SystemLogger
import java.util.* import java.util.*
@ -16,7 +17,7 @@ object CallbackHub {
fun call(): Boolean { fun call(): Boolean {
calls.add(ZoneBuilder()) calls.add(ZoneBuilder())
calls.add(OfferManager()) calls.add(GrandExchange)
calls.add(ImpetuousImpulses()) calls.add(ImpetuousImpulses())
for (call in calls) { for (call in calls) {
if (!call.call()) { if (!call.call()) {