mirror of
https://github.com/damp11113-software/ccIDE.git
synced 2025-04-27 22:48:13 +00:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
2e855b9907 | |||
5200e86f7d | |||
a5ac8c99c8 | |||
4cad5389d3 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -3,4 +3,4 @@ node_modules/
|
||||
package-lock.json
|
||||
dist/
|
||||
dist_debug/
|
||||
ccIDE.wheel
|
||||
ccIDE.wheel
|
||||
|
@ -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")
|
BIN
assets/DOPFoundationLogo.png
Normal file
BIN
assets/DOPFoundationLogo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
assets/DPSoftware2.png
Normal file
BIN
assets/DPSoftware2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
@ -218,7 +218,7 @@
|
||||
"tooltip": "Send message formatted to player chat"
|
||||
},
|
||||
"advanced_peripherals_chatbox_send_toast_formatted_to_player": {
|
||||
"message0": "Chatbox %1 toast send %2 and title %3 to player %4\nPrefix %5 Brackets %6 Bracket color %7 Range %8",
|
||||
"message0": "Chatbox %1 toast send formatted json %2 and title %3 to player %4\nPrefix %5 Brackets %6 Bracket color %7 Range %8",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
@ -227,7 +227,7 @@
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TEXT",
|
||||
"name": "JSON",
|
||||
"check": "String"
|
||||
},
|
||||
{
|
||||
@ -1508,5 +1508,301 @@
|
||||
"nextStatement": null,
|
||||
"colour": 200,
|
||||
"tooltip": "Sets the redstone level output on the given side to the given power level. (0-15)"
|
||||
},
|
||||
|
||||
"advanced_peripherals_mc_beacon_get_level": {
|
||||
"message0": "Get level from beacon %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "BEACON",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the level of the Beacon."
|
||||
},
|
||||
"advanced_peripherals_mc_beacon_get_primary_effect": {
|
||||
"message0": "Get primary effect from beacon %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "BEACON",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "String",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the registry name of the beacon's primary effect."
|
||||
},
|
||||
"advanced_peripherals_mc_beacon_get_secondary_effect": {
|
||||
"message0": "Get secondary secondary effect from beacon %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "BEACON",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "String",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the registry name of the beacon's secondary effect."
|
||||
},
|
||||
|
||||
"advanced_peripherals_mc_note_block_play_note": {
|
||||
"message0": "Play current note sound at note block %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NOTEBLOCK",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": 200,
|
||||
"tooltip": "Plays the Note Block's current note sound."
|
||||
},
|
||||
"advanced_peripherals_mc_note_block_get_note": {
|
||||
"message0": "Get current note from note block %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NOTEBLOCK",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the index for the Note Block's current note. A number from 0 to 24."
|
||||
},
|
||||
"advanced_peripherals_mc_note_block_change_note_by": {
|
||||
"message0": "Change note to %1 at note block %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TO",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NOTEBLOCK",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": 200,
|
||||
"tooltip": "Changes the Note Block's note to the given note. note must be a number from 0 to 24."
|
||||
},
|
||||
"advanced_peripherals_mc_note_block_change_note": {
|
||||
"message0": "Change note by 1 at note block %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NOTEBLOCK",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": 200,
|
||||
"tooltip": "Increments the Note Block's note to the next available note."
|
||||
},
|
||||
|
||||
"advanced_peripherals_botania_flowers_get_mana": {
|
||||
"message0": "Get mana from flower %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FLOWER",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the amount of mana stored in the flower."
|
||||
},
|
||||
"advanced_peripherals_botania_flowers_get_max_mana": {
|
||||
"message0": "Get max mana from flower %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FLOWER",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the maximum amount of mana that the flower can hold."
|
||||
},
|
||||
"advanced_peripherals_botania_flowers_is_floating": {
|
||||
"message0": "Is flower %1 floating",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FLOWER",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns true if the flower is a floating flower.",
|
||||
"inputsInline": true
|
||||
},
|
||||
"advanced_peripherals_botania_flowers_is_on_enchanted_soil": {
|
||||
"message0": "Is flower %1 on enchanted soil",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FLOWER",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns true if the flower is placed on enchanted soil.",
|
||||
"inputsInline": true
|
||||
},
|
||||
"advanced_peripherals_botania_flowers_is_empty": {
|
||||
"message0": "Is flower %1 empty",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FLOWER",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns true if the Flower is empty.",
|
||||
"inputsInline": true
|
||||
},
|
||||
"advanced_peripherals_botania_flowers_is_full": {
|
||||
"message0": "Is flower %1 full",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FLOWER",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns true if the Flower is full.",
|
||||
"inputsInline": true
|
||||
},
|
||||
|
||||
"advanced_peripherals_botania_mana_pool_get_mana": {
|
||||
"message0": "Get mana from pool %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "POOL",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the amount of mana stored in the pool."
|
||||
},
|
||||
"advanced_peripherals_botania_mana_pool_get_max_mana": {
|
||||
"message0": "Get max mana from pool %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "POOL",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the maximum amount of mana that the pool can hold."
|
||||
},
|
||||
"advanced_peripherals_botania_mana_pool_get_mana_needed": {
|
||||
"message0": "Get amount of mana is pool %1 needed to fill full",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "POOL",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns the amount of mana needed to fill the pool. Equivalent to getMaxMana() - getMana().",
|
||||
"inputsInline": true
|
||||
},
|
||||
"advanced_peripherals_botania_mana_pool_is_empty": {
|
||||
"message0": "Is pool %1 empty",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "POOL",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns true if the Mana Pool is empty.",
|
||||
"inputsInline": true
|
||||
},
|
||||
"advanced_peripherals_botania_mana_pool_is_full": {
|
||||
"message0": "Is pool %1 full",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "POOL",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns true if the Mana Pool is full.",
|
||||
"inputsInline": true
|
||||
},
|
||||
"advanced_peripherals_botania_mana_pool_can_charge_item": {
|
||||
"message0": "Can pool %1 change item",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "POOL",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns true if mode of the Mana Pool is set to charge the items on it.",
|
||||
"inputsInline": true
|
||||
},
|
||||
"advanced_peripherals_botania_mana_pool_has_items": {
|
||||
"message0": "Is pool %1 has item",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "POOL",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns true if the Mana Pool has at least one item on it.",
|
||||
"inputsInline": true
|
||||
},
|
||||
"advanced_peripherals_botania_mana_pool_get_items": {
|
||||
"message0": "get items from pool %1 ",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "POOL",
|
||||
"check": "Peripheral"
|
||||
}
|
||||
],
|
||||
"output": "Array",
|
||||
"colour": 200,
|
||||
"tooltip": "Returns a table with the items lying on the Mana Pool."
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -552,4 +552,139 @@ luaGenerator.forBlock['advanced_peripherals_redstone_integrator_set_analog_outpu
|
||||
var integrator = generator.valueToCode(block, 'INTEGRATOR', generator.ORDER_ATOMIC);
|
||||
|
||||
return `${integrator}.setOutput("${side}", ${power})\n`;
|
||||
};
|
||||
|
||||
// Generator for Minecraft: Beacon
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_mc_beacon_get_level'] = function(block, generator) {
|
||||
var beacon = generator.valueToCode(block, 'BEACON', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${beacon}.getLevel()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_mc_beacon_get_primary_effect'] = function(block, generator) {
|
||||
var beacon = generator.valueToCode(block, 'BEACON', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${beacon}.getPrimaryEffect()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_mc_beacon_get_secondary_effect'] = function(block, generator) {
|
||||
var beacon = generator.valueToCode(block, 'BEACON', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${beacon}.getSecondaryEffect()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
// Generator for Minecraft: Note Block
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_mc_note_block_play_note'] = function(block, generator) {
|
||||
var noteblock = generator.valueToCode(block, 'NOTEBLOCK', generator.ORDER_ATOMIC);
|
||||
|
||||
return `${noteblock}.playNote()\n`;
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_mc_note_block_get_note'] = function(block, generator) {
|
||||
var noteblock = generator.valueToCode(block, 'NOTEBLOCK', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${beacon}.getNote()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_mc_note_block_change_note_by'] = function(block, generator) {
|
||||
var to = generator.valueToCode(block, 'TO', generator.ORDER_ATOMIC);
|
||||
var noteblock = generator.valueToCode(block, 'NOTEBLOCK', generator.ORDER_ATOMIC);
|
||||
|
||||
return `${noteblock}.changeNoteBy(${to})\n`;
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_mc_note_block_change_note'] = function(block, generator) {
|
||||
var noteblock = generator.valueToCode(block, 'NOTEBLOCK', generator.ORDER_ATOMIC);
|
||||
|
||||
return `${noteblock}.changeNote()\n`;
|
||||
};
|
||||
|
||||
// Generator for Botania: Flowers
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_flowers_get_mana'] = function(block, generator) {
|
||||
var flower = generator.valueToCode(block, 'FLOWER', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${flower}.getMana()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_flowers_get_max_mana'] = function(block, generator) {
|
||||
var flower = generator.valueToCode(block, 'FLOWER', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${flower}.getMaxMana()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_flowers_is_floating'] = function(block, generator) {
|
||||
var flower = generator.valueToCode(block, 'FLOWER', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${flower}.isFloating()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_flowers_is_on_enchanted_soil'] = function(block, generator) {
|
||||
var flower = generator.valueToCode(block, 'FLOWER', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${flower}.isOnEnchantedSoil()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_flowers_is_empty'] = function(block, generator) {
|
||||
var flower = generator.valueToCode(block, 'FLOWER', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${flower}.isEmpty()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_flowers_is_full'] = function(block, generator) {
|
||||
var flower = generator.valueToCode(block, 'FLOWER', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${flower}.isFull()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
// Generator for Botania: Mana Pool
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_mana_pool_get_mana'] = function(block, generator) {
|
||||
var pool = generator.valueToCode(block, 'POOL', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${pool}.getMana()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_mana_pool_get_max_mana'] = function(block, generator) {
|
||||
var pool = generator.valueToCode(block, 'POOL', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${pool}.getMaxMana()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_mana_pool_get_mana_needed'] = function(block, generator) {
|
||||
var pool = generator.valueToCode(block, 'POOL', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${pool}.getManaNeeded()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_mana_pool_is_empty'] = function(block, generator) {
|
||||
var pool = generator.valueToCode(block, 'POOL', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${pool}.isEmpty()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_mana_pool_is_full'] = function(block, generator) {
|
||||
var pool = generator.valueToCode(block, 'POOL', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${pool}.isFull()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_mana_pool_can_charge_item'] = function(block, generator) {
|
||||
var pool = generator.valueToCode(block, 'POOL', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${pool}.canChargeItem()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_mana_pool_has_items'] = function(block, generator) {
|
||||
var pool = generator.valueToCode(block, 'POOL', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${pool}.hasItems()`, luaGenerator.ORDER_NONE];
|
||||
};
|
||||
|
||||
luaGenerator.forBlock['advanced_peripherals_botania_mana_pool_get_items'] = function(block, generator) {
|
||||
var pool = generator.valueToCode(block, 'POOL', generator.ORDER_ATOMIC);
|
||||
|
||||
return [`${pool}.getItems()`, luaGenerator.ORDER_NONE];
|
||||
};
|
@ -2,7 +2,7 @@
|
||||
"name": "Advanced Peripherals",
|
||||
"author": "DPSoftware Foundation",
|
||||
"description": "Advanced Peripherals is a mod that adds many useful extensions for CC:Tweaked.",
|
||||
"version": "1.0.0",
|
||||
"version": "1.2",
|
||||
"category": "Mod",
|
||||
"keyword": "mod",
|
||||
"license": "GPL-3.0-or-later",
|
||||
|
@ -45,7 +45,7 @@
|
||||
<shadow type="logic_null"></shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="advanced_peripherals_chatbox_send_message_to_player">
|
||||
<block type="advanced_peripherals_chatbox_send_toast_to_player">
|
||||
<value name="TEXT">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">Hello, world!</field>
|
||||
@ -107,6 +107,30 @@
|
||||
<shadow type="logic_null"></shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="advanced_peripherals_chatbox_send_toast_formatted_to_player">
|
||||
<value name="TITLE">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">Hi</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="PLAYER">
|
||||
<shadow type="text">
|
||||
<field name="TEXT">Player</field>
|
||||
</shadow>
|
||||
</value>
|
||||
<value name="PREFIX">
|
||||
<shadow type="logic_null"></shadow>
|
||||
</value>
|
||||
<value name="BRACKET">
|
||||
<shadow type="logic_null"></shadow>
|
||||
</value>
|
||||
<value name="BRACKETCOLOR">
|
||||
<shadow type="logic_null"></shadow>
|
||||
</value>
|
||||
<value name="RANGE">
|
||||
<shadow type="logic_null"></shadow>
|
||||
</value>
|
||||
</block>
|
||||
|
||||
<label text="Energy Detector"></label>
|
||||
<block type="advanced_peripherals_energy_detector_get_transfer_rate"></block>
|
||||
@ -462,5 +486,41 @@
|
||||
<label text="RS Bridge"></label>
|
||||
|
||||
<label text="Colony Integrator"></label>
|
||||
|
||||
<label text="Minecraft: Beacon"></label>
|
||||
<block type="advanced_peripherals_mc_beacon_get_level"></block>
|
||||
<block type="advanced_peripherals_mc_beacon_get_primary_effect"></block>
|
||||
<block type="advanced_peripherals_mc_beacon_get_secondary_effect"></block>
|
||||
|
||||
<label text="Minecraft: Note Block"></label>
|
||||
<block type="advanced_peripherals_mc_note_block_play_note"></block>
|
||||
<block type="advanced_peripherals_mc_note_block_get_note"></block>
|
||||
<block type="advanced_peripherals_mc_note_block_change_note_by">
|
||||
<value name="TO">
|
||||
<shadow type="math_number">
|
||||
<field name="NUM">0</field>
|
||||
</shadow>
|
||||
</value>
|
||||
</block>
|
||||
<block type="advanced_peripherals_mc_note_block_change_note"></block>
|
||||
|
||||
<label text="Botania: Flowers"></label>
|
||||
<block type="advanced_peripherals_botania_flowers_get_mana"></block>
|
||||
<block type="advanced_peripherals_botania_flowers_get_max_mana"></block>
|
||||
<block type="advanced_peripherals_botania_flowers_is_floating"></block>
|
||||
<block type="advanced_peripherals_botania_flowers_is_on_enchanted_soil"></block>
|
||||
<block type="advanced_peripherals_botania_flowers_is_empty"></block>
|
||||
<block type="advanced_peripherals_botania_flowers_is_full"></block>
|
||||
|
||||
<label text="Botania: Mana Pool"></label>
|
||||
<block type="advanced_peripherals_botania_mana_pool_get_mana"></block>
|
||||
<block type="advanced_peripherals_botania_mana_pool_get_max_mana"></block>
|
||||
<block type="advanced_peripherals_botania_mana_pool_get_mana_needed"></block>
|
||||
<block type="advanced_peripherals_botania_mana_pool_is_empty"></block>
|
||||
<block type="advanced_peripherals_botania_mana_pool_is_full"></block>
|
||||
<block type="advanced_peripherals_botania_mana_pool_can_charge_item"></block>
|
||||
<block type="advanced_peripherals_botania_mana_pool_has_items"></block>
|
||||
<block type="advanced_peripherals_botania_mana_pool_get_items"></block>
|
||||
|
||||
</category>
|
||||
</xml>
|
||||
|
91
index.js
91
index.js
@ -6,14 +6,15 @@ const path = require('path');
|
||||
const pino = require('pino')
|
||||
const pretty = require('pino-pretty');
|
||||
const https = require('node:https');
|
||||
const LocalStorage = require('node-localstorage').LocalStorage
|
||||
|
||||
const ipc = ipcMain
|
||||
|
||||
const logger = pino(pretty())
|
||||
const localStorage = new LocalStorage('.');
|
||||
|
||||
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
|
||||
|
||||
var ena_splash = process.env['CCIDE_ENABLE_MAIN_SPLASH'] == 'true';
|
||||
|
||||
var currentprojectpath = null;
|
||||
var currentprojectname = null;
|
||||
var currentprojectopen = false;
|
||||
@ -111,46 +112,51 @@ app.whenReady().then(async () => {
|
||||
logger.error('Error in update check:', error);
|
||||
}
|
||||
|
||||
logger.info("Version in github: " + gitver)
|
||||
logger.info("Current version: " + version)
|
||||
logger.info("Version in github: " + gitver)
|
||||
|
||||
|
||||
const normalizedAppVersion = normalizeVersion(version);
|
||||
const normalizedReleaseVersion = normalizeVersion(gitver);
|
||||
|
||||
if (normalizedAppVersion >= normalizedReleaseVersion) {
|
||||
logger.info("Software is up-to-date.");
|
||||
if (!gitver) {
|
||||
logger.error("Can't check update")
|
||||
} else {
|
||||
logger.info("A new update is available: " + gitver)
|
||||
var is_not_skip_update = localStorage.getItem('skip_update_version') != normalizedAppVersion;
|
||||
var is_ignore = localStorage.getItem('ignore_update');
|
||||
if (is_ignore || is_not_skip_update) {
|
||||
const result = dialog.showMessageBoxSync({
|
||||
type: 'question',
|
||||
buttons: ['Update', 'Ignore', 'Skip'],
|
||||
defaultId: 0,
|
||||
title: 'Update Available',
|
||||
message: `A new version (${gitver}) is available. Do you want to update now?`,
|
||||
detail: 'Click "Update" to go to the release page, "Ignore" to ignore this update, or "Skip" to skip this version.'
|
||||
});
|
||||
switch (result.response) {
|
||||
case 0: // 'Update'
|
||||
(async () => {
|
||||
try {
|
||||
const { default: open } = await import('open');
|
||||
|
||||
await open('https://github.com/DPSoftware-Foundation/ccIDE/releases/latest');
|
||||
console.log('URL opened in default browser');
|
||||
} catch (err) {
|
||||
console.error('Error opening URL:', err);
|
||||
}
|
||||
})();
|
||||
break;
|
||||
case 1: // 'Ignore'
|
||||
localStorage.setItem('ignore_update', true);
|
||||
break;
|
||||
case 2: // 'Skip'
|
||||
localStorage.setItem('skip_update_version', normalizedReleaseVersion);
|
||||
break;
|
||||
const normalizedReleaseVersion = normalizeVersion(gitver);
|
||||
if (normalizedAppVersion >= normalizedReleaseVersion) {
|
||||
logger.info("Software is up-to-date.");
|
||||
} else {
|
||||
logger.info("A new update is available: " + gitver)
|
||||
var is_not_skip_update = localStorage.getItem('skip_update_version') != normalizedAppVersion;
|
||||
var is_ignore = localStorage.getItem('ignore_update');
|
||||
if (is_ignore || is_not_skip_update) {
|
||||
const result = dialog.showMessageBoxSync({
|
||||
type: 'question',
|
||||
buttons: ['Update', 'Ignore', 'Skip'],
|
||||
defaultId: 0,
|
||||
title: 'Update Available',
|
||||
message: `A new version (${gitver}) is available. Do you want to update now?`,
|
||||
detail: 'Click "Update" to go to the release page, "Ignore" to ignore this update, or "Skip" to skip this version.'
|
||||
});
|
||||
switch (result.response) {
|
||||
case 0: // 'Update'
|
||||
(async () => {
|
||||
try {
|
||||
const { default: open } = await import('open');
|
||||
|
||||
await open('https://github.com/DPSoftware-Foundation/ccIDE/releases/latest');
|
||||
console.log('URL opened in default browser');
|
||||
} catch (err) {
|
||||
console.error('Error opening URL:', err);
|
||||
}
|
||||
})();
|
||||
break;
|
||||
case 1: // 'Ignore'
|
||||
localStorage.setItem('ignore_update', true);
|
||||
break;
|
||||
case 2: // 'Skip'
|
||||
localStorage.setItem('skip_update_version', normalizedReleaseVersion);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,7 +174,7 @@ app.whenReady().then(async () => {
|
||||
enableRemoteModule: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
show: false,
|
||||
show: ena_splash,
|
||||
center: true,
|
||||
})
|
||||
|
||||
@ -218,10 +224,13 @@ app.whenReady().then(async () => {
|
||||
});
|
||||
|
||||
ipc.on('update-log-status', (event, status) => {
|
||||
logger.info(status)
|
||||
logger.info(status);
|
||||
if (!appstarted) {
|
||||
splash.webContents.send("change-status", status)
|
||||
}
|
||||
splash.webContents.send("change-status", status);
|
||||
}
|
||||
if (status == "Downloading blocks...") {
|
||||
win.show();
|
||||
}
|
||||
});
|
||||
|
||||
//app.on('activate', () => {
|
||||
|
10639
package-lock.json
generated
10639
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
32
package.json
32
package.json
@ -1,20 +1,31 @@
|
||||
{
|
||||
"name": "ccide",
|
||||
"version": "1.5",
|
||||
"version": "1.6.0",
|
||||
"description": "ComputerCraft mod virtual lua IDE",
|
||||
"main": "index.js",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
"dev": "title ccIDE && electron .",
|
||||
"build": "title building ccIDE && electron-packager . ccIDE --platform=win32 --arch=x64 --icon=assets/ccIDEIcon.ico --out=dist --overwrite && for /d %i in (dist\\ccIDE-*) do copy package.json %i\\",
|
||||
"build_debug": "title building ccIDE (Debug) && electron-packager . ccIDE --platform=win32 --arch=x64 --icon=assets/ccIDEIcon.ico --out=dist_debug --overwrite --debug && for /d %i in (dist_debug\\ccIDE-*) do copy package.json %i\\"
|
||||
"build_debug": "title building ccIDE (Debug) && electron-packager . ccIDE --platform=win32 --arch=x64 --icon=assets/ccIDEIcon.ico --out=dist_debug --overwrite --debug && for /d %i in (dist_debug\\ccIDE-*) do copy package.json %i\\",
|
||||
"new_build": "webpack --config webpack.main.config.js && webpack --config webpack.renderer.config.js",
|
||||
"dist": "electron-builder"
|
||||
},
|
||||
"author": "DPSoftware Foundation",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"electron": "^31.1.0"
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"electron": "^31.7.7",
|
||||
"electron-builder": "^25.1.8",
|
||||
"html-webpack-plugin": "^5.6.3",
|
||||
"terser-webpack-plugin": "^5.3.11",
|
||||
"webpack": "^5.97.1",
|
||||
"webpack-cli": "^6.0.1",
|
||||
"webpack-merge": "^6.0.1",
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blockly/plugin-workspace-search": "^9.0.5",
|
||||
"@blockly/theme-dark": "^7.0.7",
|
||||
"@electron/remote": "^2.1.2",
|
||||
"blockly": "^11.1.1",
|
||||
"bootstrap": "^5.3.3",
|
||||
@ -23,6 +34,19 @@
|
||||
"open": "^10.1.0",
|
||||
"pino": "^9.3.2",
|
||||
"pino-pretty": "^11.2.2",
|
||||
"toastify-js": "^1.12.0",
|
||||
"unzipper": "^0.12.3",
|
||||
"xmldom": "^0.6.0"
|
||||
},
|
||||
"build": {
|
||||
"appId": "dev.dpsoftware.ccide",
|
||||
"productName": "ccIDE",
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"node_modules/**/*"
|
||||
],
|
||||
"directories": {
|
||||
"output": "release"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
30
readme.md
30
readme.md
@ -6,34 +6,18 @@ special thank for [ccblockly](https://github.com/Mirka1405/ccblockly) for idea
|
||||

|
||||
|
||||
# Quick Start
|
||||
1. install nodejs and git
|
||||
2. git clone cd to this project
|
||||
3. Install dependency use `npm install .`
|
||||
1. install nodejs and git.
|
||||
2. git clone and cd to this project .
|
||||
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.
|
||||
5. Done!
|
||||
|
||||
## Install Remote code into computercraft
|
||||
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
|
||||
```
|
||||
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
|
||||
wget https://raw.githubusercontent.com/DPSoftware-Foundation/ccIDE/main/startup.lua
|
||||
```
|
||||
And restart the computer.
|
||||
|
||||
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
|
||||
@ -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
|
||||
|
||||
# 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
|
||||
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")
|
@ -1,11 +1,110 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
const unzipper = require('unzipper');
|
||||
const { DOMParser, XMLSerializer } = require('xmldom');
|
||||
|
||||
|
||||
const peripheralsfolder = path.join(__dirname, "../blocks");
|
||||
|
||||
const fallbackImagePath = path.join(__dirname, '..', 'assets', 'noimagefallback.png'); // Path to fallback image
|
||||
|
||||
if (!fs.existsSync(peripheralsfolder)) {
|
||||
// If it doesn't exist, create it
|
||||
fs.mkdirSync(peripheralsfolder, { recursive: true });
|
||||
console.log('Block Folder created');
|
||||
}
|
||||
|
||||
let progressBar = document.getElementById('progressBarloading');
|
||||
let blocks_url = "https://cdn.damp11113.xyz/file/zip/ccide/blockslastest.zip?dl=1"
|
||||
|
||||
function isBlocksFolderEmpty() {
|
||||
try {
|
||||
const files = fs.readdirSync(peripheralsfolder);
|
||||
return files.length === 0; // Returns true if the folder is empty
|
||||
} catch (err) {
|
||||
console.error('Error reading folder:', err);
|
||||
return false; // Return false or handle error as needed
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadBlocks() {
|
||||
try {
|
||||
progressBar.style.display = 'inline-block';
|
||||
// Create the output directory if it doesn't exist
|
||||
if (!fs.existsSync(peripheralsfolder)) {
|
||||
fs.mkdirSync(peripheralsfolder, { recursive: true });
|
||||
}
|
||||
|
||||
console.log('Downloading blocks...');
|
||||
|
||||
const zipFilePath = path.join(peripheralsfolder, 'blocks.zip');
|
||||
|
||||
// Download the file as a Promise
|
||||
await new Promise((resolve, reject) => {
|
||||
https.get(blocks_url, (response) => {
|
||||
if (response.statusCode !== 200) {
|
||||
reject(new Error(`Download failed with status code ${response.statusCode}`));
|
||||
return;
|
||||
}
|
||||
|
||||
const totalBytes = parseInt(response.headers['content-length'], 10);
|
||||
let downloadedBytes = 0;
|
||||
|
||||
const file = fs.createWriteStream(zipFilePath);
|
||||
|
||||
response.on('data', (chunk) => {
|
||||
downloadedBytes += chunk.length;
|
||||
const percentCompleted = Math.round((downloadedBytes / totalBytes) * 100);
|
||||
progressBar.value = percentCompleted;
|
||||
progressBar.innerText = percentCompleted + '%'; // Fallback text
|
||||
process.stdout.write(`Download progress: ${percentCompleted}%\r`);
|
||||
});
|
||||
|
||||
response.pipe(file);
|
||||
|
||||
file.on('finish', () => {
|
||||
file.close();
|
||||
console.log('\nFile downloaded successfully.');
|
||||
resolve();
|
||||
});
|
||||
|
||||
file.on('error', (error) => {
|
||||
fs.unlinkSync(zipFilePath);
|
||||
reject(error);
|
||||
});
|
||||
}).on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
console.log('Unzipping file...');
|
||||
|
||||
// Unzip the file as a Promise
|
||||
await new Promise((resolve, reject) => {
|
||||
fs.createReadStream(zipFilePath)
|
||||
.pipe(unzipper.Extract({ path: peripheralsfolder }))
|
||||
.on('close', () => {
|
||||
console.log('File unzipped successfully.');
|
||||
fs.unlinkSync(zipFilePath); // Delete the zip file after extraction
|
||||
console.log('Zip file deleted.');
|
||||
|
||||
console.log('Downloaded blocks');
|
||||
progressBar.style.display = 'none';
|
||||
resolve();
|
||||
})
|
||||
.on('error', (error) => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error downloading or unzipping file:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const defineicon = {
|
||||
computer: {
|
||||
@ -76,7 +175,7 @@ function loadperipheral(workspace, currenttoolbar, peripherals, usedlibinproject
|
||||
const newxml = mergeXml(currenttoolbar, toolbar);
|
||||
workspace.updateToolbox(newxml);
|
||||
|
||||
document.getElementById('statusMessage').textContent = `Loaded ${peripherals}`;
|
||||
fireNotify(`Loaded ${peripherals}`, "success")
|
||||
|
||||
// Synchronously require generator.js
|
||||
require(generatorfilePath); // This will execute generator.js if it's a Node.js module
|
||||
@ -86,7 +185,7 @@ function loadperipheral(workspace, currenttoolbar, peripherals, usedlibinproject
|
||||
|
||||
return newxml;
|
||||
} catch (e) {
|
||||
document.getElementById('statusMessage').textContent = `Can't Import ${peripherals}: ${e}`;
|
||||
fireNotify(`Can't Import ${peripherals}: ${e}`, "error")
|
||||
ipc.send("error", `Can't Import ${peripherals}: ${e}`);
|
||||
}
|
||||
} else {
|
||||
@ -125,7 +224,6 @@ function addimageiconinfo(div, src, tiptool) {
|
||||
|
||||
function scanindex() {
|
||||
let foundedpackages = 0;
|
||||
document.getElementById('statusMessage').textContent = "Scanning Packages...";
|
||||
// clear all item in libcontainer
|
||||
document.getElementById('libcontainer').innerHTML = "";
|
||||
|
||||
@ -173,9 +271,15 @@ function scanindex() {
|
||||
|
||||
// Create the title element
|
||||
const title = document.createElement('h3');
|
||||
title.textContent = jsonData.name + ` [v${jsonData.version} by ${jsonData.author}]`;
|
||||
title.textContent = jsonData.name;
|
||||
libraryDetails.appendChild(title);
|
||||
|
||||
// Create the credit and version element
|
||||
const cv = document.createElement('p');
|
||||
cv.classList.add('library-details-cv');
|
||||
cv.textContent = `v${jsonData.version} by ${jsonData.author}`;
|
||||
libraryDetails.appendChild(cv);
|
||||
|
||||
// Create the description element
|
||||
const description = document.createElement('p');
|
||||
description.innerHTML = jsonData.description;
|
||||
@ -230,14 +334,12 @@ function scanindex() {
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('statusMessage').textContent = `Founded ${foundedpackages} Packages`;
|
||||
setTimeout(() => {
|
||||
document.getElementById('statusMessage').textContent = `Ready`;
|
||||
}, 1000);
|
||||
fireNotify(`Founded ${foundedpackages} Packages`, "success")
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
loadperipheral,
|
||||
scanindex
|
||||
scanindex,
|
||||
isBlocksFolderEmpty,
|
||||
downloadBlocks
|
||||
}
|
245
src/ccRemote.js
245
src/ccRemote.js
@ -7,109 +7,258 @@ class CCRemote {
|
||||
host: ip
|
||||
});
|
||||
|
||||
this.clients = new Map(); // Map to track client data (numeric IDs)
|
||||
this.clientIdCounter = 0; // Counter for numeric client IDs
|
||||
|
||||
console.log("Remote server is started");
|
||||
fireNotify(
|
||||
"Remote server started, waiting for clients to connect...",
|
||||
"info"
|
||||
);
|
||||
|
||||
this.socket.on('connection', (ws) => {
|
||||
document.getElementById("navbar-button-computer-disconnect").disabled = false;
|
||||
document.getElementById("navbar-button-computer-run").disabled = false;
|
||||
const clientId = this.clientIdCounter++;
|
||||
this.clients.set(clientId, { ws, isAlive: true, name: `Client-${clientId}`, clientInfo: null });
|
||||
|
||||
document.getElementById('statusMessage').textContent = "Computer connected";
|
||||
setTimeout(() => {
|
||||
document.getElementById('statusMessage').textContent = `Ready`;
|
||||
}, 1000);
|
||||
if (this.clients.size >= 0) {
|
||||
document.getElementById("navbar-button-computer-disconnect").disabled = false;
|
||||
document.getElementById("navbar-button-computer-run").disabled = false;
|
||||
}
|
||||
|
||||
console.log('WebSocket connection established.');
|
||||
console.log(`Client ${clientId} connected.`);
|
||||
fireNotify(`Client ${clientId} connected`, "success");
|
||||
|
||||
// Send "info" command to the client immediately upon connection
|
||||
this.sendCommandToClient(clientId, 'info', true);
|
||||
|
||||
// Set up heartbeat
|
||||
ws.isAlive = true;
|
||||
ws.on('pong', () => {
|
||||
ws.isAlive = true;
|
||||
this.clients.get(clientId).isAlive = true;
|
||||
});
|
||||
|
||||
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', () => {
|
||||
document.getElementById("navbar-button-computer-disconnect").disabled = true;
|
||||
document.getElementById("navbar-button-computer-run").disabled = true;
|
||||
console.log(`Client ${clientId} disconnected.`);
|
||||
this.clients.delete(clientId);
|
||||
fireNotify(`Client ${clientId} disconnected`, "warning");
|
||||
|
||||
document.getElementById('statusMessage').textContent = "Computer disconnected";
|
||||
setTimeout(() => {
|
||||
document.getElementById('statusMessage').textContent = `Ready`;
|
||||
}, 1000);
|
||||
if (this.clients.size === 0) {
|
||||
document.getElementById("navbar-button-computer-disconnect").disabled = true;
|
||||
document.getElementById("navbar-button-computer-run").disabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
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
|
||||
const interval = setInterval(() => {
|
||||
this.socket.clients.forEach((ws) => {
|
||||
if (ws.isAlive === false) {
|
||||
console.log('Client did not respond to ping, terminating connection.');
|
||||
return ws.terminate();
|
||||
for (const [clientId, clientData] of this.clients.entries()) {
|
||||
if (clientData.isAlive === false) {
|
||||
console.log(`Client ${clientId} did not respond to ping, terminating connection.`);
|
||||
fireNotify(`Client ${clientId} did not respond to ping, disconnected`, "warning");
|
||||
clientData.ws.terminate();
|
||||
this.clients.delete(clientId);
|
||||
continue;
|
||||
}
|
||||
|
||||
ws.isAlive = false;
|
||||
ws.ping();
|
||||
});
|
||||
}, 1000);
|
||||
clientData.isAlive = false;
|
||||
clientData.ws.ping();
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
this.socket.on('close', () => {
|
||||
clearInterval(interval);
|
||||
console.log('WebSocket server closed.');
|
||||
fireNotify("WebSocket server closed.", "info");
|
||||
});
|
||||
|
||||
this.socket.on('error', (error) => {
|
||||
console.error('WebSocket server error:', error);
|
||||
fireNotify(`WebSocket server error: ${error.message}`, "error");
|
||||
});
|
||||
}
|
||||
|
||||
isClientConnect() {
|
||||
for (const client of this.socket.clients) {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
return true;
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
sendCommand(command) {
|
||||
this.socket.clients.forEach((client) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(command);
|
||||
}
|
||||
});
|
||||
// Check if any client is connected
|
||||
isClientConnect() {
|
||||
return this.clients.size > 0;
|
||||
}
|
||||
|
||||
sendCode(Code) {
|
||||
this.socket.clients.forEach((client) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send("sendcode");
|
||||
// Send code to all clients
|
||||
sendCode(code) {
|
||||
this.clients.forEach((clientData, clientId) => {
|
||||
if (clientData.ws.readyState === WebSocket.OPEN) {
|
||||
clientData.ws.send("sendcode");
|
||||
setTimeout(() => {
|
||||
client.send(Code);
|
||||
clientData.ws.send(code);
|
||||
}, 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() {
|
||||
this.socket.clients.forEach((client) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send("runcode");
|
||||
this.clients.forEach((clientData, clientId) => {
|
||||
if (clientData.ws.readyState === WebSocket.OPEN) {
|
||||
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() {
|
||||
this.socket.clients.forEach((client) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.close();
|
||||
this.clients.forEach((clientData, clientId) => {
|
||||
if (clientData.ws.readyState === WebSocket.OPEN) {
|
||||
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}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
126
src/codegen.js
126
src/codegen.js
@ -9,6 +9,16 @@ const circles = document.querySelectorAll(".circle");
|
||||
let upcurrentActive = 1;
|
||||
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 = () => {
|
||||
circles.forEach((circle, index) => {
|
||||
if (index < upcurrentActive) {
|
||||
@ -34,7 +44,6 @@ const uploadUpdateProgress = () => {
|
||||
};
|
||||
|
||||
function clientexit() {
|
||||
ccInstance.sendCommand("exit")
|
||||
ccInstance.disconnectAllClients();
|
||||
}
|
||||
|
||||
@ -42,15 +51,17 @@ function gencodeonly() {
|
||||
return luaGenerator.workspaceToCode(workspace);
|
||||
}
|
||||
|
||||
let selectedClientId = null;
|
||||
|
||||
async function gencode() {
|
||||
console.log("Starting generate code")
|
||||
document.getElementById('upload-popup').style.display = 'block';
|
||||
upcurrentActive = 1;
|
||||
uploadError = false;
|
||||
uploadUpdateProgress();
|
||||
// compile/convert code
|
||||
|
||||
console.log("Generating code...")
|
||||
|
||||
// Compile/convert code
|
||||
console.log("Generating code...");
|
||||
upcurrentActive++;
|
||||
uploadUpdateProgress();
|
||||
document.getElementById('upload-status').textContent = "Generating code";
|
||||
@ -61,37 +72,108 @@ async function gencode() {
|
||||
uploadError = true;
|
||||
uploadUpdateProgress();
|
||||
document.getElementById('upload-status').textContent = e;
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
upcurrentActive++;
|
||||
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)
|
||||
const clients = await ccInstance.listClients();
|
||||
document.getElementById('upload-status').innerHTML = "";
|
||||
|
||||
// execute with remote
|
||||
console.log("Executing code in machine...")
|
||||
document.getElementById('upload-status').textContent = "Executing code";
|
||||
upcurrentActive++;
|
||||
uploadUpdateProgress();
|
||||
ccInstance.runCode();
|
||||
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";
|
||||
upcurrentActive++;
|
||||
uploadUpdateProgress();
|
||||
ccInstance.runCodeOnClient(selectedClientId);
|
||||
} catch (error) {
|
||||
console.error("Error waiting for selection:", error);
|
||||
uploadError = true;
|
||||
uploadUpdateProgress();
|
||||
document.getElementById('upload-status').innerHTML = `Error selecting client.`;
|
||||
}
|
||||
} else {
|
||||
console.log("Machine is not connected")
|
||||
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. (Please press SHIFT or CTRL and click)`;
|
||||
return
|
||||
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!
|
||||
console.log("Run code done!")
|
||||
// Done!
|
||||
console.log("Run code 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
|
||||
selectedClientId = null;
|
||||
setTimeout(function() {
|
||||
document.getElementById('upload-popup').style.display = 'none'; // Hide popup after animation completes
|
||||
document.getElementById('upload-popup').style.animation = ''; // Reset animation property
|
||||
|
265
src/index.html
265
src/index.html
@ -3,137 +3,152 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;700&display=swap" rel="stylesheet">
|
||||
<script>
|
||||
const {shell} = require('electron');
|
||||
</script>
|
||||
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
|
||||
<script src="../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation bar -->
|
||||
<nav id="navbar">
|
||||
<!--
|
||||
<button class="navbar-button" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Computer Types" style="background-color: #0087bd;">
|
||||
<svg viewBox="0 0 24 24"><path d="M6 4h12v1h3v2h-3v2h3v2h-3v2h3v2h-3v2h3v2h-3v1H6v-1H3v-2h3v-2H3v-2h3v-2H3V9h3V7H3V5h3V4m5 11v3h1v-3h-1m2 0v3h1v-3h-1m2 0v3h1v-3h-1z" /></svg>
|
||||
</button>
|
||||
-->
|
||||
<button class="navbar-button" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Packages Managers" style="background-color: #0087bd;" onclick="openlibraryselect()">
|
||||
<svg viewBox="0 0 24 24"><path d="M21 16.5c0 .38-.21.71-.53.88l-7.9 4.44c-.16.12-.36.18-.57.18-.21 0-.41-.06-.57-.18l-7.9-4.44A.991.991 0 0 1 3 16.5v-9c0-.38.21-.71.53-.88l7.9-4.44c.16-.12.36-.18.57-.18.21 0 .41.06.57.18l7.9 4.44c.32.17.53.5.53.88v9M12 4.15l-1.89 1.07L16 8.61l1.96-1.11L12 4.15M6.04 7.5 12 10.85l1.96-1.1-5.88-3.4L6.04 7.5M5 15.91l6 3.38v-6.71L5 9.21v6.7m14 0v-6.7l-6 3.37v6.71l6-3.38z" /></svg>
|
||||
</button>
|
||||
<!--
|
||||
<button class="navbar-button" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Preview code" style="background-color: #0087bd; margin-left: auto; position: absolute; right: 115px;">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0 8a5 5 0 0 1-5-5 5 5 0 0 1 5-5 5 5 0 0 1 5 5 5 5 0 0 1-5 5m0-12.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5z" /></svg>
|
||||
</button>
|
||||
-->
|
||||
<button class="navbar-button" id="navbar-button-computer-disconnect" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Disconnect Client" style="background-color: #bd0000; margin-left: auto; position: absolute; right: 65px;" onclick="clientexit()" disabled>
|
||||
<svg viewBox="0 0 24 24"><path d="M19 3H5c-1.11 0-2 .89-2 2v4h2V5h14v14H5v-4H3v4a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2m-8.92 12.58L11.5 17l5-5-5-5-1.42 1.41L12.67 11H3v2h9.67l-2.59 2.58z" /></svg>
|
||||
</button>
|
||||
<button class="navbar-button" id="navbar-button-computer-run" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Run" style="background-color: #10bd00; margin-left: auto;" onclick="gencode()" disabled>
|
||||
<svg viewBox="0 0 24 24"><path d="M8 5.14v14l11-7-11-7z" /></svg>
|
||||
</button>
|
||||
</nav>
|
||||
<!-- <meta charset="utf-8" http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-m0mwdxEgv9nMDDw3gHrhX/xCs/OAiZg5/bQ/6X5SIcA='"/> -->
|
||||
<div class="loading-area">
|
||||
<div id="loadingContent">
|
||||
<div class="loader"></div>
|
||||
<br>
|
||||
<h3>Please wait...</h3>
|
||||
<h5 id="loadingstatus"></h5>
|
||||
<progress id="progressBarloading" value="0" max="100"></progress>
|
||||
|
||||
<!-- Blockly workspace container -->
|
||||
<section id="blocklyContainer">
|
||||
<div id="blocklyDiv"></div>
|
||||
</section>
|
||||
|
||||
<!-- Status bar -->
|
||||
<div id="statusBar">
|
||||
<p id="statusMessage">Initializing...</p>
|
||||
</div>
|
||||
|
||||
<div class="popup" id="upload-popup">
|
||||
<div class="popup-content">
|
||||
<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="progress-container">
|
||||
<div class="progress" id="progress"></div>
|
||||
<div class="circle active">
|
||||
<svg viewBox="0 0 24 24"><path d="M8 3a2 2 0 0 0-2 2v4a2 2 0 0 1-2 2H3v2h1a2 2 0 0 1 2 2v4a2 2 0 0 0 2 2h2v-2H8v-5a2 2 0 0 0-2-2 2 2 0 0 0 2-2V5h2V3m6 0a2 2 0 0 1 2 2v4a2 2 0 0 0 2 2h1v2h-1a2 2 0 0 0-2 2v4a2 2 0 0 1-2 2h-2v-2h2v-5a2 2 0 0 1 2-2 2 2 0 0 1-2-2V5h-2V3h2z" /></svg>
|
||||
</div>
|
||||
<div class="circle">
|
||||
<svg viewBox="0 0 24 24"><path d="m5.5 4.14-1 1.72L15 12 4.5 18.14l1 1.72L19 12 5.5 4.14z" /></svg>
|
||||
</div>
|
||||
<div class="circle">
|
||||
<svg viewBox="0 0 24 24"><path d="M9 16v-6H5l7-7 7 7h-4v6H9m-4 4v-2h14v2H5z" /></svg>
|
||||
</div>
|
||||
<div class="circle">
|
||||
<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>
|
||||
<p id="upload-status"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="popup" id="about-popup">
|
||||
<div class="popup-content">
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" id="aboutCloseBtn"></button>
|
||||
<h2>ccIDE</h2>
|
||||
<p>
|
||||
ccIDE is an integrated development environment designed for coding Lua scripts
|
||||
for ComputerCraft. It provides a user-friendly interface for creating and managing
|
||||
projects, designing custom blocks, and debugging scripts efficiently.
|
||||
</p>
|
||||
<p>
|
||||
Developed by DPSoftware Foundation, ccIDE aims to streamline the development
|
||||
process for ComputerCraft programmers, offering features like block-based coding,
|
||||
real-time collaboration, and seamless integration with ComputerCraft environments.
|
||||
</p>
|
||||
<p>
|
||||
Visit <a href="https://damp11113.xyz/dpsoftware/ccide">ccIDE Website</a> for more information and updates.
|
||||
</p>
|
||||
<div class="license">
|
||||
© 2024 DPSoftware Foundation. Licensed under GPL v3.
|
||||
</div>
|
||||
<style>
|
||||
.license {
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="popup" id="library-popup" style="overflow-y:hidden;">
|
||||
<div class="popup-content p-3" style="max-width: 1280px; position: relative; margin-top: 100px;">
|
||||
<button type="button" class="btn-close" aria-label="Close" id="libraryCloseBtn" style="position: absolute; top: 10px; right: 10px;"></button>
|
||||
<h3>Packages Managers</h3>
|
||||
<div class="library-content">
|
||||
<div id="libcontainer">
|
||||
<div class="library-item overflow-auto library-container" data-libraryfolder="name">
|
||||
<img src="image.jpg" class="libimage" onerror="this.onerror=null;this.src='../assets/noimagefallback.png'; this.alt='No Image Available';">
|
||||
<div class="library-details">
|
||||
<h3>Title [v1.0 by Author]</h3>
|
||||
<p>Library description goes here.</p>
|
||||
<img src="../assets/basic_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Basic Computer">
|
||||
<img src="../assets/adv_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Advanced Computer">
|
||||
<img src="../assets/command_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Command Computer">
|
||||
<img src="../assets/pocket_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Pocket Computer">
|
||||
<img src="../assets/adv_pocket_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Advanced Pocket Computer">
|
||||
<img src="../assets/turtle.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Basic Turtle">
|
||||
<img src="../assets/adv_turtle.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Advanced Turtle">
|
||||
<img src="../assets/peripheral.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Peripheral">
|
||||
<img src="../assets/library.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Library">
|
||||
<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 class="button-container">
|
||||
<button type="button" class="btn btn-success btn-sm" id="packageman-import-btn">Import Packages</button>
|
||||
<button type="button" class="btn btn-warning btn-sm" onclick='scanindex()'>Refetch Packages</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" onclick='shell.openExternal("https://damp11113.xyz/dpsoftware/ccide/library")'>Download Packages</button>
|
||||
<div class="dpclogoload">
|
||||
<img src="../assets/DPSoftware2.png" style="width: 25%;"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="../node_modules/toastify-js/src/toastify.css">
|
||||
<link rel="stylesheet" type="text/css" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="content-area">
|
||||
<!-- Navigation bar -->
|
||||
<nav id="navbar">
|
||||
<!--
|
||||
<button class="navbar-button" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Computer Types" style="background-color: #0087bd;">
|
||||
<svg viewBox="0 0 24 24"><path d="M6 4h12v1h3v2h-3v2h3v2h-3v2h3v2h-3v2h3v2h-3v1H6v-1H3v-2h3v-2H3v-2h3v-2H3V9h3V7H3V5h3V4m5 11v3h1v-3h-1m2 0v3h1v-3h-1m2 0v3h1v-3h-1z" /></svg>
|
||||
</button>
|
||||
-->
|
||||
<button class="navbar-button" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Packages Managers" style="background-color: #0087bd;" onclick="openlibraryselect()">
|
||||
<svg viewBox="0 0 24 24"><path d="M21 16.5c0 .38-.21.71-.53.88l-7.9 4.44c-.16.12-.36.18-.57.18-.21 0-.41-.06-.57-.18l-7.9-4.44A.991.991 0 0 1 3 16.5v-9c0-.38.21-.71.53-.88l7.9-4.44c.16-.12.36-.18.57-.18.21 0 .41.06.57.18l7.9 4.44c.32.17.53.5.53.88v9M12 4.15l-1.89 1.07L16 8.61l1.96-1.11L12 4.15M6.04 7.5 12 10.85l1.96-1.1-5.88-3.4L6.04 7.5M5 15.91l6 3.38v-6.71L5 9.21v6.7m14 0v-6.7l-6 3.37v6.71l6-3.38z" /></svg>
|
||||
</button>
|
||||
<!--
|
||||
<button class="navbar-button" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Preview code" style="background-color: #0087bd; margin-left: auto; position: absolute; right: 115px;">
|
||||
<svg viewBox="0 0 24 24"><path d="M12 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3m0 8a5 5 0 0 1-5-5 5 5 0 0 1 5-5 5 5 0 0 1 5 5 5 5 0 0 1-5 5m0-12.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5z" /></svg>
|
||||
</button>
|
||||
-->
|
||||
<button class="navbar-button" id="navbar-button-computer-disconnect" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Disconnect Client" style="background-color: #bd0000; margin-left: auto; position: absolute; right: 65px;" onclick="clientexit()" disabled>
|
||||
<svg viewBox="0 0 24 24"><path d="M19 3H5c-1.11 0-2 .89-2 2v4h2V5h14v14H5v-4H3v4a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2m-8.92 12.58L11.5 17l5-5-5-5-1.42 1.41L12.67 11H3v2h9.67l-2.59 2.58z" /></svg>
|
||||
</button>
|
||||
<button class="navbar-button" id="navbar-button-computer-run" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Run" style="background-color: #10bd00; margin-left: auto;" onclick="gencode()" disabled>
|
||||
<svg viewBox="0 0 24 24"><path d="M8 5.14v14l11-7-11-7z" /></svg>
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<!-- Blockly workspace container -->
|
||||
<section id="blocklyContainer">
|
||||
<div id="blocklyDiv"></div>
|
||||
</section>
|
||||
|
||||
<div class="popup" id="upload-popup" style="overflow-y:hidden;">
|
||||
<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>
|
||||
<div class="upload-progress-container" style="text-align: center;">
|
||||
<div class="progress-container">
|
||||
<div class="progress" id="progress"></div>
|
||||
<div class="circle active">
|
||||
<svg viewBox="0 0 24 24"><path d="M8 3a2 2 0 0 0-2 2v4a2 2 0 0 1-2 2H3v2h1a2 2 0 0 1 2 2v4a2 2 0 0 0 2 2h2v-2H8v-5a2 2 0 0 0-2-2 2 2 0 0 0 2-2V5h2V3m6 0a2 2 0 0 1 2 2v4a2 2 0 0 0 2 2h1v2h-1a2 2 0 0 0-2 2v4a2 2 0 0 1-2 2h-2v-2h2v-5a2 2 0 0 1 2-2 2 2 0 0 1-2-2V5h-2V3h2z" /></svg>
|
||||
</div>
|
||||
<div class="circle">
|
||||
<svg viewBox="0 0 24 24"><path d="m5.5 4.14-1 1.72L15 12 4.5 18.14l1 1.72L19 12 5.5 4.14z" /></svg>
|
||||
</div>
|
||||
<div class="circle">
|
||||
<svg viewBox="0 0 24 24"><path d="M9 16v-6H5l7-7 7 7h-4v6H9m-4 4v-2h14v2H5z" /></svg>
|
||||
</div>
|
||||
<div class="circle">
|
||||
<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 id="upload-status"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="popup" id="about-popup">
|
||||
<div class="popup-content">
|
||||
<button type="button" class="btn-close float-end" aria-label="Close" id="aboutCloseBtn"></button>
|
||||
<h2>ccIDE</h2>
|
||||
<p>
|
||||
ccIDE is an integrated development environment designed for coding Lua scripts
|
||||
for ComputerCraft. It provides a user-friendly interface for creating and managing
|
||||
projects, designing custom blocks, and debugging scripts efficiently.
|
||||
</p>
|
||||
<p>
|
||||
Developed by DPSoftware Foundation, ccIDE aims to streamline the development
|
||||
process for ComputerCraft programmers, offering features like block-based coding,
|
||||
real-time collaboration, and seamless integration with ComputerCraft environments.
|
||||
</p>
|
||||
<p>
|
||||
Visit <a href="https://damp11113.xyz/dpsoftware/ccide">ccIDE Website</a> for more information and updates.
|
||||
</p>
|
||||
<div class="license">
|
||||
© 2024 DPSoftware Foundation. Licensed under GPL v3.
|
||||
</div>
|
||||
<style>
|
||||
.license {
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="popup" id="library-popup" style="overflow-y:hidden;">
|
||||
<div class="popup-content p-3" style="max-width: 1280px; position: relative; margin-top: 100px;">
|
||||
<button type="button" class="btn-close" aria-label="Close" id="libraryCloseBtn" style="position: absolute; top: 10px; right: 10px;"></button>
|
||||
<h3>Packages Managers</h3>
|
||||
<div class="library-content">
|
||||
<div id="libcontainer">
|
||||
<div class="library-item overflow-auto library-container" data-libraryfolder="name">
|
||||
<img src="image.jpg" class="libimage" onerror="this.onerror=null;this.src='../assets/noimagefallback.png'; this.alt='No Image Available';">
|
||||
<div class="library-details">
|
||||
<h3>Title</h3>
|
||||
<!--Add Author credit-->
|
||||
<h6>v1.0 by Author</h6>
|
||||
<p>Library description goes here.</p>
|
||||
<img src="../assets/basic_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Basic Computer">
|
||||
<img src="../assets/adv_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Advanced Computer">
|
||||
<img src="../assets/command_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Command Computer">
|
||||
<img src="../assets/pocket_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Pocket Computer">
|
||||
<img src="../assets/adv_pocket_computer.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Advanced Pocket Computer">
|
||||
<img src="../assets/turtle.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Basic Turtle">
|
||||
<img src="../assets/adv_turtle.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Advanced Turtle">
|
||||
<img src="../assets/peripheral.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Peripheral">
|
||||
<img src="../assets/library.png" class="libimageicon" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Library">
|
||||
<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 class="button-container">
|
||||
<button type="button" class="btn btn-success btn-sm" id="packageman-import-btn">Import Packages</button>
|
||||
<button type="button" class="btn btn-warning btn-sm" onclick='scanindex()'>Refetch Packages</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" onclick='downloadBlocks()'>Download Packages</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const {shell} = require('electron');
|
||||
</script>
|
||||
<script src="../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="frontend.js"></script>
|
||||
<script src="index.js"></script>
|
||||
<script src="codegen.js"></script>
|
||||
|
159
src/index.js
159
src/index.js
@ -20,14 +20,43 @@ console.originalLog = console.log;
|
||||
console.log = function (...args) {
|
||||
ipc.send("update-log-status", ...args)
|
||||
console.originalLog(...args)
|
||||
document.getElementById("loadingstatus").textContent = args.join(' ');
|
||||
};
|
||||
|
||||
console.log("Importing module...")
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { loadperipheral, scanindex } = require("./blocksmanager");
|
||||
const { loadperipheral, scanindex, isBlocksFolderEmpty, downloadBlocks } = require("./blocksmanager");
|
||||
const Blockly = require('blockly');
|
||||
const { WorkspaceSearch } = require("@blockly/plugin-workspace-search")
|
||||
const Toastify = require('toastify-js');
|
||||
|
||||
function fireNotify(text, status, destination, duration=3000) {
|
||||
let color;
|
||||
if (status == "success") {
|
||||
color = "#a5dc86"
|
||||
} else if (status == "warning") {
|
||||
color = "#f8bb86"
|
||||
} else if (status == "error") {
|
||||
color = "#f27474"
|
||||
} else if (status == "info") {
|
||||
color = "#3fc3ee"
|
||||
}
|
||||
|
||||
Toastify({
|
||||
text: text,
|
||||
duration: duration,
|
||||
destination: destination,
|
||||
newWindow: true,
|
||||
close: true,
|
||||
gravity: "top", // `top` or `bottom`
|
||||
position: "right", // `left`, `center` or `right`
|
||||
stopOnFocus: true, // Prevents dismissing of toast on hover
|
||||
style: {
|
||||
background: color,
|
||||
}
|
||||
}).showToast();
|
||||
}
|
||||
|
||||
let isprojectsaved = false;
|
||||
let isprojectopened = false;
|
||||
@ -39,6 +68,24 @@ Blockly.utils.colour.setHsvSaturation(0.9)
|
||||
let originaltoolbar = fs.readFileSync(path.join(__dirname, "toolbox.xml"), 'utf8');
|
||||
|
||||
try {
|
||||
const theme = Blockly.Theme.defineTheme('themeName', {
|
||||
base: Blockly.Themes.Classic,
|
||||
componentStyles: {
|
||||
workspaceBackgroundColour: "#1e1e1e",
|
||||
toolboxBackgroundColour: "blackBackground",
|
||||
toolboxForegroundColour: "#fff",
|
||||
flyoutBackgroundColour: "#252526",
|
||||
flyoutForegroundColour: "#ccc",
|
||||
flyoutOpacity: 1,
|
||||
scrollbarColour: "#797979",
|
||||
insertionMarkerColour: "#fff",
|
||||
insertionMarkerOpacity: .3,
|
||||
scrollbarOpacity: .4,
|
||||
cursorColour: "#d0d0d0",
|
||||
blackBackground: "#333"
|
||||
}
|
||||
});
|
||||
|
||||
var workspace = Blockly.inject('blocklyDiv', {
|
||||
toolbox: originaltoolbar,
|
||||
trashcan: true,
|
||||
@ -56,7 +103,8 @@ try {
|
||||
minScale: 0.1,
|
||||
scaleSpeed: 1.1,
|
||||
pinch: true
|
||||
}
|
||||
},
|
||||
theme: theme
|
||||
});
|
||||
|
||||
const workspaceSearch = new WorkspaceSearch(workspace);
|
||||
@ -67,27 +115,6 @@ try {
|
||||
ipc.send("erroronstart", `Error on initializing workspace: ${e}`)
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("Importing system library...")
|
||||
const sysmodulejson = fs.readFileSync(path.join(__dirname, "module_block_design.json"), 'utf8');
|
||||
const blocksJson = JSON.parse(sysmodulejson);
|
||||
for (const blockId in blocksJson) {
|
||||
if (blocksJson.hasOwnProperty(blockId)) {
|
||||
Blockly.Blocks[blockId] = {
|
||||
init: function() {
|
||||
this.jsonInit(blocksJson[blockId]);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
require("./module_generator")
|
||||
|
||||
console.log("Scanning library...")
|
||||
scanindex();
|
||||
} catch (e) {
|
||||
ipc.send("erroronstart", `Error on loading block: ${e}`)
|
||||
}
|
||||
|
||||
console.log("Initializing event...")
|
||||
|
||||
ipc.on('export-lua-request', (event) => {
|
||||
@ -98,7 +125,7 @@ ipc.on('export-lua-request', (event) => {
|
||||
// Save workspace
|
||||
ipc.on('save-workspace-request', (event) => {
|
||||
console.log("Saving project...")
|
||||
document.getElementById('statusMessage').textContent = `Saving...`;
|
||||
fireNotify(`Saving...`, "warning")
|
||||
const state = Blockly.serialization.workspaces.save(workspace);
|
||||
const data = {
|
||||
"usedlibrary": usedlibinproject,
|
||||
@ -120,28 +147,21 @@ ipc.on('load-workspace', (event, json) => {
|
||||
const packagefolder = libinproject[i]
|
||||
if (!usedlibinproject.includes(packagefolder)) {
|
||||
try {
|
||||
originaltoolbar = loadperipheral(workspace, originaltoolbar, packagefolder);
|
||||
originaltoolbar = loadperipheral(workspace, originaltoolbar, packagefolder, usedlibinproject);
|
||||
usedlibinproject.push(packagefolder);
|
||||
} catch (e) {
|
||||
document.getElementById('statusMessage').textContent = `Can't Import ${usedlibinproject[i]}: ${e}`;
|
||||
setTimeout(() => {
|
||||
document.getElementById('statusMessage').textContent = `Ready`;
|
||||
}, 1000);
|
||||
fireNotify(`Can't Import ${usedlibinproject[i]}: ${e}`, "error")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
Blockly.serialization.workspaces.load(data.content, workspace);
|
||||
isprojectsaved = true
|
||||
document.getElementById('statusMessage').textContent = `Project Loaded`;
|
||||
}, 100);
|
||||
Blockly.serialization.workspaces.load(data.content, workspace);
|
||||
isprojectsaved = true
|
||||
fireNotify(`Project Loaded`, "success")
|
||||
}
|
||||
} catch (e) {
|
||||
document.getElementById('statusMessage').textContent = `Can't Load Project: ${e}`;
|
||||
fireNotify(`Can't Load Project: ${e}`, "error")
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.getElementById('statusMessage').textContent = `Ready`;
|
||||
}, 1000);
|
||||
})
|
||||
|
||||
ipc.on('workspace-saved', (event, success) => {
|
||||
@ -149,10 +169,7 @@ ipc.on('workspace-saved', (event, success) => {
|
||||
if (!isprojectopened) {
|
||||
isprojectopened = true;
|
||||
}
|
||||
document.getElementById('statusMessage').textContent = `Project Saved`;
|
||||
setTimeout(() => {
|
||||
document.getElementById('statusMessage').textContent = `Ready`;
|
||||
}, 1000);
|
||||
fireNotify(`Project Saved`, "success")
|
||||
});
|
||||
|
||||
ipc.on("open-about", () => {
|
||||
@ -186,19 +203,53 @@ document.getElementById("packageman-import-btn").addEventListener('click', () =>
|
||||
selectedItems.forEach(item => {
|
||||
const packagefolder = item.getAttribute('data-libraryfolder');
|
||||
originaltoolbar = loadperipheral(workspace, originaltoolbar, packagefolder, usedlibinproject);
|
||||
fireNotify(`Loaded ${packagefolder}`, "success")
|
||||
});
|
||||
setTimeout(() => {
|
||||
document.getElementById('statusMessage').textContent = `Ready`;
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// Ensure Blockly container is shown after the workspace is injected
|
||||
console.log("Finished")
|
||||
setTimeout(() => {
|
||||
ipc.send("ready")
|
||||
}, 500);
|
||||
async function InitializingBlock() {
|
||||
try {
|
||||
console.log("Importing system library...");
|
||||
const sysmodulejson = fs.readFileSync(path.join(__dirname, "module_block_design.json"), 'utf8');
|
||||
const blocksJson = JSON.parse(sysmodulejson);
|
||||
|
||||
document.getElementById('statusMessage').textContent = "Computer isn't connect";
|
||||
setTimeout(() => {
|
||||
document.getElementById('statusMessage').textContent = `Ready`;
|
||||
}, 10000);
|
||||
for (const blockId in blocksJson) {
|
||||
if (blocksJson.hasOwnProperty(blockId)) {
|
||||
Blockly.Blocks[blockId] = {
|
||||
init: function() {
|
||||
this.jsonInit(blocksJson[blockId]);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
require("./module_generator");
|
||||
|
||||
console.log("Check library folder...");
|
||||
if (isBlocksFolderEmpty()) {
|
||||
await downloadBlocks();
|
||||
}
|
||||
scanindex();
|
||||
|
||||
|
||||
} catch (e) {
|
||||
ipc.send("erroronstart", `Error on loading block: ${e}`);
|
||||
}
|
||||
|
||||
// Ensure Blockly container is shown after the workspace is injected
|
||||
console.log("Finished")
|
||||
setTimeout(() => {
|
||||
ipc.send("ready")
|
||||
// Hide loading area
|
||||
const loadingArea = document.querySelector('.loading-area');
|
||||
loadingArea.style.opacity = '0';
|
||||
loadingArea.style.visibility = 'hidden';
|
||||
loadingArea.style.display = 'none';
|
||||
|
||||
// Show content area
|
||||
const contentArea = document.querySelector('.content-area');
|
||||
contentArea.style.opacity = '1';
|
||||
contentArea.style.visibility = 'visible';
|
||||
}, 500);
|
||||
}
|
||||
|
||||
InitializingBlock();
|
149
src/styles.css
149
src/styles.css
@ -1,16 +1,90 @@
|
||||
:root {
|
||||
--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 {
|
||||
background-color: #212121;
|
||||
margin: 0;
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
font-family: 'Arial', sans-serif;
|
||||
overflow: hidden; /* Hide scrollbars */
|
||||
}
|
||||
|
||||
.content-area {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.loading-area {
|
||||
color: #cacaca;
|
||||
position: absolute;
|
||||
z-index: 400;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: calc(100% - 22px);
|
||||
}
|
||||
|
||||
#progressBarloading {
|
||||
display: none; /* Initially hidden */
|
||||
}
|
||||
|
||||
#loadingContent {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
font-family: 'Noto Sans', sans-serif;
|
||||
overflow: hidden; /* Hide scrollbars */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 90px;
|
||||
height: 14px;
|
||||
box-shadow: 0 3px 0 #fff;
|
||||
position: relative;
|
||||
clip-path: inset(-40px 0 -5px)
|
||||
}
|
||||
|
||||
.loader:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: auto calc(50% - 17px) 0;
|
||||
height: 50px;
|
||||
--g:no-repeat linear-gradient(#ccc 0 0);
|
||||
background: var(--g),var(--g),var(--g),var(--g);
|
||||
background-size: 16px 14px;
|
||||
animation:
|
||||
l7-1 2s infinite linear,
|
||||
l7-2 2s infinite linear;
|
||||
}
|
||||
@keyframes l7-1 {
|
||||
0%,
|
||||
100% {background-position: 0 -50px,100% -50px}
|
||||
17.5% {background-position: 0 100%,100% -50px,0 -50px,100% -50px}
|
||||
35% {background-position: 0 100%,100% 100% ,0 -50px,100% -50px}
|
||||
52.5% {background-position: 0 100%,100% 100% ,0 calc(100% - 16px),100% -50px}
|
||||
70%,
|
||||
98% {background-position: 0 100%,100% 100% ,0 calc(100% - 16px),100% calc(100% - 16px)}
|
||||
}
|
||||
@keyframes l7-2 {
|
||||
0%,70% {transform:translate(0)}
|
||||
100% {transform:translate(200%)}
|
||||
}
|
||||
|
||||
.dpclogoload {
|
||||
display: flex; /* Enable flexbox */
|
||||
justify-content: center; /* Center horizontally */
|
||||
position: fixed; /* Fixed position */
|
||||
bottom: 30px; /* Adjust as necessary */
|
||||
z-index: 20; /* Ensure it appears above other content */
|
||||
width: 100%; /* Ensure the div takes full width */
|
||||
}
|
||||
|
||||
#navbar {
|
||||
@ -22,7 +96,7 @@ body {
|
||||
}
|
||||
|
||||
.navbar-button {
|
||||
background-color: #2c3e50;
|
||||
background-color: var(--button-bg);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50%; /* Make the button circular */
|
||||
@ -48,7 +122,7 @@ body {
|
||||
}
|
||||
|
||||
.navbar-button:hover {
|
||||
background-color: #0066cc; /* Darken color on hover */
|
||||
background-color: var(--button-hover-bg); /* Darken color on hover */
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
@ -66,20 +140,6 @@ body {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#statusBar {
|
||||
height: 3vh; /* Set the height of the status bar */
|
||||
background-color: #333;
|
||||
color: #ffffff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#statusMessage {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Styles for the upload-popup container */
|
||||
.popup {
|
||||
display: none; /* Hide initially */
|
||||
@ -97,7 +157,8 @@ body {
|
||||
|
||||
/* Styles for the upload-popup content */
|
||||
.popup-content {
|
||||
background-color: #fefefe;
|
||||
background-color: #333;
|
||||
color: #fefefe;
|
||||
margin: 15% auto; /* Center the upload-popup vertically and horizontally */
|
||||
padding: 20px;
|
||||
border: 1px solid #888;
|
||||
@ -151,7 +212,7 @@ body {
|
||||
}
|
||||
|
||||
.progress {
|
||||
background-color: var(--line-border-fill);
|
||||
background-color: var(--progress-bg);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
@ -163,10 +224,9 @@ body {
|
||||
}
|
||||
|
||||
.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 {
|
||||
background-color: #fff;
|
||||
color: #999;
|
||||
@ -186,7 +246,7 @@ body {
|
||||
}
|
||||
|
||||
.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 */
|
||||
}
|
||||
|
||||
@ -211,15 +271,20 @@ body {
|
||||
}
|
||||
.library-details {
|
||||
flex: 1;
|
||||
line-height: 10px;
|
||||
line-height: 5px;
|
||||
}
|
||||
.library-details-cv {
|
||||
color: #7a7a7a;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.library-item {
|
||||
cursor: pointer;
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
border-bottom: 1px solid #7f8c8d; /* Lighter border */
|
||||
}
|
||||
.library-item.selected {
|
||||
background-color: #e9ecef;
|
||||
background-color: #34495e; /* Darker background for selected items */
|
||||
}
|
||||
.library-content {
|
||||
flex: 1;
|
||||
@ -228,11 +293,27 @@ body {
|
||||
max-height: 720px; /* Ensure a max height for scrolling */
|
||||
}
|
||||
.library-item:hover {
|
||||
background-color: #cacaca;
|
||||
background-color: #7f8c8d; /* Hover effect for items */
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
justify-content: center;
|
||||
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")
|
23
webpack.main.config.js
Normal file
23
webpack.main.config.js
Normal file
@ -0,0 +1,23 @@
|
||||
const path = require("path");
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const nodeExternals = require("webpack-node-externals");
|
||||
|
||||
module.exports = {
|
||||
mode: "production",
|
||||
target: "electron-main", // For Electron main process
|
||||
entry: "./src/index.js", // Adjust based on your main entry file
|
||||
output: {
|
||||
filename: "main.js",
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
},
|
||||
externals: [nodeExternals()], // Exclude node_modules
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{ from: "assets", to: "assets" },
|
||||
{ from: "blocks", to: "blocks" },
|
||||
{ from: "src/styles.css", to: "styles.css" },
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
18
webpack.renderer.config.js
Normal file
18
webpack.renderer.config.js
Normal file
@ -0,0 +1,18 @@
|
||||
const path = require("path");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
|
||||
module.exports = {
|
||||
mode: "production",
|
||||
target: "web", // This should target the web environment for the renderer process
|
||||
entry: "./src/frontend.js", // Ensure this points to the correct renderer entry
|
||||
output: {
|
||||
filename: "renderer.js",
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
template: "src/index.html", // Ensure this injects the renderer script
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user