Minecraft - Steem/Hive/Blurt - Beta
Been working on making MineCraft and Hive, or mashing them together at least.

It's a new upgraded version, trying to iron out the bugs. Also trying to figure out how to code in a stationary NPC that I don't have to cage in.
Taking all help if its given.
main.lua
-- main.lua
local g_Plugin = nil
local g_Config =
{
HiveEngineRpc = "https://api.hive-engine.com/rpc/contracts",
BridgeUrl = "http://127.0.0.1:8787",
BridgeAuthToken = "",
PaymentAccount = "",
BankEnabled = false,
BankX = 0,
BankY = 0,
BankZ = 0,
Debug = false,
BankName = "PeakeCoin Bank",
BankerName = "Banker",
DefaultSymbol = "PEAK",
BankSignsEnabled = true,
BankSignSymbols = "PEAK",
BankSignUpdateSeconds = 30,
}
local g_Accounts = {}
local g_Bridges = {}
local g_Ledger = {}
local g_Bank =
{
WorldName = "",
AtmX = 0,
AtmY = 0,
AtmZ = 0,
AtmBaseY = 0,
BankerId = nil,
Placed = false,
SignsPlaced = false,
LastPriceUpdate = 0,
Signs = {},
}
local g_TickCounter = 0
local CONFIG_FILE = nil
local function SetBlockAt(a_World, a_X, a_Y, a_Z, a_BlockType, a_BlockMeta)
local meta = a_BlockMeta or 0
local ok = pcall(function()
if (Vector3i ~= nil) then
a_World:SetBlock(Vector3i(a_X, a_Y, a_Z), a_BlockType, meta)
else
error("Vector3i not available")
end
end)
if not ok then
a_World:SetBlock(a_X, a_Y, a_Z, a_BlockType, meta)
end
end
local function ResolveConfigPath()
if (CONFIG_FILE and CONFIG_FILE ~= "") then
return CONFIG_FILE
end
local plugin = cPluginManager:Get():GetCurrentPlugin()
if (plugin) then
CONFIG_FILE = plugin:GetLocalFolder() .. "/HiveEngineTrade.ini"
else
CONFIG_FILE = "Plugins/HiveEngineTrade/HiveEngineTrade.ini"
end
return CONFIG_FILE
end
local function SendPlayerMessage(a_Player, a_Message)
if (a_Player and a_Player.SendMessage) then
a_Player:SendMessage(a_Message)
else
LOG(a_Message)
end
end
local function LoadConfig()
local configPath = ResolveConfigPath()
local ini = cIniFile()
if (not ini:ReadFile(configPath)) then
LOGINFO("HiveEngineTrade: creating default config at " .. configPath)
end
g_Config.HiveEngineRpc = ini:GetValueSet("HiveEngineTrade", "HiveEngineRpc", g_Config.HiveEngineRpc)
g_Config.BridgeUrl = ini:GetValueSet("HiveEngineTrade", "BridgeUrl", g_Config.BridgeUrl)
g_Config.BridgeAuthToken = ini:GetValueSet("HiveEngineTrade", "BridgeAuthToken", g_Config.BridgeAuthToken)
g_Config.PaymentAccount = ini:GetValueSet("HiveEngineTrade", "PaymentAccount", g_Config.PaymentAccount)
g_Config.BankEnabled = ini:GetValueSetB("HiveEngineTrade", "BankEnabled", g_Config.BankEnabled)
g_Config.BankX = ini:GetValueSetI("HiveEngineTrade", "BankX", g_Config.BankX)
g_Config.BankY = ini:GetValueSetI("HiveEngineTrade", "BankY", g_Config.BankY)
g_Config.BankZ = ini:GetValueSetI("HiveEngineTrade", "BankZ", g_Config.BankZ)
g_Config.Debug = ini:GetValueSetB("HiveEngineTrade", "Debug", g_Config.Debug)
g_Config.BankName = ini:GetValueSet("HiveEngineTrade", "BankName", g_Config.BankName)
g_Config.BankerName = ini:GetValueSet("HiveEngineTrade", "BankerName", g_Config.BankerName)
g_Config.DefaultSymbol = ini:GetValueSet("HiveEngineTrade", "DefaultSymbol", g_Config.DefaultSymbol)
g_Config.BankSignsEnabled = ini:GetValueSetB("HiveEngineTrade", "BankSignsEnabled", g_Config.BankSignsEnabled)
g_Config.BankSignSymbols = ini:GetValueSet("HiveEngineTrade", "BankSignSymbols", g_Config.BankSignSymbols)
g_Config.BankSignUpdateSeconds = ini:GetValueSetI("HiveEngineTrade", "BankSignUpdateSeconds", g_Config.BankSignUpdateSeconds)
g_Accounts = {}
local keyId = ini:FindKey("Accounts")
if (keyId ~= cIniFile.noID) then
local numValues = ini:GetNumValues(keyId)
for idx = 0, numValues - 1 do
local valueName = ini:GetValueName(keyId, idx)
if (valueName ~= "__placeholder") then
local value = ini:GetValue("Accounts", valueName)
if (value ~= "") then
g_Accounts[valueName] = value
end
end
end
end
g_Ledger = {}
local ledgerKeyId = ini:FindKey("Ledger")
if (ledgerKeyId ~= cIniFile.noID) then
local numValues = ini:GetNumValues(ledgerKeyId)
for idx = 0, numValues - 1 do
local valueName = ini:GetValueName(ledgerKeyId, idx)
if (valueName ~= "__placeholder") then
local value = ini:GetValue("Ledger", valueName)
local playerName, symbol = valueName:match("^([^:]+):(.+)$")
local amount = tonumber(value or "0") or 0
if (playerName and symbol and amount ~= 0) then
g_Ledger[playerName] = g_Ledger[playerName] or {}
g_Ledger[playerName][symbol] = amount
end
end
end
end
ini:WriteFile(configPath)
g_Bridges = {}
local bridgeKeyId = ini:FindKey("Bridges")
if (bridgeKeyId ~= cIniFile.noID) then
local numValues = ini:GetNumValues(bridgeKeyId)
for idx = 0, numValues - 1 do
local valueName = ini:GetValueName(bridgeKeyId, idx)
if (valueName ~= "__placeholder") then
local value = ini:GetValue("Bridges", valueName)
if (value ~= "") then
g_Bridges[valueName] = value
end
end
end
end
end
local function SaveAccount(a_PlayerName, a_HiveAccount)
local ini = cIniFile()
ini:ReadFile(ResolveConfigPath())
ini:SetValue("Accounts", a_PlayerName, a_HiveAccount)
ini:WriteFile(ResolveConfigPath())
g_Accounts[a_PlayerName] = a_HiveAccount
end
local function SaveBridge(a_PlayerName, a_BridgeUrl)
local ini = cIniFile()
ini:ReadFile(ResolveConfigPath())
if (a_BridgeUrl == nil or a_BridgeUrl == "") then
ini:DeleteValue("Bridges", a_PlayerName)
g_Bridges[a_PlayerName] = nil
else
ini:SetValue("Bridges", a_PlayerName, a_BridgeUrl)
g_Bridges[a_PlayerName] = a_BridgeUrl
end
ini:WriteFile(ResolveConfigPath())
end
local function GetLinkedAccount(a_PlayerName)
return g_Accounts[a_PlayerName]
end
local function GetBridgeUrlForPlayer(a_Player)
if (not a_Player) then
return g_Config.BridgeUrl
end
local name = a_Player:GetName()
return g_Bridges[name] or g_Config.BridgeUrl
end
local function HasAdminPermission(a_Player)
if (not a_Player) then
return true
end
if (a_Player.HasPermission) then
return a_Player:HasPermission("hive.admin")
end
return false
end
local function GetLedgerBalance(a_PlayerName, a_Symbol)
local perPlayer = g_Ledger[a_PlayerName]
if (not perPlayer) then
return 0
end
return perPlayer[a_Symbol] or 0
end
local function SetLedgerBalance(a_PlayerName, a_Symbol, a_Amount)
local amount = tonumber(a_Amount) or 0
if (amount == 0) then
if (g_Ledger[a_PlayerName]) then
g_Ledger[a_PlayerName][a_Symbol] = nil
end
else
g_Ledger[a_PlayerName] = g_Ledger[a_PlayerName] or {}
g_Ledger[a_PlayerName][a_Symbol] = amount
end
local ini = cIniFile()
ini:ReadFile(ResolveConfigPath())
local key = a_PlayerName .. ":" .. a_Symbol
if (amount == 0) then
ini:DeleteValue("Ledger", key)
else
ini:SetValue("Ledger", key, tostring(amount))
end
ini:WriteFile(ResolveConfigPath())
return amount
end
local function AddLedgerBalance(a_PlayerName, a_Symbol, a_Delta)
local delta = tonumber(a_Delta)
if (not delta) then
return nil, "Invalid amount"
end
local current = GetLedgerBalance(a_PlayerName, a_Symbol)
local nextAmount = current + delta
if (nextAmount < 0) then
return nil, "Insufficient balance"
end
return SetLedgerBalance(a_PlayerName, a_Symbol, nextAmount)
end
local function HttpPostJson(a_Url, a_Table, a_Callback, a_Headers)
local body, err = cJson:Serialize(a_Table)
if (not body) then
a_Callback(false, "JSON serialize failed: " .. (err or "<unknown>"))
return
end
local headers = a_Headers or {}
headers["Content-Type"] = "application/json"
local ok, msg = cUrlClient:Post(a_Url,
function(a_Body, a_Data)
if (not a_Body) then
a_Callback(false, a_Data or "<no error>")
return
end
a_Callback(true, a_Body, a_Data)
end,
headers,
body
)
if (not ok) then
a_Callback(false, msg or "<no error>")
end
end
local function HeRpc(a_Method, a_Params, a_Callback)
HttpPostJson(
g_Config.HiveEngineRpc,
{ jsonrpc = "2.0", id = 1, method = a_Method, params = a_Params },
a_Callback
)
end
local function RequireLinkedAccount(a_Player)
local name = a_Player:GetName()
local account = GetLinkedAccount(name)
if (not account or account == "") then
SendPlayerMessage(a_Player, "No Hive account linked. Use /hive link <account>")
return nil
end
return account
end
function Initialize(a_Plugin)
g_Plugin = a_Plugin
g_Plugin:SetName("HiveEngineTrade")
g_Plugin:SetVersion(1)
LoadConfig()
LOG("HiveEngineTrade: ConfigPath=" .. ResolveConfigPath())
LOG("HiveEngineTrade: Config BankEnabled=" .. tostring(g_Config.BankEnabled) ..
" BankXYZ=" .. g_Config.BankX .. "," .. g_Config.BankY .. "," .. g_Config.BankZ ..
" Debug=" .. tostring(g_Config.Debug))
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY, OnPlayerRightClickingEntity)
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_BREAKING_BLOCK, OnPlayerBreakingBlock)
cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick)
if (g_Config.BankEnabled) then
SetupBank()
end
LOG("Initialized " .. g_Plugin:GetName() .. " v." .. g_Plugin:GetVersion())
return true
end
local function IsBankerEntity(a_Entity)
if (not a_Entity) then
return false
end
if (g_Bank.BankerId and a_Entity:GetUniqueID() == g_Bank.BankerId) then
return true
end
if (a_Entity:GetClass() ~= "cVillager") then
return false
end
if (g_Bank.AtmX == 0 and g_Bank.AtmZ == 0) then
return false
end
local pos = a_Entity:GetPosition()
local dx = math.abs(pos.x - g_Bank.AtmX)
local dy = math.abs(pos.y - (g_Bank.AtmY or pos.y))
local dz = math.abs(pos.z - g_Bank.AtmZ)
return (dx <= 3) and (dy <= 3) and (dz <= 3)
end
local function EnsureBankerAt(a_World, a_X, a_Y, a_Z)
local found = nil
local searchBox = cBoundingBox(Vector3d(a_X, a_Y, a_Z), 4, 2)
a_World:ForEachEntityInBox(searchBox, function (a_Entity)
if (IsBankerEntity(a_Entity)) then
found = a_Entity
return true
end
return false
end)
if (found) then
g_Bank.BankerId = found:GetUniqueID()
return
end
local entityId = a_World:SpawnMob(a_X + 0.5, a_Y, a_Z + 0.5, mtVillager)
if (entityId == cEntity.INVALID_ID) then
LOGWARNING("HiveEngineTrade: failed to spawn banker villager")
return
end
a_World:DoWithEntityByID(entityId, function (a_Entity)
g_Bank.BankerId = a_Entity:GetUniqueID()
end)
end
local function ParseSymbolList(a_List)
local symbols = {}
for token in string.gmatch(a_List or "", "[^,%s]+") do
table.insert(symbols, string.upper(token))
end
if (#symbols == 0 and g_Config.DefaultSymbol ~= "") then
table.insert(symbols, string.upper(g_Config.DefaultSymbol))
end
return symbols
end
local function EnsureBankSigns(a_World)
if (g_Bank.SignsPlaced or (not g_Config.BankSignsEnabled)) then
return
end
local baseX = g_Bank.AtmX
local baseY = g_Bank.AtmY
local baseZ = g_Bank.AtmZ
local signBlock = 68 -- wall sign
local signMeta = 2 -- facing north (toward interior)
local symbols = ParseSymbolList(g_Config.BankSignSymbols)
local signY = baseY + 2
local signZ = baseZ + 2
local positions = {
{ baseX - 2, signY, signZ },
{ baseX - 1, signY, signZ },
{ baseX, signY, signZ },
{ baseX + 1, signY, signZ },
{ baseX + 2, signY, signZ },
}
g_Bank.Signs = {}
for idx, symbol in ipairs(symbols) do
local pos = positions[idx]
if (pos) then
local sx, sy, sz = pos[1], pos[2], pos[3]
SetBlockAt(a_World, sx, sy, sz, 0, 0)
SetBlockAt(a_World, sx, sy, sz, signBlock, signMeta)
a_World:SetSignLines(sx, sy, sz, "PRICE", symbol, "loading", "")
table.insert(g_Bank.Signs, { Symbol = symbol, X = sx, Y = sy, Z = sz })
end
end
g_Bank.SignsPlaced = true
if (g_Config.Debug) then
LOG("HiveEngineTrade: Bank signs placed count=" .. tostring(#g_Bank.Signs) .. " z=" .. tostring(signZ))
end
end
local function UpdateBankSigns()
if (not g_Config.BankSignsEnabled) then
return
end
if (g_Bank.WorldName == "" or (not g_Bank.SignsPlaced)) then
return
end
local now = os.time()
if ((now - g_Bank.LastPriceUpdate) < g_Config.BankSignUpdateSeconds) then
return
end
g_Bank.LastPriceUpdate = now
for _, sign in ipairs(g_Bank.Signs) do
HeRpc("findOne", {
contract = "market",
table = "metrics",
query = { symbol = sign.Symbol },
}, function(success, bodyOrErr)
local world = cRoot:Get():GetWorld(g_Bank.WorldName)
if (not world) then
return
end
if (not success) then
world:SetSignLines(sign.X, sign.Y, sign.Z, "PRICE", sign.Symbol, "n/a", "")
return
end
local result = cJson:Parse(bodyOrErr)
local lastPrice = "n/a"
local volume = ""
if (result and result.result) then
lastPrice = result.result.lastPrice or lastPrice
volume = result.result.volume or volume
end
local line4 = (volume ~= "") and ("vol " .. tostring(volume)) or ""
world:SetSignLines(sign.X, sign.Y, sign.Z, "PRICE", sign.Symbol, tostring(lastPrice), line4)
end)
end
end
local function EnsureBankPlatform(a_World, a_X, a_Y, a_Z)
-- Build a simple 7x7 stone-brick building with a plank roof.
-- a_Y is the desired ground level; we place the floor one block lower.
local baseY = a_Y - 1
-- Use numeric block IDs for compatibility:
-- 0 = air, 5 = planks, 98 = stone bricks
local floorBlock = 98
local wallBlock = 98
local roofBlock = 5
local roofMeta = 0 -- oak
local airBlock = 0
local size = 3
local wallHeight = 5
local barsBlock = 101 -- iron bars
-- Clear a 7x7x8 volume to remove old blocks
for dy = 0, 7 do
for dx = -size, size do
for dz = -size, size do
SetBlockAt(a_World, a_X + dx, baseY + dy, a_Z + dz, airBlock, 0)
end
end
end
-- Floor (7x7)
for dx = -size, size do
for dz = -size, size do
SetBlockAt(a_World, a_X + dx, baseY, a_Z + dz, floorBlock, 0)
end
end
-- Walls (height 5)
for dy = 1, wallHeight do
for dx = -size, size do
for dz = -size, size do
local isEdge = (dx == -size) or (dx == size) or (dz == -size) or (dz == size)
if (isEdge) then
-- Doorway at front center (z -size)
if not((dz == -size) and (dx == 0) and (dy <= 2)) then
SetBlockAt(a_World, a_X + dx, baseY + dy, a_Z + dz, wallBlock, 0)
end
end
end
end
end
-- Roof (7x7)
for dx = -size, size do
for dz = -size, size do
SetBlockAt(a_World, a_X + dx, baseY + wallHeight + 1, a_Z + dz, roofBlock, roofMeta)
end
end
-- Banker cage (3x3 iron bars) centered on the banker
local cageMinX = a_X - 1
local cageMaxX = a_X + 1
local cageMinZ = a_Z - 1
local cageMaxZ = a_Z + 1
for dy = 1, 3 do
for dx = cageMinX, cageMaxX do
for dz = cageMinZ, cageMaxZ do
local isEdge = (dx == cageMinX) or (dx == cageMaxX) or (dz == cageMinZ) or (dz == cageMaxZ)
if (isEdge) then
SetBlockAt(a_World, dx, baseY + dy, dz, barsBlock, 0)
else
SetBlockAt(a_World, dx, baseY + dy, dz, airBlock, 0)
end
end
end
end
-- Cage roof
for dx = cageMinX, cageMaxX do
for dz = cageMinZ, cageMaxZ do
SetBlockAt(a_World, dx, baseY + 4, dz, barsBlock, 0)
end
end
end
function SetupBank()
if (g_Bank.Placed) then
return
end
local world = cRoot:Get():GetDefaultWorld()
if (not world) then
LOGWARNING("HiveEngineTrade: default world not ready")
return
end
local spawnX = math.floor(world:GetSpawnX())
local spawnY = math.floor(world:GetSpawnY())
local spawnZ = math.floor(world:GetSpawnZ())
local useFixed = ((g_Config.BankX ~= 0) or (g_Config.BankY ~= 0) or (g_Config.BankZ ~= 0))
local atmX = useFixed and g_Config.BankX or (spawnX + 1)
local atmZ = useFixed and g_Config.BankZ or spawnZ
g_Bank.WorldName = world:GetName()
if (g_Config.Debug) then
LOG("HiveEngineTrade: SetupBank world=" .. g_Bank.WorldName .. " useFixed=" .. tostring(useFixed) .. " target=" .. atmX .. "," .. (useFixed and g_Config.BankY or spawnY) .. "," .. atmZ)
end
local chunkX = math.floor(atmX / 16)
local chunkZ = math.floor(atmZ / 16)
world:ChunkStay({{chunkX, chunkZ}}, nil, function ()
local groundY = spawnY
if (useFixed) then
groundY = g_Config.BankY
else
local isValid, height = world:TryGetHeight(atmX, atmZ)
if (isValid and height and (height > 0)) then
groundY = height
end
end
if (g_Config.Debug) then
LOG("HiveEngineTrade: Chunk ready; placing bank at " .. atmX .. "," .. groundY .. "," .. atmZ)
end
g_Bank.AtmX = atmX
g_Bank.AtmZ = atmZ
g_Bank.AtmY = groundY
g_Bank.AtmBaseY = groundY - 1
EnsureBankPlatform(world, atmX, groundY, atmZ)
world:SetSpawn(atmX, groundY, atmZ)
EnsureBankerAt(world, atmX, groundY, atmZ)
EnsureBankSigns(world)
g_Bank.Placed = true
if (g_Config.Debug) then
LOG("HiveEngineTrade: Bank placed and spawn set")
end
end)
end
function OnTick(a_TimeDelta)
if (g_Config.BankEnabled and (not g_Bank.Placed)) then
SetupBank()
end
if (g_Config.BankEnabled and g_Bank.Placed and (not g_Bank.SignsPlaced)) then
local world = cRoot:Get():GetWorld(g_Bank.WorldName)
if (world) then
EnsureBankSigns(world)
end
end
UpdateBankSigns()
g_TickCounter = g_TickCounter + 1
if (g_Config.Debug and (g_TickCounter == 20)) then
LOG("HiveEngineTrade: Tick running, bankPlaced=" .. tostring(g_Bank.Placed))
end
end
function HandleHiveBankSigns(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local world = a_Player:GetWorld()
g_Bank.SignsPlaced = false
EnsureBankSigns(world)
SendPlayerMessage(a_Player, "Bank signs refreshed")
return true
end
function HandleHiveLink(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local hiveAccount = a_Split[2]
if (not hiveAccount or hiveAccount == "") then
return true, "Usage: /hive link <hiveAccount>"
end
SaveAccount(a_Player:GetName(), hiveAccount)
SendPlayerMessage(a_Player, "Linked Hive account: " .. hiveAccount)
return true
end
function HandleHiveBridge(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local url = a_Split[2]
if (not url or url == "") then
return true, "Usage: /hive bridge <url|clear>"
end
if (string.lower(url) == "clear") then
SaveBridge(a_Player:GetName(), "")
SendPlayerMessage(a_Player, "Cleared personal bridge URL; using server default")
return true
end
SaveBridge(a_Player:GetName(), url)
SendPlayerMessage(a_Player, "Set personal bridge URL: " .. url)
return true
end
function HandleHiveVault(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local name = a_Player:GetName()
local perPlayer = g_Ledger[name]
if (not perPlayer) then
SendPlayerMessage(a_Player, "Vault balance: empty")
return true
end
SendPlayerMessage(a_Player, "Vault balances for " .. name .. ":")
local count = 0
for symbol, amount in pairs(perPlayer) do
SendPlayerMessage(a_Player, "- " .. symbol .. " = " .. tostring(amount))
count = count + 1
end
if (count == 0) then
SendPlayerMessage(a_Player, "Vault balance: empty")
end
return true
end
function HandleHiveVaultAdd(a_Split, a_Player)
if (not HasAdminPermission(a_Player)) then
return true, "No permission"
end
local playerName = a_Split[2]
local symbol = a_Split[3]
local amount = a_Split[4]
if (not playerName or not symbol or not amount) then
return true, "Usage: /hive vaultadd <player> <symbol> <amount>"
end
local newBalance, err = AddLedgerBalance(playerName, symbol, amount)
if (not newBalance) then
SendPlayerMessage(a_Player, "Vault add failed: " .. (err or "<error>"))
return true
end
SendPlayerMessage(a_Player, "Vault updated: " .. playerName .. " " .. symbol .. " = " .. tostring(newBalance))
return true
end
function HandleHiveVaultTake(a_Split, a_Player)
if (not HasAdminPermission(a_Player)) then
return true, "No permission"
end
local playerName = a_Split[2]
local symbol = a_Split[3]
local amount = a_Split[4]
if (not playerName or not symbol or not amount) then
return true, "Usage: /hive vaulttake <player> <symbol> <amount>"
end
local delta = -math.abs(tonumber(amount) or 0)
if (delta == 0) then
return true, "Invalid amount"
end
local newBalance, err = AddLedgerBalance(playerName, symbol, delta)
if (not newBalance) then
SendPlayerMessage(a_Player, "Vault take failed: " .. (err or "<error>"))
return true
end
SendPlayerMessage(a_Player, "Vault updated: " .. playerName .. " " .. symbol .. " = " .. tostring(newBalance))
return true
end
function HandleHiveDeposit(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local symbol = a_Split[2]
local amount = a_Split[3]
if (not symbol or not amount) then
return true, "Usage: /hive deposit <symbol> <amount>"
end
local amountNum = tonumber(amount)
if (not amountNum or amountNum <= 0) then
return true, "Invalid amount"
end
local hiveAccount = RequireLinkedAccount(a_Player)
if (not hiveAccount) then
return true
end
local headers = {}
if (g_Config.BridgeAuthToken ~= "") then
headers["Authorization"] = "Bearer " .. g_Config.BridgeAuthToken
end
local payload = {
action = "deposit",
account = hiveAccount,
player = a_Player:GetName(),
symbol = symbol,
amount = tostring(amountNum),
}
local bridgeUrl = GetBridgeUrlForPlayer(a_Player)
HttpPostJson(bridgeUrl .. "/deposit", payload, function(success, bodyOrErr)
if (not success) then
SendPlayerMessage(a_Player, "Deposit request failed: " .. (bodyOrErr or "<error>"))
return
end
local result, err = cJson:Parse(bodyOrErr)
if (not result) then
SendPlayerMessage(a_Player, "Bridge response invalid: " .. (err or "<parse error>"))
return
end
if (result.ok) then
local instructions = result.instructions or result.memo or result.address or "Deposit request created"
SendPlayerMessage(a_Player, "Deposit instructions: " .. instructions)
SendPlayerMessage(a_Player, "After deposit confirms, an admin will credit your vault balance.")
else
SendPlayerMessage(a_Player, "Deposit rejected: " .. (result.error or "<unknown>"))
end
end, headers)
return true
end
function HandleHiveWithdraw(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local symbol = a_Split[2]
local amount = a_Split[3]
if (not symbol or not amount) then
return true, "Usage: /hive withdraw <symbol> <amount>"
end
local amountNum = tonumber(amount)
if (not amountNum or amountNum <= 0) then
return true, "Invalid amount"
end
local name = a_Player:GetName()
local balance = GetLedgerBalance(name, symbol)
if (balance < amountNum) then
SendPlayerMessage(a_Player, "Insufficient vault balance: " .. tostring(balance))
return true
end
local hiveAccount = RequireLinkedAccount(a_Player)
if (not hiveAccount) then
return true
end
local headers = {}
if (g_Config.BridgeAuthToken ~= "") then
headers["Authorization"] = "Bearer " .. g_Config.BridgeAuthToken
end
local payload = {
action = "withdraw",
account = hiveAccount,
player = a_Player:GetName(),
symbol = symbol,
amount = tostring(amountNum),
}
local bridgeUrl = GetBridgeUrlForPlayer(a_Player)
HttpPostJson(bridgeUrl .. "/withdraw", payload, function(success, bodyOrErr)
if (not success) then
SendPlayerMessage(a_Player, "Withdraw failed: " .. (bodyOrErr or "<error>"))
return
end
local result, err = cJson:Parse(bodyOrErr)
if (not result) then
SendPlayerMessage(a_Player, "Bridge response invalid: " .. (err or "<parse error>"))
return
end
if (result.ok) then
if (result.txid or result.processed) then
local newBalance = AddLedgerBalance(name, symbol, -amountNum)
SendPlayerMessage(a_Player, "Withdraw submitted: " .. (result.txid or "<processed>") .. ". New vault balance: " .. tostring(newBalance))
elseif (result.pending) then
SendPlayerMessage(a_Player, "Withdraw queued: " .. (result.requestId or "<pending>"))
SendPlayerMessage(a_Player, "An admin will finalize this withdrawal.")
else
SendPlayerMessage(a_Player, "Withdraw accepted.")
end
else
SendPlayerMessage(a_Player, "Withdraw rejected: " .. (result.error or "<unknown>"))
end
end, headers)
return true
end
function HandleHiveBalance(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local symbol = a_Split[2]
if (not symbol or symbol == "") then
return true, "Usage: /hive balance <symbol> [hiveAccount]"
end
local hiveAccount = a_Split[3]
if (not hiveAccount or hiveAccount == "") then
hiveAccount = RequireLinkedAccount(a_Player)
if (not hiveAccount) then
return true
end
end
HeRpc("findOne", {
contract = "tokens",
table = "balances",
query = { account = hiveAccount, symbol = symbol },
}, function(success, bodyOrErr)
if (not success) then
SendPlayerMessage(a_Player, "Balance lookup failed: " .. (bodyOrErr or "<error>"))
return
end
local result, err = cJson:Parse(bodyOrErr)
if (not result) then
SendPlayerMessage(a_Player, "Invalid response: " .. (err or "<parse error>"))
return
end
local balance = "0"
if (result.result and result.result.balance) then
balance = result.result.balance
end
SendPlayerMessage(a_Player, "Balance " .. hiveAccount .. " " .. symbol .. " = " .. balance)
end)
return true
end
function HandleHivePrice(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local symbol = a_Split[2]
if (not symbol or symbol == "") then
return true, "Usage: /hive price <symbol>"
end
HeRpc("findOne", {
contract = "market",
table = "metrics",
query = { symbol = symbol },
}, function(success, bodyOrErr)
if (not success) then
SendPlayerMessage(a_Player, "Price lookup failed: " .. (bodyOrErr or "<error>"))
return
end
local result, err = cJson:Parse(bodyOrErr)
if (not result) then
SendPlayerMessage(a_Player, "Invalid response: " .. (err or "<parse error>"))
return
end
local lastPrice = "n/a"
local volume = "n/a"
if (result.result) then
lastPrice = result.result.lastPrice or lastPrice
volume = result.result.volume or volume
end
SendPlayerMessage(a_Player, "Market " .. symbol .. " lastPrice=" .. lastPrice .. " volume=" .. volume)
end)
return true
end
function HandleHiveSwap(a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local hiveAmount = a_Split[2]
local symbol = a_Split[3] or g_Config.DefaultSymbol
if (not hiveAmount) then
return true, "Usage: /hive swap <hiveAmount> [symbol]"
end
local amountNum = tonumber(hiveAmount)
if (not amountNum or amountNum <= 0) then
return true, "Invalid hiveAmount"
end
local hiveAccount = RequireLinkedAccount(a_Player)
if (not hiveAccount) then
return true
end
HeRpc("findOne", {
contract = "market",
table = "metrics",
query = { symbol = symbol },
}, function(success, bodyOrErr)
if (not success) then
SendPlayerMessage(a_Player, "Swap lookup failed: " .. (bodyOrErr or "<error>"))
return
end
local result, err = cJson:Parse(bodyOrErr)
if (not result) then
SendPlayerMessage(a_Player, "Invalid response: " .. (err or "<parse error>"))
return
end
if (not result.result or not result.result.lastPrice) then
SendPlayerMessage(a_Player, "No market data for " .. symbol)
return
end
local price = tonumber(result.result.lastPrice)
if (not price or price <= 0) then
SendPlayerMessage(a_Player, "Invalid market price for " .. symbol)
return
end
local quantity = amountNum / price
local qtyStr = string.format("%.3f", quantity)
local priceStr = string.format("%.3f", price)
SendPlayerMessage(a_Player, "Submitting market swap at price " .. priceStr .. " for quantity " .. qtyStr)
local split = { a_Split[1], symbol, priceStr, qtyStr }
SubmitTrade("buy", split, a_Player)
end)
return true
end
local function SubmitTrade(a_Action, a_Split, a_Player)
if (not a_Player) then
return true, "This command must be run by a player"
end
local symbol = a_Split[2]
local price = a_Split[3]
local quantity = a_Split[4]
if (not symbol or not price or not quantity) then
return true, "Usage: /hive " .. a_Action .. " <symbol> <price> <quantity>"
end
local hiveAccount = RequireLinkedAccount(a_Player)
if (not hiveAccount) then
return true
end
local headers = {}
if (g_Config.BridgeAuthToken ~= "") then
headers["Authorization"] = "Bearer " .. g_Config.BridgeAuthToken
end
local payload = {
action = a_Action,
account = hiveAccount,
symbol = symbol,
price = price,
quantity = quantity,
}
local bridgeUrl = GetBridgeUrlForPlayer(a_Player)
HttpPostJson(bridgeUrl .. "/trade", payload, function(success, bodyOrErr)
if (not success) then
SendPlayerMessage(a_Player, "Trade failed: " .. (bodyOrErr or "<error>"))
return
end
local result, err = cJson:Parse(bodyOrErr)
if (not result) then
SendPlayerMessage(a_Player, "Bridge response invalid: " .. (err or "<parse error>"))
return
end
if (result.ok) then
SendPlayerMessage(a_Player, "Trade submitted: " .. (result.txid or "<no txid>"))
else
SendPlayerMessage(a_Player, "Trade rejected: " .. (result.error or "<unknown>"))
end
end, headers)
return true
end
function HandleHiveBuy(a_Split, a_Player)
return SubmitTrade("buy", a_Split, a_Player)
end
function HandleHiveSell(a_Split, a_Player)
return SubmitTrade("sell", a_Split, a_Player)
end
function OnPlayerRightClickingEntity(a_Player, a_Entity)
if (not IsBankerEntity(a_Entity)) then
return false
end
SendPlayerMessage(a_Player, g_Config.BankName .. " - Banker")
SendPlayerMessage(a_Player, "Use /hive vault, /hive deposit <symbol> <amount>, /hive withdraw <symbol> <amount>")
SendPlayerMessage(a_Player, "Market: /hive price " .. g_Config.DefaultSymbol .. " and /hive swap <hiveAmount> " .. g_Config.DefaultSymbol)
return true
end
function OnPlayerBreakingBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta)
if (g_Bank.WorldName == "") then
return false
end
local world = a_Player:GetWorld()
if (world:GetName() ~= g_Bank.WorldName) then
return false
end
local inFootprint =
(a_BlockX >= g_Bank.AtmX - 2) and (a_BlockX <= g_Bank.AtmX + 2) and
(a_BlockZ >= g_Bank.AtmZ - 2) and (a_BlockZ <= g_Bank.AtmZ + 2) and
(a_BlockY >= g_Bank.AtmBaseY) and (a_BlockY <= g_Bank.AtmBaseY + 4)
if (inFootprint) then
SendPlayerMessage(a_Player, "This bank is unbreakable")
return true
end
return false
end
🪙 PeakeCoin Ecosystem
💱 PeakeCoin USDT Bridge (Hive ↔ Polygon/MATIC)
Bridge SWAP.USDT from Hive Engine to USDT on Polygon (MATIC).
Whitelist access, documentation, and bridge status updates:
👉 https://geocities.ws/peakecoin
⚙️ HiveP.I.M.P. — PeakeCoin Intelligent Market Protector
Operated by @hivepimp, P.I.M.P. focuses on stabilizing PEK markets and strengthening liquidity on Hive Engine.
Community participation supports long-term ecosystem health.
🤖 PeakeBot — Autonomous Trading System
Independent multi-token trading bot with RC-awareness, adaptive delay logic, and smart cycle control.
📊 Trading bot documentation:
👉 https://geocities.ws/p/e/peakecoin/trading-bot/peakebot_v0_01.html
💻 Open-source repositories:
👉 https://github.com/paulmoon410
🎰 PeakeSino — The PeakeCoin Casino (Beta)
Blockchain-powered games using PEK as the native in-game currency.
Built on Hive with a focus on provable fairness and community-driven growth.
🃏 Play the beta games here:
👉 https://geocities.ws/peakecoin/pek_casino/beta_games/index.html
🙏 Acknowledgements
Thanks to and please follow:
@enginewitty @ecoinstant @neoxian @txracer @thecrazygm @holdonia @aggroed
For their continued support, guidance, and help expanding the PeakeCoin ecosystem.
Upvoted! Thank you for supporting witness @jswit.