Added the ability to award credits from a CSV file with an ingame command (ADMIN)

Added the ability to modify an individual user's credits (PMOD)
Added ContentAPI methods for working with credits
Corrected a source of syntactic confusion in the login decoder (no actual change in behavior)
This commit is contained in:
Ceikry 2022-09-11 13:44:54 +00:00 committed by Ryan
parent 49db1538f6
commit 6e6f60ee27
4 changed files with 110 additions and 5 deletions

View file

@ -2099,4 +2099,30 @@ fun equipSlot(item: Int) : EquipmentSlot? {
return EquipmentSlot
.values()
.getOrNull(itemDefinition(item).getConfiguration(ItemConfigParser.EQUIP_SLOT, -1))
}
/**
* Adjusts the user's credits by the given amount
* @param player the player whose credits to adjust
* @param amt the amount to adjust by - add with positive, remove with negative.
* @return true if successful. Success is defined as always true when adding, but can be false if we are trying to remove, and it would put the amount below 0.
*/
fun updateCredits(player: Player, amount: Int) : Boolean {
val creds = getCredits(player) + amount
if (creds < 0)
return false
else
player.details.accountInfo.credits = creds
return true
}
/**
* Gets the number of credits a user has.
* @param player the player to check
* @return the number of credits they have
*/
fun getCredits(player: Player) : Int {
return player.details.accountInfo.credits
}

View file

@ -23,6 +23,7 @@ class UserAccountInfo(
var joinDate: Timestamp
) {
companion object {
val default = createDefault()
@JvmStatic fun createDefault() : UserAccountInfo {
return UserAccountInfo("", "", 0, 0, 0, "", "", 0L, 0L, "", "", "", "", "1,0,8,9", 0L, 0L, false, joinDate = Timestamp(System.currentTimeMillis())).also { it.setInitialReferenceValues() }
}
@ -101,5 +102,7 @@ class UserAccountInfo(
return result
}
fun isDefault() : Boolean {
return this == default
}
}

View file

@ -1,16 +1,27 @@
package rs09.game.system.command.sets
import api.sendMessage
import core.game.node.entity.player.Player
import core.game.node.entity.player.info.Rights
import core.game.system.task.Pulse
import rs09.game.world.GameWorld
import core.game.world.map.Location
import rs09.game.world.repository.Repository
import core.plugin.Initializable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import rs09.ServerConstants
import rs09.ServerStore
import rs09.ServerStore.Companion.addToList
import rs09.auth.UserAccountInfo
import rs09.game.system.command.CommandMapping
import rs09.game.system.command.Privilege
import rs09.game.world.GameWorld
import rs09.game.world.repository.Repository
import java.io.File
import java.io.FileReader
import java.util.concurrent.TimeUnit
import kotlin.math.abs
@Initializable
/**
@ -233,5 +244,70 @@ class ModerationCommandSet : CommandSet(Privilege.MODERATOR){
/**
* =============================================================================================================
*/
define("modcr", Privilege.MODERATOR, "::modcr <lt>user_name<gt> <lt>amount<gt>", "Modifies user_name's credits by the given amount.") {player, args ->
val username = (args.getOrNull(1) ?: "").lowercase()
val amount = args.getOrNull(2)?.toIntOrNull() ?: Integer.MIN_VALUE
if (username.isEmpty()) {
reject(player, "Usage: ::modcr user_name amount")
return@define
}
if (amount == Integer.MIN_VALUE) {
reject(player, "Usage ::modcr user_name amount")
return@define
}
val p = Repository.getPlayerByName(username)
val info: UserAccountInfo = if (p == null)
GameWorld.accountStorage.getAccountInfo(username)
else
p.details.accountInfo
if (info.isDefault()) {
reject(player, "The user you specified ($username) does not exist.")
return@define
}
info.credits += amount
if (p == null)
GameWorld.accountStorage.update(info)
else
sendMessage(p, "You have been ${if (amount > 0) "granted" else "penalized"} ${abs(amount)} credits.")
notify(player, "Updated $username's credits to ${info.credits} by ${if (amount > 0) "adding" else "removing"} ${abs(amount)}.")
}
define("csvmodcr", Privilege.ADMIN, "::csvmodcr filename", "Awards credits based on a csv list from a file. Relative to data dir.") {player, args ->
val filename = args.getOrNull(1) ?: ""
if (filename.isEmpty()) {
reject(player, "Usage: ::csvmodcr filename")
return@define
}
GlobalScope.launch {
val f = File(ServerConstants.DATA_PATH + File.separator + filename)
if (!f.exists()) {
notify(player, "Unable to locate file $filename.")
notify(player, "Note: The file must be in ${ServerConstants.DATA_PATH}")
return@launch
}
val lines: List<String>
withContext(Dispatchers.IO) {
FileReader(f).use {
lines = f.readLines()
}
}
for (line in lines) {
if (line.startsWith("#")) continue
val tokens = line.split(",")
val username = tokens[0].lowercase().trim().replace(" ", "_")
val amount = tokens[1].trim()
CommandMapping.get("modcr")?.handle?.invoke(player, arrayOf("", username, amount))
}
}
}
}
}

View file

@ -108,7 +108,7 @@ object Login {
return try {
val numBytes = buffer.get().toInt() and 0xFF
val encryptedBytes = ByteArray(numBytes)
buffer[encryptedBytes]
buffer.get(encryptedBytes)
val encryptedBigInt = BigInteger(encryptedBytes)
ByteBuffer.wrap(encryptedBigInt.modPow(exponent, modulus).toByteArray())
@ -117,7 +117,7 @@ object Login {
}
}
private fun noop(buffer: ByteBuffer, amount: Int = 1) {buffer[ByteArray(amount)]}
private fun noop(buffer: ByteBuffer, amount: Int = 1) {buffer.get(ByteArray(amount))}
fun proceedWith(session: IoSession, details: PlayerDetails, opcode: Int) {
if (!Repository.LOGGED_IN_PLAYERS.contains(details.username))