From 1748f076635a33c50ad18945e7ef467bc203b355 Mon Sep 17 00:00:00 2001 From: ankushKun Date: Mon, 27 May 2024 16:00:05 +0530 Subject: [PATCH] editor dont consume scroll --- next_app/pbcopy | 424 --------------------- next_app/src/components/bottom-tab-bar.tsx | 6 +- next_app/src/components/layout.tsx | 17 +- next_app/src/components/terminal.tsx | 99 +++-- next_app/src/pages/_app.tsx | 1 + 5 files changed, 63 insertions(+), 484 deletions(-) delete mode 100644 next_app/pbcopy diff --git a/next_app/pbcopy b/next_app/pbcopy deleted file mode 100644 index 3d982eb..0000000 --- a/next_app/pbcopy +++ /dev/null @@ -1,424 +0,0 @@ --- CRED = "Sa0iBLPNyJQrwpTTG-tWLQU-1QeUAJA73DdxGGiKoJc" -Version = "0.3" - --- Attack info -LastPlayerAttacks = LastPlayerAttacks or {} -CurrentAttacks = CurrentAttacks or 0 -TenSecondCheck = TenSecondCheck or 0 - --- grid dimensions -Width = 10 -Height = 10 -Range = 3 - --- Player energy -MaxEnergy = 100 -EnergyPerSec = 1 --- Attack settings -AverageMaxStrengthHitsToKill = 3 -- Average number of hits to eliminate a player - --- Initializes default player state --- @return Table representing player's initial state -function playerInitState() - return { - x = math.random(0, Width), - y = math.random(0, Height), - health = 100, - energy = 0, - lastTurn = 0 - } -end - --- Function to incrementally increase player's energy --- Called periodically to update player energy -function onTick() - if GameMode ~= "Playing" then return end -- Only active during "Playing" state - - if LastTick == undefined then LastTick = Now end - - local Elapsed = Now - LastTick - if Elapsed >= 1000 then -- Actions performed every second - for player, state in pairs(Players) do - local newEnergy = math.floor(math.min(MaxEnergy, state.energy + (Elapsed * EnergyPerSec // 2000))) - state.energy = newEnergy - end - LastTick = Now - end - - if TenSecondCheck == 0 then - TenSecondCheck = Now - end - - local TenSecondElaspedCheck = Now - TenSecondCheck - if TenSecondElaspedCheck >= 10000 then - -- only keep the last 20 - while #LastPlayerAttacks > 20 do - table.remove(LastPlayerAttacks, 1) - end - TenSecondCheck = Now - end - - -end - -local function isOccupied(x,y) - local result = false - for k,v in pairs(Players) do - if v.x == x and v.y == y then - result = true - return - end - end -end - --- Handles player movement --- @param msg: Message request sent by player with movement direction and player info -function move(msg) - local playerToMove = msg.From - local direction = msg.Tags.Direction - - local directionMap = { - Up = {x = 0, y = -1}, Down = {x = 0, y = 1}, - Left = {x = -1, y = 0}, Right = {x = 1, y = 0}, - UpRight = {x = 1, y = -1}, UpLeft = {x = -1, y = -1}, - DownRight = {x = 1, y = 1}, DownLeft = {x = -1, y = 1} - } - - -- only 1 turn per second - if msg.Timestamp < Players[playerToMove].lastTurn + 1000 then - return - end - -- calculate and update new coordinates - if directionMap[direction] then - local newX = Players[playerToMove].x + directionMap[direction].x - local newY = Players[playerToMove].y + directionMap[direction].y - - -- Player cant move to cell already occupied. - if isOccupied(newX, newY) then - Send({Target = playerToMove, Action = "Move-Failed", Reason = "Cell Occupied."}) - return - end - - -- updates player coordinates while checking for grid boundaries - Players[playerToMove].x = (newX - 1) % Width + 1 - Players[playerToMove].y = (newY - 1) % Height + 1 - - Send({Target = playerToMove, Action="Player-Moved", Data = playerToMove .. " moved to " .. Players[playerToMove].x .. "," .. Players[playerToMove].y .. "."}) - --announce("Player-Moved", playerToMove .. " moved to " .. Players[playerToMove].x .. "," .. Players[playerToMove].y .. ".") - else - Send({Target = playerToMove, Action = "Move-Failed", Reason = "Invalid direction."}) - end - Players[playerToMove].lastTurn = msg.Timestamp - onTick() -- Optional: Update energy each move -end - --- Handles player attacks --- @param msg: Message request sent by player with attack info and player state -function attack(msg) - local player = msg.From - local attackEnergy = tonumber(msg.Tags.AttackEnergy) < 0 and 0 or tonumber(msg.Tags.AttackEnergy) - - -- get player coordinates - local x = Players[player].x - local y = Players[player].y - - -- only 1 turn per second - if msg.Timestamp < Players[player].lastTurn + 1000 then - return - end - - -- check if player has enough energy to attack - if Players[player].energy < attackEnergy then - ao.send({Target = player, Action = "Attack-Failed", Reason = "Not enough energy."}) - return - end - - -- update player energy and calculate damage - Players[player].energy = Players[player].energy - attackEnergy - local damage = math.floor((math.random() * 2 * attackEnergy) * (2/AverageMaxStrengthHitsToKill)) - - --announce("Attack", player .. " has launched a " .. damage .. " damage attack from " .. x .. "," .. y .. "!") - -- check if any player is within range and update their status - for target, state in pairs(Players) do - if target ~= player and inRange(x, y, state.x, state.y, Range) then - local newHealth = state.health - damage - -- Document Current Attacks - CurrentAttacks = CurrentAttacks + 1 - LastPlayerAttacks[CurrentAttacks] = { - Player = player, - Target = target, - id = CurrentAttacks - } - if newHealth <= 0 then - eliminatePlayer(target, player) - else - Players[target].health = newHealth - Send({Target = target, Action = "Hit", Damage = tostring(damage), Health = tostring(newHealth)}) - Send({Target = player, Action = "Successful-Hit", Recipient = target, Damage = tostring(damage), Health = tostring(newHealth)}) - end - end - end - Players[player].lastTurn = msg.Timestamp -end - --- Helper function to check if a target is within range --- @param x1, y1: Coordinates of the attacker --- @param x2, y2: Coordinates of the potential target --- @param range: Attack range --- @return Boolean indicating if the target is within range -function inRange(x1, y1, x2, y2, range) - return x2 >= (x1 - range) and x2 <= (x1 + range) and y2 >= (y1 - range) and y2 <= (y1 + range) -end - --- HANDLERS: Game state management for AO-Effect - --- Handler for player movement -Handlers.add("PlayerMove", Handlers.utils.hasMatchingTag("Action", "PlayerMove"), move) - --- Handler for player attacks -Handlers.add("PlayerAttack", Handlers.utils.hasMatchingTag("Action", "PlayerAttack"), attack) - --- ARENA GAME BLUEPRINT. - --- REQUIREMENTS: cron must be added and activated for game operation. - --- This blueprint provides the framework to operate an 'arena' style game --- inside an ao process. Games are played in rounds, where players aim to --- eliminate one another until only one remains, or until the game time --- has elapsed. The game process will play rounds indefinitely as players join --- and leave. - --- When a player eliminates another, they receive the eliminated player's deposit token --- as a reward. Additionally, the builder can provide a bonus of these tokens --- to be distributed per round as an additional incentive. If the intended --- player type in the game is a bot, providing an additional 'bonus' --- creates an opportunity for coders to 'mine' the process's --- tokens by competing to produce the best agent. - --- The builder can also provide other handlers that allow players to perform --- actions in the game, calling 'eliminatePlayer()' at the appropriate moment --- in their game logic to control the framework. - --- Processes can also register in a 'Listen' mode, where they will receive --- all announcements from the game, but are not considered for entry into the --- rounds themselves. They are also not unregistered unless they explicitly ask --- to be. - --- GLOBAL VARIABLES. - --- Game progression modes in a loop: --- [Not-Started] -> Waiting -> Playing -> [Someone wins or timeout] -> Waiting... --- The loop is broken if there are not enough players to start a game after the waiting state. -GameMode = GameMode or "Playing" -StateChangeTime = StateChangeTime or 0 - --- State durations (in milliseconds) -WaitTime = WaitTime or 2 * 60 * 1000 -- 2 minutes -GameTime = GameTime or 20 * 60 * 1000 -- 20 minutes -Now = Now or 0 -- Current time, updated on every message. - --- Token information for player stakes. -PaymentToken = PaymentToken or ao.id -- Token address -PaymentQty = PaymentQty or 1 -- Quantity of tokens for registration -BonusQty = BonusQty or 1 -- Bonus token quantity for winners - --- Players waiting to join the next game and their payment status. -Waiting = Waiting or {} --- Active players and their game states. -Players = Players or {} --- Number of winners in the current game. -Winners = 0 --- Processes subscribed to game announcements. -Listeners = Listeners or {} --- Minimum number of players required to start a game. -MinimumPlayers = MinimumPlayers or 1 - --- Default player state initialization. -PlayerInitState = PlayerInitState or {} - - --- Sends a state change announcement to all registered listeners. --- @param event: The event type or name. --- @param description: Description of the event. -function announce(event, description) - for ix, address in pairs(Listeners) do - ao.send({ - Target = address, - Action = "Announcement", - Event = event, - Data = description - }) - end -end - --- Sends a reward to a player. --- @param recipient: The player receiving the reward. --- @param qty: The quantity of the reward. --- @param reason: The reason for the reward. -function sendReward(recipient, qty, reason) - ao.send({ - Target = PaymentToken, - Action = "Transfer", - Quantity = tostring(qty), - Recipient = recipient, - Reason = reason - }) -end - --- Removes a listener from the listeners' list. --- @param listener: The listener to be removed. -function removeListener(listener) - local idx = 0 - for i, v in ipairs(Listeners) do - if v == listener then - idx = i - -- addLog("removeListener", "Found listener: " .. listener .. " at index: " .. idx) -- Useful for tracking listener removal - break - end - end - if idx > 0 then - -- addLog("removeListener", "Removing listener: " .. listener .. " at index: " .. idx) -- Useful for tracking listener removal - table.remove(Listeners, idx) - end -end - --- Handles the elimination of a player from the game. --- @param eliminated: The player to be eliminated. --- @param eliminator: The player causing the elimination. -function eliminatePlayer(eliminated, eliminator) - - sendReward(eliminator, tonumber(GameBalances[eliminated]), "Eliminated-Player") - GameBalances[eliminated] = "0" - Players[eliminated] = nil - - Send({ - Target = eliminated, - Action = "Eliminated", - Eliminator = eliminator - }) - removeListener(eliminated) - -- announce("Player-Eliminated", eliminated .. " was eliminated by " .. eliminator .. "!") - - local playerCount = 0 - for player, _ in pairs(Players) do - playerCount = playerCount + 1 - end -end - -function scaleNumber(oldValue) - local oldMin = 10 - local oldMax = 1000 - local newMin = 1 - local newMax = 100 - - local newValue = (((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin - return newValue -end - - - --- HANDLERS: Game state management - --- Handler for cron messages, manages game state transitions. -Handlers.add( - "Game-State-Timers", - function(Msg) - return "continue" - end, - function(Msg) - Now = tonumber(Msg.Timestamp) - onTick() - end -) - --- Handler for player deposits to participate in the next game. -Handlers.add( - "Transfer", - function(Msg) - return - Msg.Action == "Credit-Notice" and - -- Msg.From == CRED and - tonumber(Msg.Quantity) >= PaymentQty and "continue" - end, - function(Msg) - print("Player " .. Msg.Sender .. " has deposited " .. Msg.Quantity .. " " .. PaymentToken .. " to join the game.") - local q = tonumber(Msg.Quantity) - - if not GameBalances[Msg.Sender] then - GameBalances[Msg.Sender] = "0" - end - - local balance = tonumber(GameBalances[Msg.Sender]) - Players[Msg.Sender] = playerInitState() - - balance = math.floor(balance + q) - GameBalances[Msg.Sender] = tostring(balance) - if balance <= 10 then - Players[Msg.Sender].health = 1 - elseif balance >= 1000 then - Players[Msg.Sender].health = 100 - else - Players[Msg.Sender].health = math.floor(scaleNumber(balance)) - end - Send({ - Target = Msg.Sender, - Action = "Payment-Received", - Data = "You are in the game." - }) - - end -) - --- Exits the game receives CRED -Handlers.add( - "Withdraw", - Handlers.utils.hasMatchingTag("Action", "Withdraw"), - function(Msg) - Players[Msg.From] = nil - Send({Target = Game, Action = "Transfer", Quantity = GameBalances[Msg.From], Recipient = Msg.From }) - GameBalances[Msg.From] = "0" - removeListener(Msg.From) - Send({ - Target = Msg.From, - Action = "Removed from the Game" - }) - end -) - - --- Retrieves the current game state. -Handlers.add( - "GetGameState", - Handlers.utils.hasMatchingTag("Action", "GetGameState"), - function (Msg) - if Players[Msg.From] and Msg.Name then - Players[Msg.From].name = Msg.Name - end - local json = require("json") - local GameState = json.encode({ - GameMode = GameMode, - Players = Players, - }) - Send({ - Target = Msg.From, - Action = "GameState", - Data = GameState - }) - end -) - --- Retrieves the current attacks that has been made in the game. -Handlers.add( - "GetGameAttacksInfo", - Handlers.utils.hasMatchingTag("Action", "GetGameAttacksInfo"), - function (Msg) - local GameAttacksInfo = require("json").encode({ - LastPlayerAttacks = Utils.values(LastPlayerAttacks) - }) - Send({ - Target = Msg.From, - Action = "GameAttacksInfo", - Data = GameAttacksInfo - }) - end -) diff --git a/next_app/src/components/bottom-tab-bar.tsx b/next_app/src/components/bottom-tab-bar.tsx index 4c85252..54afda8 100644 --- a/next_app/src/components/bottom-tab-bar.tsx +++ b/next_app/src/components/bottom-tab-bar.tsx @@ -143,9 +143,9 @@ export default function BottomTabBar({ collapsed, toggle, setFullScreen, fullscr {collapsed ? : } - {globalState.activeProject &&
+
- + {globalState.activeProject && } {/*
{prompt}
  ))} -
} +
); } diff --git a/next_app/src/components/layout.tsx b/next_app/src/components/layout.tsx index b16d422..f6bb9ce 100644 --- a/next_app/src/components/layout.tsx +++ b/next_app/src/components/layout.tsx @@ -59,8 +59,13 @@ const monacoConfig: { lineHeight: 20, lineNumbersMinChars: 2, scrollBeyondLastLine: false, - scrollbar: { vertical: "hidden", horizontal: "hidden" }, + scrollBeyondLastColumn: 10, + scrollbar: { + vertical: "hidden", horizontal: "hidden", + alwaysConsumeMouseWheel: false + }, renderLineHighlight: "none", + smoothScrolling: true, }, CodeFile: { fontSize: 14, @@ -205,12 +210,10 @@ const CodeCell = ({ manager.updateFile(project, { file, content: newContent }); }} height={ - (cell.code.split("\n").length > 10 - ? 10 - : cell.code.split("\n").length) * 20 + (cell.code.split("\n").length > 15 ? 15 : cell.code.split("\n").length) * 20 } width="94%" - className="min-h-[68px] pt-0 font-btr-code" + className="min-h-[68px] pt-0 font-btr-code overflow-y-clip" value={cell.code} defaultValue={cell.code} language={file.language} @@ -302,8 +305,8 @@ const VisualCell = ( manager.updateFile(project, { file, content: newContent }); }} height={ - (file.content.cells[cellId].code.split("\n").length > 10 - ? 10 + (file.content.cells[cellId].code.split("\n").length > 15 + ? 15 : file.content.cells[cellId].code.split("\n").length) * 20 } width="100%" diff --git a/next_app/src/components/terminal.tsx b/next_app/src/components/terminal.tsx index 8e5d221..96d5722 100644 --- a/next_app/src/components/terminal.tsx +++ b/next_app/src/components/terminal.tsx @@ -1,4 +1,3 @@ -import "@xterm/xterm/css/xterm.css" import { Dispatch, SetStateAction, useEffect, useState } from "react" import { Terminal } from "@xterm/xterm"; // import { FitAddon } from "@xterm/addon-fit"; @@ -23,16 +22,15 @@ export default function Term({ prompt, setPrompt, commandOutputs, setCommandOutp const [loaded, setLoaded] = useState(false) const globalState = useGlobalState() const projectManager = useProjectManager() - const project = projectManager.getProject(globalState.activeProject) const [running, setRunning] = useState(false) // const [prompt, setPrompt] = useState("aos> ") const { theme } = useTheme() const [term, setTerm] = useState(new Terminal({ cursorBlink: true, cursorStyle: "bar", - fontSize: 14.5, + fontSize: 14, fontFamily: "DM Mono", - cursorWidth: 50, + cursorWidth: 25, theme: { background: theme == "dark" ? "black" : "white", foreground: theme == "dark" ? "white" : "black", @@ -41,9 +39,9 @@ export default function Term({ prompt, setPrompt, commandOutputs, setCommandOutp selectionForeground: theme == "dark" ? "black" : "white", cursorAccent: theme == "dark" ? "white" : "black", }, - allowTransparency: true, + allowTransparency: false, cols: 150, - rows: 20, + rows: 50, lineHeight: 1, })) const [rl, setRl] = useState(new Readline()) @@ -62,7 +60,7 @@ export default function Term({ prompt, setPrompt, commandOutputs, setCommandOutp term.resize(maxCols, term.buffer.normal.length > maxRows ? maxRows : term.buffer.normal.length) }) rl.print(prompt) - }, [loaded]) + }, [loaded, globalState.activeProject]) useEffect(() => { @@ -70,6 +68,46 @@ export default function Term({ prompt, setPrompt, commandOutputs, setCommandOutp if (p) setTermDiv(p as HTMLDivElement) }, []) + useEffect(() => { + if (loaded) return; + if (!termDiv) return; + + + term.loadAddon(rl); + // term.loadAddon(fit); + term.open(termDiv); + // console.log(history) + // history.forEach((line) => { + // console.log("history", line) + // rl.appendHistory(line) + // term.resize(maxCols, term.buffer.normal.length > maxRows ? maxRows : term.buffer.normal.length) + // }) + // fit.fit(); + + rl.setCheckHandler((text) => { + let trimmedText = text.trimEnd(); + if (trimmedText.endsWith("&&")) { + return false; + } + return true; + }); + + readLine(prompt) + + setLoaded(true) + }, [termDiv]) + + useEffect(() => { + if (!termDiv) return; + if (!loaded) return; + term.clear() + rl.println("\r\x1b[K"); + commandOutputs.forEach((line) => { + rl.println(line); + term.resize(maxCols, term.buffer.normal.length > maxRows ? maxRows : term.buffer.normal.length) + }) + rl.print(prompt) + }, [commandOutputs, prompt]) function readLine(newPrompt: string) { rl.read(newPrompt || prompt).then(processLine); @@ -144,49 +182,10 @@ export default function Term({ prompt, setPrompt, commandOutputs, setCommandOutp setTimeout(() => readLine(result?.Output?.data?.prompt || prompt), 100); } - - useEffect(() => { - if (loaded) return; - if (!termDiv) return; - - - term.loadAddon(rl); - // term.loadAddon(fit); - term.open(termDiv); - // console.log(history) - // history.forEach((line) => { - // console.log("history", line) - // rl.appendHistory(line) - // term.resize(maxCols, term.buffer.normal.length > maxRows ? maxRows : term.buffer.normal.length) - // }) - // fit.fit(); - - rl.setCheckHandler((text) => { - let trimmedText = text.trimEnd(); - if (trimmedText.endsWith("&&")) { - return false; - } - return true; - }); - - readLine(prompt) - - setLoaded(true) - }, [termDiv]) - - useEffect(() => { - if (!termDiv) return; - if (!loaded) return; - term.clear() - rl.println("\r\x1b[K"); - commandOutputs.forEach((line) => { - rl.println(line); - term.resize(maxCols, term.buffer.normal.length > maxRows ? maxRows : term.buffer.normal.length) - }) - rl.print(prompt) - }, [commandOutputs, prompt]) - - + if (!globalState.activeProject) { + return
+ } + const project = projectManager.getProject(globalState.activeProject) return
} \ No newline at end of file diff --git a/next_app/src/pages/_app.tsx b/next_app/src/pages/_app.tsx index 166573f..07ffde7 100644 --- a/next_app/src/pages/_app.tsx +++ b/next_app/src/pages/_app.tsx @@ -1,5 +1,6 @@ import "@/styles/globals.css"; import 'katex/dist/katex.min.css'; +import "@xterm/xterm/css/xterm.css" import type { AppProps } from "next/app"; import { Toaster } from "@/components/ui/toaster"; import { Toaster as Sonner } from "@/components/ui/sonner";