diff --git a/README.md b/README.md index 530e063..78d3ed1 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Open `config.lua` and change `branding.title` to the name of your shop you want shown in the header. -Next change `currencies.host`, `currencies.name`, and `currencies.pkey` for the krist currency to your krist address, the krist name you will be using (or nil), and your krist address' private key, respectively. You can then either remove/comment out the tenebra currency, or fill in your respective details for that. +Next change `currencies.name`, and `currencies.pkey` for the krist currency to your krist address, the krist name you will be using (or nil), and your krist address' private key, respectively. If you are using a kristwallet format password, change `currencies.pkeyFormat` to `"kristwallet"`. You can then either remove/comment out the tenebra currency, or fill in your respective details for that. **WARNING**: If you do not use a name for your shop, any transaction that doesn't purchase an item to your address will be refunded. Do not run the shop on your personal address you will be receiving krist to if you are not using a name. @@ -39,4 +39,4 @@ - `sounds` controls the sounds that get played in various situations - `currencies` lists the currencies accepted by the shop. If you don't have a name on a given currency, you can leave it out or set it to nil to use nameless mode. - `peripherals` defines peripherals to be used for the shop. Most of these can be left at nil to be automatically set. `peripherals.outputChest` should generally be left on `"self"` as setting it to a chest will cause items to be inserted into the chest without dropping them, as chest dropping is not yet implemented in plethora 1.19 -- `hooks` define event hook functions to be executed when their respective event happens. Use this when you need additional functional (such as posting to webhooks) when the shop starts, a purchase happens or fails, or an error occurs. \ No newline at end of file +- `hooks` define event hook functions to be executed when their respective event happens. Use this when you need additional functional (such as posting to webhooks) when the shop starts, a purchase happens or fails, an error occurs, and other events. \ No newline at end of file diff --git a/config.lua b/config.lua index de7a64b..88d99e7 100644 --- a/config.lua +++ b/config.lua @@ -20,7 +20,8 @@ refundAtLeastOne = "You must purchase at least one of this product!", refundInvalidProduct = "You must supply a valid product to purchase!", refundNoProduct = "You must supply a product to purchase!", - refundError = "An error occurred while processing your purchase!" + refundError = "An error occurred while processing your purchase!", + refundDenied = "This purchase has been denied" }, theme = { formatting = { @@ -97,10 +98,9 @@ { id = "krist", -- if not krist or tenebra, must supply endpoint -- node = "https://krist.dev" - host = "ksbangelco", name = "radon.kst", pkey = "", - pkeyFormat = "raw", -- Currently must be 'raw', kwallet support is planned + pkeyFormat = "raw", -- Currently must be 'raw' or 'kristwallet' -- You can get your raw pkey from kristweb or using https://pkey.its-em.ma/ value = 1.0 -- Default scaling on item prices, can be overridden on a per-item basis }, @@ -129,6 +129,7 @@ }, hooks = { start = nil, -- function(version, config, products) + prePurchase = nil, -- function(product, amount, refundAmount, transaction, transactionCurrency) returns continueTransaction, error, errorMessage purchase = nil, -- function(product, amount, refundAmount, transaction, transactionCurrency) failedPurchase = nil, -- function(transaction, transactionCurrency, product, errorMessage) programError = nil, -- function(err) diff --git a/core/ConfigValidator.lua b/core/ConfigValidator.lua index 0054730..191120a 100644 --- a/core/ConfigValidator.lua +++ b/core/ConfigValidator.lua @@ -93,7 +93,6 @@ __entry = { id = "string", node = "string?", - host = [[regex<^[a-z0-9]{10}$>: address]], name = "string?", pkey = "string", pkeyFormat = "enum<'raw' | 'kristwallet'>: pkey format", @@ -111,6 +110,7 @@ }, hooks = { start = "function?", + prePurchase = "function?", purchase = "function?", failedPurchase = "function?", programError = "function?", diff --git a/core/ShopState.lua b/core/ShopState.lua index 80962ff..d31f999 100644 --- a/core/ShopState.lua +++ b/core/ShopState.lua @@ -106,40 +106,53 @@ if purchasedProduct.quantity and purchasedProduct.quantity > 0 then local productSources, available = ScanInventory.findProductItems(state.products, purchasedProduct, amountPurchased) local refundAmount = math.floor(transaction.value - (available * productPrice)) - print("Purchased " .. available .. " of " .. purchasedProduct.name .. " for " .. transaction.from .. " for " .. transaction.value .. " " .. transactionCurrency.id .. " (refund " .. refundAmount .. ")") if available > 0 then - for _, productSource in ipairs(productSources) do - if state.config.peripherals.outputChest == "self" then - if not turtle then - error("Self output but not a turtle!") - end - if not state.modem.getNameLocal() then - error("Modem is not connected! Try right clicking it") - end - peripheral.call(productSource.inventory, "pushItems", state.modem.getNameLocal(), productSource.slot, productSource.amount, 1) - if state.config.settings.dropDirection == "forward" then - turtle.drop(productSource.amount) - elseif state.config.settings.dropDirection == "up" then - turtle.dropUp(productSource.amount) - elseif state.config.settings.dropDirection == "down" then - turtle.dropDown(productSource.amount) + local allowPurchase = true + local err + local errMessage + if state.config.hooks and state.config.hooks.prePurchase then + allowPurchase, err, errMessage = eventHook.execute(state.config.hooks.prePurchase, purchasedProduct, available, refundAmount, transaction, transactionCurrency) + end + if allowPurchase ~= false then + print("Purchased " .. available .. " of " .. purchasedProduct.name .. " for " .. transaction.from .. " for " .. transaction.value .. " " .. transactionCurrency.id .. " (refund " .. refundAmount .. ")") + for _, productSource in ipairs(productSources) do + if state.config.peripherals.outputChest == "self" then + if not turtle then + error("Self output but not a turtle!") + end + if not state.modem.getNameLocal() then + error("Modem is not connected! Try right clicking it") + end + peripheral.call(productSource.inventory, "pushItems", state.modem.getNameLocal(), productSource.slot, productSource.amount, 1) + if state.config.settings.dropDirection == "forward" then + turtle.drop(productSource.amount) + elseif state.config.settings.dropDirection == "up" then + turtle.dropUp(productSource.amount) + elseif state.config.settings.dropDirection == "down" then + turtle.dropDown(productSource.amount) + else + error("Invalid drop direction: " .. state.config.settings.dropDirection) + end else - error("Invalid drop direction: " .. state.config.settings.dropDirection) + peripheral.call(productSource.inventory, "pushItems", state.config.peripherals.outputChest, productSource.slot, productSource.amount, 1) + --peripheral.call(state.config.peripherals.outputChest, "drop", 1, productSource.amount, state.config.settings.dropDirection) end - else - peripheral.call(productSource.inventory, "pushItems", state.config.peripherals.outputChest, productSource.slot, productSource.amount, 1) - --peripheral.call(state.config.peripherals.outputChest, "drop", 1, productSource.amount, state.config.settings.dropDirection) end - end - purchasedProduct.quantity = purchasedProduct.quantity - available - if refundAmount > 0 then - refund(transactionCurrency, transaction.from, meta, refundAmount, state.config.lang.refundRemaining) - end - if state.config.settings.playSounds then - sound.playSound(state.speaker, state.config.sounds.purchase) - end - if state.config.hooks and state.config.hooks.purchase then - eventHook.execute(state.config.hooks.purchase, purchasedProduct, available, refundAmount, transaction, transactionCurrency) + purchasedProduct.quantity = purchasedProduct.quantity - available + if refundAmount > 0 then + refund(transactionCurrency, transaction.from, meta, refundAmount, state.config.lang.refundRemaining) + end + if state.config.settings.playSounds then + sound.playSound(state.speaker, state.config.sounds.purchase) + end + if state.config.hooks and state.config.hooks.purchase then + eventHook.execute(state.config.hooks.purchase, purchasedProduct, available, refundAmount, transaction, transactionCurrency) + end + else + refund(transactionCurrency, transaction.from, meta, transaction.value, errMessage or state.config.lang.refundDenied, err) + if state.config.hooks and state.config.hooks.failedPurchase then + eventHook.execute(state.config.hooks.failedPurchase, transaction, transactionCurrency, purchasedProduct, errMessage or state.config.lang.refundDenied, err) + end end else refund(transactionCurrency, transaction.from, meta, transaction.value, state.config.lang.refundOutOfStock) @@ -190,6 +203,24 @@ local kryptonWs = currency.krypton:connect() kryptonWs:subscribe("ownTransactions") kryptonWs:getSelf() + local pkey = currency.pkey + if currency.pkeyFormat == "kristwallet" then + pkey = currency.krypton:toKristWalletFormat(currency.pkey) + end + currency.host = currency.krypton:makev2address(pkey) + if currency.name then + local name = currency.name + if name:find("%.") then + name = name:sub(1, name:find("%.") - 1) + end + local nameInfo = currency.krypton:getName(name) + if not nameInfo then + error("Name " .. currency.name .. " does not exist!") + end + if nameInfo.name.owner:lower() ~= currency.host:lower() then + error("Name " .. currency.name .. " is not owned by " .. currency.host .. "!") + end + end table.insert(kryptonListeners, function() kryptonWs:listen() end) end parallel.waitForAny(function() diff --git a/radon.lua b/radon.lua index 2df55be..78722ef 100644 --- a/radon.lua +++ b/radon.lua @@ -1,7 +1,7 @@ local oldPullEvent = os.pullEvent os.pullEvent = os.pullEventRaw -local version = "1.1.10" +local version = "1.1.11" --- Imports local _ = require("util.score")