mirror of
https://github.com/damp11113-software/ccIDE.git
synced 2025-04-27 14:38:12 +00:00
update 1.6
support multiple upload to machine and make remote script to one file and support to run on startup
This commit is contained in:
parent
a5ac8c99c8
commit
5200e86f7d
@ -1,50 +0,0 @@
|
|||||||
local ws = assert(http.websocket("ws://127.0.0.1:5133"))
|
|
||||||
print("connected to server")
|
|
||||||
|
|
||||||
local id
|
|
||||||
local isrunning = true
|
|
||||||
|
|
||||||
function exitcheck()
|
|
||||||
while true do
|
|
||||||
local event = os.pullEventRaw("terminate")
|
|
||||||
if event == "terminate" then
|
|
||||||
print("Exiting...")
|
|
||||||
isrunning = false
|
|
||||||
ws.close()
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function main()
|
|
||||||
while isrunning do
|
|
||||||
print("ready")
|
|
||||||
local message, error = ws.receive()
|
|
||||||
if message then
|
|
||||||
print("Received message:", message)
|
|
||||||
if message == "ping" then
|
|
||||||
ws.send("pong")
|
|
||||||
elseif message == "sendcode" then
|
|
||||||
local file = io.open("main.lua", "w")
|
|
||||||
print("waiting for code")
|
|
||||||
local filedata, error = ws.receive()
|
|
||||||
file:write(filedata)
|
|
||||||
file:close()
|
|
||||||
elseif message == "runcode" then
|
|
||||||
id = multishell.launch({}, "main.lua")
|
|
||||||
multishell.setTitle(id, "Code")
|
|
||||||
multishell.setFocus(id)
|
|
||||||
elseif message == "exit" then
|
|
||||||
print("Exiting...")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
print("WebSocket error:", error)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
parallel.waitForAny(exitcheck, main)
|
|
||||||
print("Exited")
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ccide",
|
"name": "ccide",
|
||||||
"version": "1.5",
|
"version": "1.6",
|
||||||
"description": "ComputerCraft mod virtual lua IDE",
|
"description": "ComputerCraft mod virtual lua IDE",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
30
readme.md
30
readme.md
@ -6,34 +6,18 @@ special thank for [ccblockly](https://github.com/Mirka1405/ccblockly) for idea
|
|||||||

|

|
||||||
|
|
||||||
# Quick Start
|
# Quick Start
|
||||||
1. install nodejs and git
|
1. install nodejs and git.
|
||||||
2. git clone cd to this project
|
2. git clone and cd to this project .
|
||||||
3. Install dependency use `npm install .`
|
3. Install dependency use `npm install .`.
|
||||||
4. To run this IDE use `npm run dev` or if you using windows you can use `run.bat` to run it.
|
4. To run this IDE use `npm run dev` or if you using windows you can use `run.bat` to run it.
|
||||||
5. Done!
|
|
||||||
|
|
||||||
## Install Remote code into computercraft
|
## Install Remote code into computercraft
|
||||||
it very simple! to install Remote code.
|
it very simple! to install Remote code.
|
||||||
### Run from URL
|
|
||||||
for advanced computer/pocket/turtle
|
|
||||||
```
|
```
|
||||||
wget run https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/advremote.lua
|
wget https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/startup.lua
|
||||||
```
|
|
||||||
for non advance computer/pocket/turtle
|
|
||||||
```
|
|
||||||
wget run https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/remote.lua
|
|
||||||
```
|
|
||||||
### Download and Run
|
|
||||||
for advanced computer/pocket/turtle
|
|
||||||
```
|
|
||||||
wget https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/advremote.lua advremote.lua
|
|
||||||
advremote
|
|
||||||
```
|
|
||||||
for non advanced computer/pocket/turtle
|
|
||||||
```
|
|
||||||
wget https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/remote.lua remote.lua
|
|
||||||
remote
|
|
||||||
```
|
```
|
||||||
|
And restart the computer.
|
||||||
|
|
||||||
If error "Domain not permitted" try [this solution](https://github.com/cc-tweaked/CC-Tweaked/discussions/626#discussioncomment-241924).
|
If error "Domain not permitted" try [this solution](https://github.com/cc-tweaked/CC-Tweaked/discussions/626#discussioncomment-241924).
|
||||||
|
|
||||||
## official support library, peripheral and module function
|
## official support library, peripheral and module function
|
||||||
@ -150,7 +134,7 @@ https://github.com/user-attachments/assets/195231d4-8fd8-4101-8068-70bc038a5c4f
|
|||||||
https://github.com/user-attachments/assets/8f114cfa-d87c-47d0-a670-a13dc975ab06
|
https://github.com/user-attachments/assets/8f114cfa-d87c-47d0-a670-a13dc975ab06
|
||||||
|
|
||||||
# For adapting in other project
|
# For adapting in other project
|
||||||
This project is based for every block based IDE from DPSoftware Foundation
|
This project is for every block based IDE from DPSoftware Foundation.
|
||||||
|
|
||||||
# License
|
# License
|
||||||
This project is licensed under the [GPL v3 License](https://github.com/DPSoftware-Foundation/ccIDE/blob/main/LICENSE).
|
This project is licensed under the [GPL v3 License](https://github.com/DPSoftware-Foundation/ccIDE/blob/main/LICENSE).
|
||||||
|
48
remote.lua
48
remote.lua
@ -1,48 +0,0 @@
|
|||||||
local ws = assert(http.websocket("ws://127.0.0.1:5133"))
|
|
||||||
print("connected to server")
|
|
||||||
|
|
||||||
local id
|
|
||||||
local isrunning = true
|
|
||||||
|
|
||||||
function exitcheck()
|
|
||||||
while true do
|
|
||||||
local event = os.pullEventRaw("terminate")
|
|
||||||
if event == "terminate" then
|
|
||||||
print("Exiting...")
|
|
||||||
isrunning = false
|
|
||||||
ws.close()
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function main()
|
|
||||||
while isrunning do
|
|
||||||
print("ready")
|
|
||||||
local message, error = ws.receive()
|
|
||||||
if message then
|
|
||||||
print("Received message:", message)
|
|
||||||
if message == "ping" then
|
|
||||||
ws.send("pong")
|
|
||||||
elseif message == "sendcode" then
|
|
||||||
local file = io.open("main.lua", "w")
|
|
||||||
print("waiting for code")
|
|
||||||
local filedata, error = ws.receive()
|
|
||||||
file:write(filedata)
|
|
||||||
file:close()
|
|
||||||
elseif message == "runcode" then
|
|
||||||
shell.run("main")
|
|
||||||
elseif message == "exit" then
|
|
||||||
print("Exiting...")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
print("WebSocket error:", error)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
parallel.waitForAny(exitcheck, main)
|
|
||||||
print("Exited")
|
|
241
src/ccRemote.js
241
src/ccRemote.js
@ -7,105 +7,258 @@ class CCRemote {
|
|||||||
host: ip
|
host: ip
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Remote server is started");
|
this.clients = new Map(); // Map to track client data (numeric IDs)
|
||||||
|
this.clientIdCounter = 0; // Counter for numeric client IDs
|
||||||
|
|
||||||
fireNotify("Computer isn't connect", "warning", "https://github.com/DPSoftware-Foundation/ccIDE#install-remote-code-into-computercraft")
|
console.log("Remote server is started");
|
||||||
|
fireNotify(
|
||||||
|
"Remote server started, waiting for clients to connect...",
|
||||||
|
"info"
|
||||||
|
);
|
||||||
|
|
||||||
this.socket.on('connection', (ws) => {
|
this.socket.on('connection', (ws) => {
|
||||||
|
const clientId = this.clientIdCounter++;
|
||||||
|
this.clients.set(clientId, { ws, isAlive: true, name: `Client-${clientId}`, clientInfo: null });
|
||||||
|
|
||||||
|
if (this.clients.size >= 0) {
|
||||||
document.getElementById("navbar-button-computer-disconnect").disabled = false;
|
document.getElementById("navbar-button-computer-disconnect").disabled = false;
|
||||||
document.getElementById("navbar-button-computer-run").disabled = false;
|
document.getElementById("navbar-button-computer-run").disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
fireNotify("Computer connected", "success")
|
console.log(`Client ${clientId} connected.`);
|
||||||
|
fireNotify(`Client ${clientId} connected`, "success");
|
||||||
|
|
||||||
console.log('WebSocket connection established.');
|
// Send "info" command to the client immediately upon connection
|
||||||
|
this.sendCommandToClient(clientId, 'info', true);
|
||||||
|
|
||||||
// Set up heartbeat
|
|
||||||
ws.isAlive = true;
|
|
||||||
ws.on('pong', () => {
|
ws.on('pong', () => {
|
||||||
ws.isAlive = true;
|
this.clients.get(clientId).isAlive = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('message', (message) => {
|
ws.on('message', (message) => {
|
||||||
console.log(`Received message => ${message}`);
|
console.log(`Message from Client ${clientId}: ${message}`);
|
||||||
|
// Handle info response
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(message);
|
||||||
|
|
||||||
|
if (data.OSVersion && typeof data.OSVersion === 'string' &&
|
||||||
|
data.Name && typeof data.Name === 'string' &&
|
||||||
|
typeof data.ID === 'number' &&
|
||||||
|
typeof data.uptime === 'number' &&
|
||||||
|
typeof data.Type === 'number') {
|
||||||
|
|
||||||
|
// Update clientInfo with the received data
|
||||||
|
this.clients.get(clientId).clientInfo = data;
|
||||||
|
console.log(`Client ${clientId} info updated:`, data);
|
||||||
|
} else {
|
||||||
|
console.log(`Invalid data format from Client ${clientId}:`, data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error parsing message from Client ${clientId}:`, error);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('close', () => {
|
ws.on('close', () => {
|
||||||
|
console.log(`Client ${clientId} disconnected.`);
|
||||||
|
this.clients.delete(clientId);
|
||||||
|
fireNotify(`Client ${clientId} disconnected`, "warning");
|
||||||
|
|
||||||
|
if (this.clients.size === 0) {
|
||||||
document.getElementById("navbar-button-computer-disconnect").disabled = true;
|
document.getElementById("navbar-button-computer-disconnect").disabled = true;
|
||||||
document.getElementById("navbar-button-computer-run").disabled = true;
|
document.getElementById("navbar-button-computer-run").disabled = true;
|
||||||
|
}
|
||||||
fireNotify("Computer disconnected", "warning")
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('error', (error) => {
|
ws.on('error', (error) => {
|
||||||
console.error('Client error:', error);
|
console.error(`Client ${clientId} error:`, error);
|
||||||
|
fireNotify(`Error with Client ${clientId}: ${error.message}`, "error");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ping clients every 30 seconds to check if they are alive
|
// Ping clients every 30 seconds to check if they are alive
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
this.socket.clients.forEach((ws) => {
|
for (const [clientId, clientData] of this.clients.entries()) {
|
||||||
if (ws.isAlive === false) {
|
if (clientData.isAlive === false) {
|
||||||
console.log('Client did not respond to ping, terminating connection.');
|
console.log(`Client ${clientId} did not respond to ping, terminating connection.`);
|
||||||
return ws.terminate();
|
fireNotify(`Client ${clientId} did not respond to ping, disconnected`, "warning");
|
||||||
|
clientData.ws.terminate();
|
||||||
|
this.clients.delete(clientId);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.isAlive = false;
|
clientData.isAlive = false;
|
||||||
ws.ping();
|
clientData.ws.ping();
|
||||||
});
|
}
|
||||||
}, 1000);
|
}, 30000);
|
||||||
|
|
||||||
this.socket.on('close', () => {
|
this.socket.on('close', () => {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
console.log('WebSocket server closed.');
|
console.log('WebSocket server closed.');
|
||||||
|
fireNotify("WebSocket server closed.", "info");
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('error', (error) => {
|
this.socket.on('error', (error) => {
|
||||||
console.error('WebSocket server error:', error);
|
console.error('WebSocket server error:', error);
|
||||||
|
fireNotify(`WebSocket server error: ${error.message}`, "error");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List all connected clients with their IDs, names, and clientInfo
|
||||||
|
// List all connected clients with their IDs, names, and clientInfo
|
||||||
|
async listClients() {
|
||||||
|
const clientList = [];
|
||||||
|
|
||||||
|
// Create an array of promises for fetching client info
|
||||||
|
const infoPromises = [];
|
||||||
|
|
||||||
|
// Loop over each client and trigger 'info' command to get the latest information
|
||||||
|
for (const [clientId, clientData] of this.clients.entries()) {
|
||||||
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
||||||
|
const infoPromise = new Promise((resolve) => {
|
||||||
|
// Set a timeout to handle cases where no response is received
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
resolve({ id: clientId, name: clientData.name, info: null });
|
||||||
|
}, 5000); // Wait 5 seconds for a response
|
||||||
|
|
||||||
|
// Listen for the response from the client
|
||||||
|
const messageHandler = (message) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(message);
|
||||||
|
if (data.OSVersion && typeof data.OSVersion === 'string' &&
|
||||||
|
data.Name && typeof data.Name === 'string' &&
|
||||||
|
typeof data.ID === 'number' &&
|
||||||
|
typeof data.uptime === 'number' &&
|
||||||
|
typeof data.Type === 'number') {
|
||||||
|
|
||||||
|
// Resolve with the valid data
|
||||||
|
resolve({ id: clientId, name: clientData.name, info: data });
|
||||||
|
} else {
|
||||||
|
resolve({ id: clientId, name: clientData.name, info: null });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
resolve({ id: clientId, name: clientData.name, info: null });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the "info" command to the client
|
||||||
|
this.sendCommandToClient(clientId, 'info', true);
|
||||||
|
|
||||||
|
// Attach the handler for this specific client
|
||||||
|
clientData.ws.on('message', messageHandler);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add the promise to the array
|
||||||
|
infoPromises.push(infoPromise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all promises to resolve (all client info to be updated)
|
||||||
|
const resolvedClientInfo = await Promise.all(infoPromises);
|
||||||
|
|
||||||
|
// Construct the final list of clients with updated information
|
||||||
|
for (const clientInfo of resolvedClientInfo) {
|
||||||
|
clientList.push(clientInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any client is connected
|
||||||
isClientConnect() {
|
isClientConnect() {
|
||||||
for (const client of this.socket.clients) {
|
return this.clients.size > 0;
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendCommand(command) {
|
// Send code to all clients
|
||||||
this.socket.clients.forEach((client) => {
|
sendCode(code) {
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
this.clients.forEach((clientData, clientId) => {
|
||||||
client.send(command);
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
||||||
}
|
clientData.ws.send("sendcode");
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
sendCode(Code) {
|
|
||||||
this.socket.clients.forEach((client) => {
|
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
|
||||||
client.send("sendcode");
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
client.send(Code);
|
clientData.ws.send(code);
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send code to a specific client
|
||||||
|
sendCodeToClient(clientId, code) {
|
||||||
|
const client = this.clients.get(clientId);
|
||||||
|
if (!client || client.ws.readyState !== WebSocket.OPEN) {
|
||||||
|
console.error(`Client ${clientId} is not available or not connected.`);
|
||||||
|
fireNotify(`Client ${clientId} is not connected.`, "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.ws.send("sendcode");
|
||||||
|
setTimeout(() => {
|
||||||
|
client.ws.send(code);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run code on all clients
|
||||||
runCode() {
|
runCode() {
|
||||||
this.socket.clients.forEach((client) => {
|
this.clients.forEach((clientData, clientId) => {
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
||||||
client.send("runcode");
|
clientData.ws.send("runcode");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run code on a specific client
|
||||||
|
runCodeOnClient(clientId) {
|
||||||
|
const client = this.clients.get(clientId);
|
||||||
|
if (!client || client.ws.readyState !== WebSocket.OPEN) {
|
||||||
|
console.error(`Client ${clientId} is not available or not connected.`);
|
||||||
|
fireNotify(`Client ${clientId} is not connected.`, "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.ws.send("runcode");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect all clients
|
||||||
disconnectAllClients() {
|
disconnectAllClients() {
|
||||||
this.socket.clients.forEach((client) => {
|
this.clients.forEach((clientData, clientId) => {
|
||||||
if (client.readyState === WebSocket.OPEN) {
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
||||||
client.close();
|
clientData.ws.send("exit");
|
||||||
|
clientData.ws.close();
|
||||||
|
fireNotify(`Client ${clientId} disconnected`, "warning");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.clients.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a command to a specific client
|
||||||
|
sendCommandToClient(clientId, command, expectResponse = false) {
|
||||||
|
const client = this.clients.get(clientId);
|
||||||
|
if (!client || client.ws.readyState !== WebSocket.OPEN) {
|
||||||
|
console.error(`Client ${clientId} is not available or not connected.`);
|
||||||
|
fireNotify(`Client ${clientId} is not connected.`, "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client.ws.send(command);
|
||||||
|
|
||||||
|
if (expectResponse) {
|
||||||
|
client.ws.on('message', (response) => {
|
||||||
|
console.log(`Response from Client ${clientId}: ${response}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a command to all clients
|
||||||
|
sendCommandToAll(command, expectResponse = false) {
|
||||||
|
for (const [clientId, clientData] of this.clients.entries()) {
|
||||||
|
if (clientData.ws.readyState === WebSocket.OPEN) {
|
||||||
|
clientData.ws.send(command);
|
||||||
|
|
||||||
|
if (expectResponse) {
|
||||||
|
clientData.ws.on('message', (response) => {
|
||||||
|
console.log(`Response from Client ${clientId}: ${response}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
122
src/codegen.js
122
src/codegen.js
@ -9,6 +9,16 @@ const circles = document.querySelectorAll(".circle");
|
|||||||
let upcurrentActive = 1;
|
let upcurrentActive = 1;
|
||||||
let uploadError = false; // Flag to track if there's an error
|
let uploadError = false; // Flag to track if there's an error
|
||||||
|
|
||||||
|
const defineicon = {
|
||||||
|
5: path.join(__dirname, '..', 'assets', 'basic_computer.png'),
|
||||||
|
6: path.join(__dirname, '..', 'assets', 'adv_computer.png'),
|
||||||
|
7: path.join(__dirname, '..', 'assets', 'command_computer.png'),
|
||||||
|
2: path.join(__dirname, '..', 'assets', 'pocket_computer.png'),
|
||||||
|
4: path.join(__dirname, '..', 'assets', 'adv_pocket_computer.png'),
|
||||||
|
1: path.join(__dirname, '..', 'assets', 'turtle.png'),
|
||||||
|
3: path.join(__dirname, '..', 'assets', 'adv_turtle.png')
|
||||||
|
}
|
||||||
|
|
||||||
const uploadUpdateProgress = () => {
|
const uploadUpdateProgress = () => {
|
||||||
circles.forEach((circle, index) => {
|
circles.forEach((circle, index) => {
|
||||||
if (index < upcurrentActive) {
|
if (index < upcurrentActive) {
|
||||||
@ -34,7 +44,6 @@ const uploadUpdateProgress = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function clientexit() {
|
function clientexit() {
|
||||||
ccInstance.sendCommand("exit")
|
|
||||||
ccInstance.disconnectAllClients();
|
ccInstance.disconnectAllClients();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,15 +51,17 @@ function gencodeonly() {
|
|||||||
return luaGenerator.workspaceToCode(workspace);
|
return luaGenerator.workspaceToCode(workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let selectedClientId = null;
|
||||||
|
|
||||||
async function gencode() {
|
async function gencode() {
|
||||||
console.log("Starting generate code")
|
console.log("Starting generate code")
|
||||||
document.getElementById('upload-popup').style.display = 'block';
|
document.getElementById('upload-popup').style.display = 'block';
|
||||||
upcurrentActive = 1;
|
upcurrentActive = 1;
|
||||||
uploadError = false;
|
uploadError = false;
|
||||||
uploadUpdateProgress();
|
uploadUpdateProgress();
|
||||||
// compile/convert code
|
|
||||||
|
|
||||||
console.log("Generating code...")
|
// Compile/convert code
|
||||||
|
console.log("Generating code...");
|
||||||
upcurrentActive++;
|
upcurrentActive++;
|
||||||
uploadUpdateProgress();
|
uploadUpdateProgress();
|
||||||
document.getElementById('upload-status').textContent = "Generating code";
|
document.getElementById('upload-status').textContent = "Generating code";
|
||||||
@ -61,37 +72,108 @@ async function gencode() {
|
|||||||
uploadError = true;
|
uploadError = true;
|
||||||
uploadUpdateProgress();
|
uploadUpdateProgress();
|
||||||
document.getElementById('upload-status').textContent = e;
|
document.getElementById('upload-status').textContent = e;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
upcurrentActive++;
|
upcurrentActive++;
|
||||||
uploadUpdateProgress();
|
uploadUpdateProgress();
|
||||||
if (ccInstance.isClientConnect()) {
|
|
||||||
// upload to computercraft with remote
|
|
||||||
console.log("Uploading code to machine...")
|
|
||||||
document.getElementById('upload-status').textContent = "Uploading code to machine";
|
|
||||||
ccInstance.sendCode(code);
|
|
||||||
await delay(500)
|
|
||||||
|
|
||||||
// execute with remote
|
if (ccInstance.isClientConnect()) {
|
||||||
console.log("Executing code in machine...")
|
const clients = await ccInstance.listClients();
|
||||||
|
document.getElementById('upload-status').innerHTML = "";
|
||||||
|
|
||||||
|
const ClientLists = document.createElement('div');
|
||||||
|
ClientLists.classList.add("library-content");
|
||||||
|
|
||||||
|
clients.forEach(client => {
|
||||||
|
console.log(`Info:`, client.info);
|
||||||
|
|
||||||
|
const ClientItem = document.createElement('div');
|
||||||
|
ClientItem.classList.add('library-item', 'overflow-auto', 'library-container');
|
||||||
|
ClientItem.setAttribute('data-clientid', client.id);
|
||||||
|
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.classList.add('libimage');
|
||||||
|
img.src = defineicon[client.info.Type];
|
||||||
|
ClientItem.appendChild(img);
|
||||||
|
|
||||||
|
const ClientDetails = document.createElement('div');
|
||||||
|
ClientDetails.classList.add('library-details');
|
||||||
|
|
||||||
|
const title = document.createElement('h3');
|
||||||
|
title.textContent = client.info.Name;
|
||||||
|
ClientDetails.appendChild(title);
|
||||||
|
|
||||||
|
const description = document.createElement('p');
|
||||||
|
description.innerHTML = `OS: ${client.info.OSVersion} | ID: ${client.info.ID} | Uptime: ${client.info.uptime}s`;
|
||||||
|
ClientDetails.appendChild(description);
|
||||||
|
|
||||||
|
ClientItem.appendChild(ClientDetails);
|
||||||
|
|
||||||
|
// Add event listener for user selection
|
||||||
|
ClientItem.addEventListener('click', () => {
|
||||||
|
selectedClientId = client.id; // Correctly store the client ID
|
||||||
|
ClientItem.classList.add('selected'); // Optional: Style selected item
|
||||||
|
});
|
||||||
|
|
||||||
|
ClientLists.appendChild(ClientItem);
|
||||||
|
});
|
||||||
|
|
||||||
|
const title = document.createElement("h3");
|
||||||
|
title.textContent = "Upload to machine";
|
||||||
|
document.getElementById('upload-status').appendChild(title);
|
||||||
|
|
||||||
|
document.getElementById('upload-status').appendChild(ClientLists);
|
||||||
|
|
||||||
|
// Wait for user selection
|
||||||
|
const waitForSelection = () => new Promise((resolve, reject) => {
|
||||||
|
const checkSelection = setInterval(() => {
|
||||||
|
if (selectedClientId !== null) {
|
||||||
|
clearInterval(checkSelection);
|
||||||
|
resolve(selectedClientId);
|
||||||
|
}
|
||||||
|
}, 100); // Check every 100ms if a client is selected
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait until the user selects a client
|
||||||
|
try {
|
||||||
|
const selectedClientId = await waitForSelection();
|
||||||
|
console.log(`Selected client: ${selectedClientId}`);
|
||||||
|
|
||||||
|
document.getElementById('upload-status').innerHTML = "";
|
||||||
|
|
||||||
|
// Now proceed with uploading code to the selected client
|
||||||
|
console.log("Uploading code to machine...");
|
||||||
|
document.getElementById('upload-status').textContent = "Uploading code to machine";
|
||||||
|
ccInstance.sendCodeToClient(selectedClientId, code);
|
||||||
|
await delay(500);
|
||||||
|
|
||||||
|
// Execute with remote
|
||||||
|
console.log("Executing code in machine...");
|
||||||
document.getElementById('upload-status').textContent = "Executing code";
|
document.getElementById('upload-status').textContent = "Executing code";
|
||||||
upcurrentActive++;
|
upcurrentActive++;
|
||||||
uploadUpdateProgress();
|
uploadUpdateProgress();
|
||||||
ccInstance.runCode();
|
ccInstance.runCodeOnClient(selectedClientId);
|
||||||
} else {
|
} catch (error) {
|
||||||
console.log("Machine is not connected")
|
console.error("Error waiting for selection:", error);
|
||||||
uploadError = true;
|
uploadError = true;
|
||||||
uploadUpdateProgress();
|
uploadUpdateProgress();
|
||||||
document.getElementById('upload-status').innerHTML = `Please Connect Computer to IDE.\nInstruction: <a href="https://github.com/DPSoftware-Foundation/ccIDE#install-remote-code-into-computercraft">Install Remote code into computercraft</a> in github. (Please press SHIFT or CTRL and click)`;
|
document.getElementById('upload-status').innerHTML = `Error selecting client.`;
|
||||||
return
|
}
|
||||||
|
} else {
|
||||||
|
console.log("Machine is not connected");
|
||||||
|
uploadError = true;
|
||||||
|
uploadUpdateProgress();
|
||||||
|
document.getElementById('upload-status').innerHTML = `Please Connect Computer to IDE.\nInstruction: <a href="https://github.com/DPSoftware-Foundation/ccIDE#install-remote-code-into-computercraft">Install Remote code into computercraft</a> in github.`;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// done!
|
// Done!
|
||||||
console.log("Run code done!")
|
console.log("Run code done!");
|
||||||
document.getElementById('upload-status').textContent = "Done!";
|
document.getElementById('upload-status').textContent = "Done!";
|
||||||
await delay(1000)
|
await delay(1000);
|
||||||
document.getElementById('upload-popup').style.animation = 'fadeOut 0.3s ease'; // Apply fade-out animation
|
document.getElementById('upload-popup').style.animation = 'fadeOut 0.3s ease'; // Apply fade-out animation
|
||||||
|
selectedClientId = null;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
document.getElementById('upload-popup').style.display = 'none'; // Hide popup after animation completes
|
document.getElementById('upload-popup').style.display = 'none'; // Hide popup after animation completes
|
||||||
document.getElementById('upload-popup').style.animation = ''; // Reset animation property
|
document.getElementById('upload-popup').style.animation = ''; // Reset animation property
|
||||||
|
@ -54,8 +54,8 @@
|
|||||||
<div id="blocklyDiv"></div>
|
<div id="blocklyDiv"></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="popup" id="upload-popup">
|
<div class="popup" id="upload-popup" style="overflow-y:hidden;">
|
||||||
<div class="popup-content">
|
<div class="popup-content p-3" style="max-width: 720px; position: relative; margin-top: 100px;">
|
||||||
<button type="button" class="btn-close float-end" aria-label="Close" id="uploadCloseBtn"></button>
|
<button type="button" class="btn-close float-end" aria-label="Close" id="uploadCloseBtn"></button>
|
||||||
<div class="upload-progress-container" style="text-align: center;">
|
<div class="upload-progress-container" style="text-align: center;">
|
||||||
<div class="progress-container">
|
<div class="progress-container">
|
||||||
@ -73,7 +73,7 @@
|
|||||||
<svg viewBox="0 0 24 24"><path d="m20 22-3.86-1.55c.7-1.53 1.2-3.11 1.51-4.72L20 22M7.86 20.45 4 22l2.35-6.27c.31 1.61.81 3.19 1.51 4.72M12 2s5 2 5 10c0 3.1-.75 5.75-1.67 7.83A2 2 0 0 1 13.5 21h-3a2 2 0 0 1-1.83-1.17C7.76 17.75 7 15.1 7 12c0-8 5-10 5-10m0 10c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z" /></svg>
|
<svg viewBox="0 0 24 24"><path d="m20 22-3.86-1.55c.7-1.53 1.2-3.11 1.51-4.72L20 22M7.86 20.45 4 22l2.35-6.27c.31 1.61.81 3.19 1.51 4.72M12 2s5 2 5 10c0 3.1-.75 5.75-1.67 7.83A2 2 0 0 1 13.5 21h-3a2 2 0 0 1-1.83-1.17C7.76 17.75 7 15.1 7 12c0-8 5-10 5-10m0 10c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z" /></svg>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p id="upload-status"></p>
|
<div id="upload-status"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -132,7 +132,6 @@
|
|||||||
<img src="../assets/network-require.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Network Require">
|
<img src="../assets/network-require.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Network Require">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
:root {
|
:root {
|
||||||
--line-border-fill: #3498db;
|
--line-border-fill: #3498db;
|
||||||
--line-border-empty: #e0e0e0;
|
--line-border-empty: #7f8c8d; /* Lighter gray for dark mode */
|
||||||
|
--background-color: #121212; /* Dark background for body */
|
||||||
|
--text-color: #e0e0e0; /* Lighter text color */
|
||||||
|
--button-bg: #333; /* Dark button background */
|
||||||
|
--button-hover-bg: #0066cc; /* Button hover color */
|
||||||
|
--progress-bg: #3498db; /* Progress bar fill color */
|
||||||
|
--error-color: #e74c3c; /* Error state color */
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background-color: #212121;
|
background-color: var(--background-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
overflow: hidden; /* Hide scrollbars */
|
overflow: hidden; /* Hide scrollbars */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +96,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navbar-button {
|
.navbar-button {
|
||||||
background-color: #2c3e50;
|
background-color: var(--button-bg);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 50%; /* Make the button circular */
|
border-radius: 50%; /* Make the button circular */
|
||||||
@ -114,7 +122,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.navbar-button:hover {
|
.navbar-button:hover {
|
||||||
background-color: #0066cc; /* Darken color on hover */
|
background-color: var(--button-hover-bg); /* Darken color on hover */
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +157,8 @@ body {
|
|||||||
|
|
||||||
/* Styles for the upload-popup content */
|
/* Styles for the upload-popup content */
|
||||||
.popup-content {
|
.popup-content {
|
||||||
background-color: #fefefe;
|
background-color: #333;
|
||||||
|
color: #fefefe;
|
||||||
margin: 15% auto; /* Center the upload-popup vertically and horizontally */
|
margin: 15% auto; /* Center the upload-popup vertically and horizontally */
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border: 1px solid #888;
|
border: 1px solid #888;
|
||||||
@ -203,7 +212,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
background-color: var(--line-border-fill);
|
background-color: var(--progress-bg);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -215,10 +224,9 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.progress.error {
|
.progress.error {
|
||||||
background-color: red; /* Set to red color for error state */
|
background-color: var(--error-color); /* Set to red color for error state */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.circle {
|
.circle {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
color: #999;
|
color: #999;
|
||||||
@ -238,7 +246,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.circle.error {
|
.circle.error {
|
||||||
border-color: red; /* Optionally, change border color to red */
|
border-color: var(--error-color); /* Optionally, change border color to red */
|
||||||
color: white; /* Optionally, adjust text color for visibility */
|
color: white; /* Optionally, adjust text color for visibility */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,10 +276,10 @@ body {
|
|||||||
.library-item {
|
.library-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-bottom: 1px solid #e9ecef;
|
border-bottom: 1px solid #7f8c8d; /* Lighter border */
|
||||||
}
|
}
|
||||||
.library-item.selected {
|
.library-item.selected {
|
||||||
background-color: #e9ecef;
|
background-color: #34495e; /* Darker background for selected items */
|
||||||
}
|
}
|
||||||
.library-content {
|
.library-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
@ -280,11 +288,27 @@ body {
|
|||||||
max-height: 720px; /* Ensure a max height for scrolling */
|
max-height: 720px; /* Ensure a max height for scrolling */
|
||||||
}
|
}
|
||||||
.library-item:hover {
|
.library-item:hover {
|
||||||
background-color: #cacaca;
|
background-color: #7f8c8d; /* Hover effect for items */
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container {
|
.button-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: center;
|
||||||
gap: 10px;
|
align-items: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.btn-invisible {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swipe-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pointer-pointer {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
117
startup.lua
Normal file
117
startup.lua
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
print("checking computer type...")
|
||||||
|
local machineType = 0
|
||||||
|
local isAdvanced = false
|
||||||
|
local isPocket = false
|
||||||
|
local isTurtle = false
|
||||||
|
local isCommand = false
|
||||||
|
|
||||||
|
-- Check if advanced (multishell exists in advanced computers and advanced pocket computers)
|
||||||
|
if multishell then
|
||||||
|
isAdvanced = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if Pocket Computer (API specific to Pocket Computers)
|
||||||
|
if pocket then
|
||||||
|
isPocket = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check if Turtle (turtle API is available for turtles)
|
||||||
|
if turtle then
|
||||||
|
isTurtle = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if commands then
|
||||||
|
isCommand = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Determine machine type
|
||||||
|
if isTurtle then
|
||||||
|
if isAdvanced then
|
||||||
|
machineType = 3 -- Advanced Turtle
|
||||||
|
else
|
||||||
|
machineType = 1 -- Standard Turtle
|
||||||
|
end
|
||||||
|
elseif isPocket then
|
||||||
|
if isAdvanced then
|
||||||
|
machineType = 4 -- Advanced Pocket Computer
|
||||||
|
else
|
||||||
|
machineType = 2 -- Standard Pocket Computer
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if isAdvanced then
|
||||||
|
if isCommand then
|
||||||
|
machineType = 7 -- Command Computer
|
||||||
|
else
|
||||||
|
machineType = 6 -- Advanced Computer
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
machineType = 5 -- Standard Computer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Machine Type: " .. machineType)
|
||||||
|
print("connecting to IDE...")
|
||||||
|
local ws = assert(http.websocket("ws://127.0.0.1:5133"))
|
||||||
|
print("connected to server")
|
||||||
|
|
||||||
|
local id
|
||||||
|
local isrunning = true
|
||||||
|
|
||||||
|
function exitcheck()
|
||||||
|
while true do
|
||||||
|
local event = os.pullEventRaw("terminate")
|
||||||
|
if event == "terminate" then
|
||||||
|
print("Exiting...")
|
||||||
|
isrunning = false
|
||||||
|
ws.close()
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function main()
|
||||||
|
while isrunning do
|
||||||
|
print("ready")
|
||||||
|
local message, error = ws.receive()
|
||||||
|
if message then
|
||||||
|
print("Received message:", message)
|
||||||
|
if message == "ping" then
|
||||||
|
ws.send("pong")
|
||||||
|
elseif message == "info" then
|
||||||
|
info = {
|
||||||
|
OSVersion = os.version(),
|
||||||
|
ID = os.getComputerID(),
|
||||||
|
Name = os.getComputerLabel() or "No Name",
|
||||||
|
Type = machineType,
|
||||||
|
uptime = os.clock()
|
||||||
|
}
|
||||||
|
ws.send(textutils.serialiseJSON(info))
|
||||||
|
elseif message == "sendcode" then
|
||||||
|
local file = io.open("main.lua", "w")
|
||||||
|
print("waiting for code")
|
||||||
|
local filedata, error = ws.receive()
|
||||||
|
file:write(filedata)
|
||||||
|
file:close()
|
||||||
|
elseif message == "runcode" then
|
||||||
|
if isAdvanced then
|
||||||
|
id = multishell.launch({}, "main.lua")
|
||||||
|
multishell.setTitle(id, "Code")
|
||||||
|
multishell.setFocus(id)
|
||||||
|
else
|
||||||
|
shell.run("main")
|
||||||
|
end
|
||||||
|
elseif message == "exit" then
|
||||||
|
print("Exiting...")
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
print("WebSocket error:", error)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
parallel.waitForAny(exitcheck, main)
|
||||||
|
print("Exited")
|
Loading…
x
Reference in New Issue
Block a user