HiveCraft - In Game Browser Coding
I have been working on trying to code in a browser for the Bank feature, and the @Splinterlands features...

Please be patient, I've been working on stuff relentlessly. The game is in a rough place... If you want to help.. I definitely need it.
info.lua
g_PluginInfo =
{
Name = "WebBrowser",
Date = "2026-03-26",
Description = [[
In-game web browser. Fetches URLs, searches DuckDuckGo,
queries Wikipedia, and shows live Hive Engine token metrics.
Content is displayed as paged chat output.
]],
Commands =
{
["/web"] =
{
HelpString = "In-game browser: /web <url> | search <q> | wiki <t> | hive <SYM> | next | prev",
Handler = HandleWeb,
ParameterCombinations =
{
{ Params = "<url>", HelpString = "Fetch a URL" },
{ Params = "next", HelpString = "Next page" },
{ Params = "prev", HelpString = "Previous page" },
{ Params = "search <query>", HelpString = "DuckDuckGo instant answer" },
{ Params = "wiki <topic>", HelpString = "Wikipedia article summary" },
{ Params = "hive <SYMBOL>", HelpString = "Hive Engine token metrics" },
},
},
},
}
main.lua
-- WebBrowser/main.lua
-- In-game web browser using paged chat display
-- Commands: /web <url> | /web search <query> | /web wiki <topic> | /web hive <symbol> | /web next | /web prev
local g_Sessions = {} -- [playerName] = { pages={}, current=1, title="", url="" }
local PAGE_LINES = 12
local LINE_WIDTH = 52
-- ─── HTML Stripper ──────────────────────────────────────────────────────────
local function StripHtml(a_Html)
local t = a_Html
-- Remove noisy blocks entirely
t = t:gsub("<[Ss][Cc][Rr][Ii][Pp][Tt][^>]*>.-</[Ss][Cc][Rr][Ii][Pp][Tt]>", "")
t = t:gsub("<[Ss][Tt][Yy][Ll][Ee][^>]*>.-</[Ss][Tt][Yy][Ll][Ee]>", "")
-- Block elements → newline
t = t:gsub("<[Bb][Rr]%s*/?>", "\n")
t = t:gsub("<[Pp][^>]*>", "\n")
t = t:gsub("</[Pp]>", "\n")
t = t:gsub("<[Dd][Ii][Vv][^>]*>", "\n")
t = t:gsub("</[Dd][Ii][Vv]>", "\n")
t = t:gsub("<[Ll][Ii][^>]*>", "\n- ")
t = t:gsub("<[Hh][1-6][^>]*>", "\n## ")
t = t:gsub("</[Hh][1-6]>", "\n")
-- Strip all remaining tags
t = t:gsub("<[^>]+>", "")
-- HTML entities
t = t:gsub("&", "&")
t = t:gsub("<", "<")
t = t:gsub(">", ">")
t = t:gsub(""", '"')
t = t:gsub("'", "'")
t = t:gsub(" ", " ")
t = t:gsub("&#(%d+);", function(n)
local num = tonumber(n)
if (num and num >= 32 and num <= 126) then
return string.char(num)
end
return ""
end)
-- Collapse whitespace
t = t:gsub("[ \t]+", " ")
t = t:gsub(" \n", "\n")
t = t:gsub("\n ", "\n")
t = t:gsub("\n\n+", "\n")
t = t:gsub("^\n+", "")
return t
end
-- ─── Text Layout ─────────────────────────────────────────────────────────────
local function WrapText(a_Text, a_MaxWidth)
local lines = {}
for para in (a_Text .. "\n"):gmatch("([^\n]*)\n") do
if (para == "") then
-- skip blank lines to save space
else
local current = ""
for word in para:gmatch("[^ ]+") do
-- split word if it's wider than the line
while (#word > a_MaxWidth) do
if (#current > 0) then
table.insert(lines, current)
current = ""
end
table.insert(lines, word:sub(1, a_MaxWidth))
word = word:sub(a_MaxWidth + 1)
end
local candidate = (current == "") and word or (current .. " " .. word)
if (#candidate <= a_MaxWidth) then
current = candidate
else
if (#current > 0) then
table.insert(lines, current)
end
current = word
end
end
if (#current > 0) then
table.insert(lines, current)
end
end
end
return lines
end
local function PaginateLines(a_Lines, a_LinesPerPage)
local pages = {}
local i = 1
while (i <= #a_Lines) do
local page = {}
for j = i, math.min(i + a_LinesPerPage - 1, #a_Lines) do
table.insert(page, a_Lines[j])
end
table.insert(pages, page)
i = i + a_LinesPerPage
end
return pages
end
-- ─── Display ─────────────────────────────────────────────────────────────────
local function ShowPage(a_Player, a_Session, a_PageNum)
local pages = a_Session.pages
if (a_PageNum < 1 or a_PageNum > #pages) then
a_Player:SendMessageFailure("No page " .. a_PageNum .. " (total: " .. #pages .. ")")
return
end
a_Session.current = a_PageNum
local divider = cChatColor.Gray .. string.rep("-", 50)
a_Player:SendMessage(divider)
a_Player:SendMessage(cChatColor.Gold .. "[WEB] " .. cChatColor.White .. a_Session.title)
a_Player:SendMessage(cChatColor.Yellow .. "p." .. a_PageNum .. "/" .. #pages
.. " " .. cChatColor.DarkGray .. a_Session.url)
a_Player:SendMessage(divider)
for _, line in ipairs(pages[a_PageNum]) do
a_Player:SendMessage(cChatColor.White .. line)
end
a_Player:SendMessage(divider)
local nav = ""
if (a_PageNum > 1) then nav = nav .. cChatColor.Aqua .. "/web prev " end
if (a_PageNum < #pages) then nav = nav .. cChatColor.Aqua .. "/web next" end
if (nav ~= "") then a_Player:SendMessage(nav) end
end
-- ─── URL Fetcher ─────────────────────────────────────────────────────────────
local function FetchUrl(a_Player, a_Url, a_TitleOverride, a_ParseFn)
a_Player:SendMessageInfo("Fetching " .. a_Url .. " ...")
local name = a_Player:GetName()
local ok, err = cUrlClient:Get(a_Url, function(a_Body, a_Status, a_Headers)
if (not a_Body or a_Body == "") then
a_Player:SendMessageFailure("Empty response (status=" .. tostring(a_Status) .. ")")
return
end
local title, lines
if (a_ParseFn) then
title, lines = a_ParseFn(a_Body)
else
-- Default: strip HTML
local text = a_Body
local ct = (a_Headers and (a_Headers["Content-Type"] or a_Headers["content-type"])) or ""
if (ct:find("html") or ct == "") then
text = StripHtml(text)
-- Try to extract <title>
if (not a_TitleOverride) then
local t = a_Body:match("<title[^>]*>([^<]+)</title>")
a_TitleOverride = (t and t:gsub("^%s+", ""):gsub("%s+$", "")) or a_Url
end
end
lines = WrapText(text, LINE_WIDTH)
title = a_TitleOverride or a_Url
end
if (not lines or #lines == 0) then
a_Player:SendMessageFailure("No readable content.")
return
end
local pages = PaginateLines(lines, PAGE_LINES)
g_Sessions[name] = { pages = pages, current = 1, title = title, url = a_Url }
ShowPage(a_Player, g_Sessions[name], 1)
end, {})
if (not ok) then
a_Player:SendMessageFailure("Request failed: " .. (err or "unknown"))
end
end
-- ─── Search Parsers ──────────────────────────────────────────────────────────
local function ParseDuckDuckGo(a_Body)
local data = cJson:Parse(a_Body)
if (not data) then
return "Search", { "Failed to parse results." }
end
local lines = {}
if (data.Abstract and data.Abstract ~= "") then
table.insert(lines, "[ Summary ]")
for _, l in ipairs(WrapText(data.Abstract, LINE_WIDTH)) do
table.insert(lines, l)
end
end
if (data.Answer and data.Answer ~= "") then
table.insert(lines, "[ Answer ]")
for _, l in ipairs(WrapText(data.Answer, LINE_WIDTH)) do
table.insert(lines, l)
end
end
if (data.RelatedTopics) then
table.insert(lines, "[ Related ]")
for i, topic in ipairs(data.RelatedTopics) do
if (i > 8) then break end
if (topic.Text and topic.Text ~= "") then
for _, l in ipairs(WrapText("- " .. topic.Text, LINE_WIDTH)) do
table.insert(lines, l)
end
end
end
end
if (#lines == 0) then
table.insert(lines, "No instant-answer results.")
table.insert(lines, "Try /web wiki <topic> for Wikipedia.")
end
return "Search: " .. (data.Heading or ""), lines
end
local function ParseWikipedia(a_Body)
local data = cJson:Parse(a_Body)
if (not data or not data.extract) then
return "Wikipedia", { "No article found." }
end
local lines = {}
if (data.description and data.description ~= "") then
for _, l in ipairs(WrapText("[" .. data.description .. "]", LINE_WIDTH)) do
table.insert(lines, l)
end
end
for _, l in ipairs(WrapText(data.extract, LINE_WIDTH)) do
table.insert(lines, l)
end
return "Wiki: " .. (data.title or ""), lines
end
local function ParseHiveMetrics(a_Body, a_Symbol)
local data = cJson:Parse(a_Body)
local lines = {}
if (not data or not data.result) then
table.insert(lines, "No data for " .. a_Symbol)
return "Hive: " .. a_Symbol, lines
end
local r = data.result
local fields = {
{ "Symbol", r.symbol },
{ "Last Price", r.lastPrice },
{ "Highest Bid",r.highestBid },
{ "Lowest Ask", r.lowestAsk },
{ "24h Volume", r.volume },
{ "Vol HIVE", r.volumeExpiration },
{ "Trade Count",r.tradesInLastHour },
{ "High", r.priceChangeHivePct },
}
for _, pair in ipairs(fields) do
local label, value = pair[1], pair[2]
if (value and value ~= "" and value ~= nil) then
table.insert(lines, label .. ": " .. tostring(value))
end
end
return "Hive: " .. a_Symbol, lines
end
-- ─── Command Handler ─────────────────────────────────────────────────────────
function HandleWeb(a_Split, a_Player)
if (not a_Player) then
return true, "Must be run as a player"
end
local sub = a_Split[2]
if (not sub or sub == "") then
a_Player:SendMessageInfo(cChatColor.Gold .. "WebBrowser commands:")
a_Player:SendMessageInfo(cChatColor.Yellow .. "/web <url> " .. cChatColor.White .. "fetch any URL")
a_Player:SendMessageInfo(cChatColor.Yellow .. "/web search <q> " .. cChatColor.White .. "DuckDuckGo instant answer")
a_Player:SendMessageInfo(cChatColor.Yellow .. "/web wiki <topic> " .. cChatColor.White .. "Wikipedia summary")
a_Player:SendMessageInfo(cChatColor.Yellow .. "/web hive <SYMBOL> " .. cChatColor.White .. "Hive Engine token metrics")
a_Player:SendMessageInfo(cChatColor.Yellow .. "/web next /web prev")
return true
end
local name = a_Player:GetName()
local subLow = sub:lower()
-- Navigation
if (subLow == "next" or subLow == "n") then
local s = g_Sessions[name]
if (not s) then a_Player:SendMessageFailure("No page open. Use /web <url> first.") return true end
ShowPage(a_Player, s, s.current + 1)
return true
end
if (subLow == "prev" or subLow == "p" or subLow == "back" or subLow == "b") then
local s = g_Sessions[name]
if (not s) then a_Player:SendMessageFailure("No page open. Use /web <url> first.") return true end
ShowPage(a_Player, s, s.current - 1)
return true
end
-- DuckDuckGo search
if (subLow == "search" or subLow == "s") then
local query = table.concat(a_Split, " ", 3)
if (not query or query == "") then return true, "Usage: /web search <query>" end
local encoded = query:gsub("[^%w%-_%.~]", function(c)
return string.format("%%%02X", string.byte(c))
end)
local url = "https://api.duckduckgo.com/?q=" .. encoded .. "&format=json&no_html=1&skip_disambig=1"
FetchUrl(a_Player, url, nil, function(b) return ParseDuckDuckGo(b) end)
return true
end
-- Wikipedia
if (subLow == "wiki" or subLow == "w") then
local topic = table.concat(a_Split, "_", 3)
if (not topic or topic == "") then return true, "Usage: /web wiki <topic>" end
local url = "https://en.wikipedia.org/api/rest_v1/page/summary/" .. topic
FetchUrl(a_Player, url, nil, function(b) return ParseWikipedia(b) end)
return true
end
-- Hive Engine token
if (subLow == "hive") then
local symbol = (a_Split[3] or ""):upper()
if (symbol == "") then return true, "Usage: /web hive <SYMBOL>" end
local url = "https://api.hive-engine.com/rpc/contracts"
local body = '{"jsonrpc":"2.0","id":1,"method":"findOne","params":{"contract":"market","table":"metrics","query":{"symbol":"' .. symbol .. '"}}}'
a_Player:SendMessageInfo("Fetching Hive Engine: " .. symbol .. " ...")
local ok, err = cUrlClient:Post(url, function(a_Body, a_Status)
if (not a_Body or a_Body == "") then
a_Player:SendMessageFailure("Empty response")
return
end
local title, lines = ParseHiveMetrics(a_Body, symbol)
local pages = PaginateLines(lines, PAGE_LINES)
g_Sessions[name] = { pages = pages, current = 1, title = title, url = url }
ShowPage(a_Player, g_Sessions[name], 1)
end, { ["Content-Type"] = "application/json" }, body)
if (not ok) then a_Player:SendMessageFailure("Request failed: " .. (err or "")) end
return true
end
-- Raw URL
local url = sub
if (not url:match("^https?://")) then
url = "https://" .. url
end
FetchUrl(a_Player, url, nil, nil)
return true
end
function Initialize(Plugin)
Plugin:SetName("WebBrowser")
Plugin:SetVersion(1)
LOG("WebBrowser loaded")
return true
end
plugin.lua
dofile("Plugins/WebBrowser/main.lua")
🪙 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.