├── resources ├── android-project │ ├── settings.gradle │ ├── app │ │ ├── jni │ │ │ ├── Android.mk │ │ │ ├── src │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── Android.mk │ │ │ ├── Application.mk │ │ │ └── CMakeLists.txt │ │ ├── src │ │ │ └── main │ │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values │ │ │ │ │ ├── styles.xml │ │ │ │ │ ├── colors.xml │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── themes.xml │ │ │ │ ├── drawable │ │ │ │ │ ├── ic_baseline_arrow_back_24.xml │ │ │ │ │ ├── ic_baseline_arrow_forward_24.xml │ │ │ │ │ ├── ic_baseline_close_24.xml │ │ │ │ │ ├── ic_baseline_keyboard_tab_24.xml │ │ │ │ │ ├── ic_baseline_remove_circle_outline_24.xml │ │ │ │ │ ├── ic_baseline_refresh_24.xml │ │ │ │ │ ├── ic_baseline_power_settings_new_24.xml │ │ │ │ │ ├── ic_baseline_content_paste_24.xml │ │ │ │ │ └── ic_baseline_keyboard_24.xml │ │ │ │ └── values-night │ │ │ │ │ └── themes.xml │ │ │ │ ├── java │ │ │ │ └── org │ │ │ │ │ └── libsdl │ │ │ │ │ └── app │ │ │ │ │ ├── HIDDevice.java │ │ │ │ │ └── SDL.java │ │ │ │ └── AndroidManifest.xml │ │ ├── proguard-rules.pro │ │ ├── build.gradle │ │ └── AndroidManifest.xml │ ├── .idea │ │ ├── .gitignore │ │ ├── compiler.xml │ │ ├── misc.xml │ │ ├── modules │ │ │ ├── craftos2-android.iml │ │ │ └── app │ │ │ │ └── craftos2-android.app.iml │ │ └── jarRepositories.xml │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ ├── build.gradle │ ├── gradle.properties │ ├── gradlew.bat │ └── gradlew ├── image1.png ├── CraftOS-PC.ico ├── linux-icons.zip ├── CCT-Test-Bootstrap.lua ├── .install ├── Info.plist ├── packStandaloneROM.js ├── CraftOS-PC.exe.manifest ├── appdata.xml ├── BenchmarkRenderers.lua └── CCT-Tests.patch ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .gitattributes ├── .gitmodules ├── .vscode ├── tasks.json ├── launch.json └── settings.json ├── src ├── platform │ ├── resource.h │ ├── emscripten.cpp │ ├── CraftOS-PC 2.rc │ └── android.cpp ├── apis.hpp ├── platform.cpp ├── apis │ ├── handles │ │ ├── fs_handle.hpp │ │ └── http_handle.hpp │ ├── peripheral.cpp │ ├── mounter.cpp │ └── periphemu.cpp ├── terminal │ ├── TRoRTerminal.hpp │ ├── HardwareSDLTerminal.hpp │ ├── CLITerminal.hpp │ ├── RawTerminal.hpp │ └── SDLTerminal.hpp ├── mem │ ├── cluster.hpp │ └── cluster.cpp ├── peripheral │ ├── debug_adapter.hpp │ ├── computer.hpp │ ├── energy.hpp │ ├── tank.hpp │ ├── chest.hpp │ ├── energy.cpp │ ├── drive.hpp │ ├── modem.hpp │ ├── speaker.hpp │ ├── monitor.hpp │ ├── debugger.hpp │ ├── chest.cpp │ ├── computer_p.cpp │ ├── debug_adapter.cpp │ └── tank.cpp ├── main.hpp ├── platform.hpp ├── termsupport.hpp ├── runtime.hpp └── gif.hpp ├── SECURITY.md ├── .gitignore ├── examples ├── plugin_base.cpp ├── ccemux.vcxproj.filters ├── example_peripheral.cpp └── peripheral_base.cpp ├── api ├── generic_peripheral │ ├── energy_storage.hpp │ ├── fluid_storage.hpp │ └── inventory.hpp ├── lib.hpp ├── configuration.hpp ├── peripheral.hpp └── FileEntry.hpp ├── vcpkg.json ├── m4 ├── find_cxx11.m4 └── find_cxx.m4 └── LICENSE /resources/android-project/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /resources/android-project/app/jni/Android.mk: -------------------------------------------------------------------------------- 1 | include $(call all-subdir-makefiles) 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: MCJack123 4 | -------------------------------------------------------------------------------- /resources/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MCJack123/craftos2/HEAD/resources/image1.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | src/font.c linguist-generated 2 | src/peripheral/speaker_sounds.cpp linguist-generated -------------------------------------------------------------------------------- /resources/CraftOS-PC.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MCJack123/craftos2/HEAD/resources/CraftOS-PC.ico -------------------------------------------------------------------------------- /resources/android-project/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /resources/linux-icons.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MCJack123/craftos2/HEAD/resources/linux-icons.zip -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "craftos2-lua"] 2 | path = craftos2-lua 3 | url = https://github.com/MCJack123/craftos2-lua 4 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MCJack123/craftos2/HEAD/resources/android-project/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MCJack123/craftos2/HEAD/resources/android-project/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MCJack123/craftos2/HEAD/resources/android-project/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MCJack123/craftos2/HEAD/resources/android-project/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MCJack123/craftos2/HEAD/resources/android-project/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /resources/android-project/.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /resources/android-project/app/jni/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | project(MY_APP) 4 | 5 | find_library(SDL2 SDL2) 6 | 7 | add_library(main SHARED) 8 | 9 | target_sources(main PRIVATE YourSourceHere.c) 10 | 11 | target_link_libraries(main SDL2) 12 | 13 | 14 | -------------------------------------------------------------------------------- /resources/android-project/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Apr 25 19:21:23 EDT 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip 7 | -------------------------------------------------------------------------------- /resources/android-project/app/jni/Application.mk: -------------------------------------------------------------------------------- 1 | 2 | # Uncomment this if you're using STL in your project 3 | # You can find more information here: 4 | # https://developer.android.com/ndk/guides/cpp-support 5 | APP_STL := c++_shared 6 | 7 | APP_ABI := armeabi-v7a arm64-v8a x86 x86_64 8 | 9 | # Min runtime API level 10 | APP_PLATFORM=android-16 11 | -------------------------------------------------------------------------------- /resources/android-project/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_arrow_forward_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build", 8 | "type": "shell", 9 | "command": "make", 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | } 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_close_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_keyboard_tab_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_remove_circle_outline_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/android-project/app/jni/src/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := main 6 | 7 | SDL_PATH := ../SDL 8 | 9 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include 10 | 11 | # Add your application source files here... 12 | LOCAL_SRC_FILES := YourSourceHere.c 13 | 14 | LOCAL_SHARED_LIBRARIES := SDL2 SDL2_mixer PocoFoundation PocoNet PocoNetSSL ssl crypto PocoJSON PocoXML 15 | 16 | LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog 17 | 18 | include $(BUILD_SHARED_LIBRARY) 19 | -------------------------------------------------------------------------------- /src/platform/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by CraftOS-PC 2.rc 4 | // 5 | #define IDR_RT_MANIFEST1 24 6 | #define IDI_ICON1 104 7 | 8 | // Next default values for new objects 9 | // 10 | #ifdef APSTUDIO_INVOKED 11 | #ifndef APSTUDIO_READONLY_SYMBOLS 12 | #define _APS_NEXT_RESOURCE_VALUE 105 13 | #define _APS_NEXT_COMMAND_VALUE 40001 14 | #define _APS_NEXT_CONTROL_VALUE 1001 15 | #define _APS_NEXT_SYMED_VALUE 101 16 | #endif 17 | #endif 18 | -------------------------------------------------------------------------------- /resources/android-project/app/jni/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | project(GAME) 4 | 5 | # armeabi-v7a requires cpufeatures library 6 | # include(AndroidNdkModules) 7 | # android_ndk_import_module_cpufeatures() 8 | 9 | 10 | # SDL sources are in a subfolder named "SDL" 11 | add_subdirectory(SDL) 12 | 13 | # Compilation of companion libraries 14 | #add_subdirectory(SDL_image) 15 | #add_subdirectory(SDL_mixer) 16 | #add_subdirectory(SDL_ttf) 17 | 18 | # Your game and its CMakeLists.txt are in a subfolder named "src" 19 | add_subdirectory(src) 20 | 21 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_refresh_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/CCT-Test-Bootstrap.lua: -------------------------------------------------------------------------------- 1 | config.set("abortTimeout", 3000) -- to speed things up a bit 2 | config.add("http_blacklist", "$private") 3 | if ... == "debugger" then 4 | periphemu.create("left", "debugger") 5 | peripheral.call("left", "break") 6 | end 7 | for _,v in ipairs(fs.list("/")) do if not fs.isReadOnly(v) then fs.delete(v) end end 8 | _G._CCPC_FIRST_RUN = nil 9 | _G._CCPC_UPDATED_VERSION = nil 10 | local logfile = assert(io.open("test-log.txt", "w")) 11 | io.output(logfile) 12 | shell.run("/test-rom/mcfly /test-rom/spec") 13 | logfile:close() 14 | os.shutdown(_G.failed_tests) 15 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_power_settings_new_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_content_paste_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | #dede6c 11 | #b3b358 12 | #191919 13 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CraftOS-PC 3 | Previous 4 | Ctrl 5 | Alt 6 | Reboot 7 | Next 8 | Keyboard 9 | Close 10 | Tab 11 | Paste 12 | Terminate 13 | Shut Down 14 | 15 | -------------------------------------------------------------------------------- /src/apis.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * apis.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the library structures for all CraftOS APIs. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef APIS_HPP 12 | #define APIS_HPP 13 | #include "util.hpp" 14 | extern library_t config_lib; 15 | extern library_t fs_lib; 16 | extern library_t http_lib; 17 | #ifndef NO_MOUNTER 18 | extern library_t mounter_lib; 19 | #endif 20 | extern library_t os_lib; 21 | extern library_t periphemu_lib; 22 | extern library_t peripheral_lib; 23 | extern library_t rs_lib; 24 | extern library_t term_lib; 25 | #endif 26 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/drawable/ic_baseline_keyboard_24.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /resources/android-project/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | google() 7 | } 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.3' 10 | 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | jcenter() 19 | google() 20 | } 21 | } 22 | 23 | task clean(type: Delete) { 24 | delete rootProject.buildDir 25 | } 26 | -------------------------------------------------------------------------------- /resources/.install: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Mac distribution auto-updater 3 | # DO NOT RUN STANDALONE! 4 | SRCAPP=$(dirname $0)/CraftOS-PC.app 5 | DSTAPP=$1 6 | TMPDIR=$(mktemp) 7 | echo Temp dir: $TMPDIR 8 | mkdir $TMPDIR 9 | echo $SRCAPP -\> $DSTAPP 10 | if [ -d $DSTAPP/Contents/PlugIns ]; then 11 | echo Backing up plugins... 12 | cp -Rp $DSTAPP/Contents/PlugIns $TMPDIR/ 13 | fi 14 | echo Installing new version... 15 | rm -rf $DSTAPP 16 | cp -Rp $SRCAPP $(dirname $DSTAPP)/ 17 | if [ -d $TMPDIR/PlugIns ]; then 18 | echo Replacing plugins... 19 | cp -Rp $TMPDIR/PlugIns $DSTAPP/Contents/ 20 | fi; 21 | echo Restarting... 22 | sleep 1 23 | open $DSTAPP 24 | nohup sh -c "sleep 3; hdiutil detach $(dirname $0)" & -------------------------------------------------------------------------------- /src/platform.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * platform.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file controls which platform implementation will be compiled. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include "platform.hpp" 12 | #ifdef WIN32 13 | #include "platform/win.cpp" 14 | #else 15 | #ifdef __APPLE__ 16 | #include "platform/darwin.cpp" 17 | #else 18 | #ifdef __ANDROID__ 19 | #include "platform/android.cpp" 20 | #else 21 | #ifdef __linux__ 22 | #include "platform/linux.cpp" 23 | #else 24 | #ifdef __EMSCRIPTEN__ 25 | #include "platform/emscripten.cpp" 26 | #else 27 | #error Unknown platform 28 | #endif 29 | #endif 30 | #endif 31 | #endif 32 | #endif -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | There is only one branch for updates, so only the latest versions have security updates. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | If a bug is related to the following issues: 10 | - Filesystem sandbox escape (outside of mounts) 11 | - Process/library loading 12 | - Arbitrary code execution 13 | - Network rule bypass 14 | - Any other form of reading host information (excluding LuaJIT) 15 | 16 | it is a security vulnerability, and should be reported as such. 17 | 18 | Use the Security tab to privately report a vulnerability. It will be reviewed, and if it's valid, a patch will be made available within a week (depending on the severity of the vulnerability). 19 | -------------------------------------------------------------------------------- /resources/android-project/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in [sdk]/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/java/org/libsdl/app/HIDDevice.java: -------------------------------------------------------------------------------- 1 | package org.libsdl.app; 2 | 3 | import android.hardware.usb.UsbDevice; 4 | 5 | interface HIDDevice 6 | { 7 | public int getId(); 8 | public int getVendorId(); 9 | public int getProductId(); 10 | public String getSerialNumber(); 11 | public int getVersion(); 12 | public String getManufacturerName(); 13 | public String getProductName(); 14 | public UsbDevice getDevice(); 15 | public boolean open(); 16 | public int sendFeatureReport(byte[] report); 17 | public int sendOutputReport(byte[] report); 18 | public boolean getFeatureReport(byte[] report); 19 | public void setFrozen(boolean frozen); 20 | public void close(); 21 | public void shutdown(); 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj* 2 | craftos 3 | /.vs 4 | /Debug 5 | /packages 6 | x86 7 | x64 8 | ARM64 9 | CraftOS-PC*.app 10 | /autoscan.log 11 | /Makefile - Copy 12 | /autom4te.cache 13 | /CraftOS-PC 14 | /CraftOS-PC-CCT-Edition 15 | /CraftOS-PC.xcodeproj 16 | /ccemux.* 17 | .vscode/c_cpp_properties.json 18 | codesign 19 | CraftOS-PC 2.code-workspace 20 | Makefile 21 | config.log 22 | config.status 23 | CraftOS-PC*.dmg 24 | .DS_Store 25 | example_peripheral.dylib 26 | craftos.html* 27 | craftos.wa* 28 | craftos.*js 29 | CraftOS-PC.html 30 | *.dSYM 31 | /src/lua51.lib 32 | a.out* 33 | *.mem 34 | index.html 35 | *.obj 36 | *.exe 37 | raw_frame_reader 38 | src/fs_standalone.cpp 39 | *.vcxproj.user 40 | *.aps 41 | include_arm 42 | vcpkg_installed 43 | /ignored.txt 44 | /src/apikey.cpp 45 | *.dylib 46 | *.so 47 | *.bundle -------------------------------------------------------------------------------- /resources/android-project/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | android.useAndroidX=true 19 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /src/apis/handles/fs_handle.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * apis/handles/fs_handle.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the methods for file handles. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef FS_HANDLE_HPP 12 | #define FS_HANDLE_HPP 13 | extern "C" { 14 | #include 15 | } 16 | extern int fs_handle_close(lua_State *L); 17 | extern int fs_handle_gc(lua_State *L); 18 | extern int fs_handle_readAll(lua_State *L); 19 | extern int fs_handle_readLine(lua_State *L); 20 | extern int fs_handle_readChar(lua_State *L); 21 | extern int fs_handle_readByte(lua_State *L); 22 | extern int fs_handle_readAllByte(lua_State *L); 23 | extern int fs_handle_writeString(lua_State *L); 24 | extern int fs_handle_writeLine(lua_State *L); 25 | extern int fs_handle_writeByte(lua_State *L); 26 | extern int fs_handle_flush(lua_State *L); 27 | extern int fs_handle_seek(lua_State *L); 28 | #endif -------------------------------------------------------------------------------- /examples/plugin_base.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * plugin_base.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file can be used as a template for new plugins. 6 | * 7 | * This code is released in the public domain. 8 | */ 9 | 10 | extern "C" { 11 | #include 12 | #include 13 | } 14 | #include 15 | 16 | // add your functions here... 17 | 18 | static luaL_Reg M[] = { 19 | // add functions here as {name, function}... 20 | {NULL, NULL} 21 | }; 22 | 23 | // replace "myplugin" with the plugin name as used in `luaopen_*` below 24 | static PluginInfo info("myplugin"); 25 | 26 | extern "C" { 27 | // replace "myplugin" with the plugin name 28 | DLLEXPORT int luaopen_myplugin(lua_State *L) { 29 | luaL_newlib(L, M); 30 | return 1; 31 | } 32 | 33 | DLLEXPORT PluginInfo * plugin_init(PluginFunctions * func, const path_t& path) { 34 | // configure any other information, or save the functions here... 35 | return &info; 36 | } 37 | } -------------------------------------------------------------------------------- /examples/ccemux.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/terminal/TRoRTerminal.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * terminal/TRoRTerminal.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the TRoRTerminal class. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef TERMINAL_TRORTERMINAL_HPP 12 | #define TERMINAL_TRORTERMINAL_HPP 13 | #include 14 | #include 15 | #include "../runtime.hpp" 16 | 17 | class TRoRTerminal: public Terminal { 18 | public: 19 | static void init(); 20 | static void quit(); 21 | static void pollEvents() {defaultPollEvents();} 22 | static void showGlobalMessage(uint32_t flags, const char * title, const char * message); 23 | TRoRTerminal(std::string title); 24 | ~TRoRTerminal() override; 25 | void render() override {} 26 | void showMessage(uint32_t flags, const char * title, const char * message) override; 27 | void setLabel(std::string label) override; 28 | void onActivate() override {} 29 | bool resize(unsigned w, unsigned h) override {return false;} 30 | }; 31 | 32 | #endif -------------------------------------------------------------------------------- /src/mem/cluster.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mem/cluster.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the cluster allocator. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include 12 | 13 | #define CLUSTER_SIZE 4096 14 | #define CLUSTER_BITMAP_SIZE CLUSTER_SIZE / (sizeof(bitmap_unit) * 8) 15 | 16 | class ClusterAllocator { 17 | typedef unsigned long bitmap_unit; 18 | 19 | struct cluster_t { 20 | cluster_t * next; 21 | unsigned long id; 22 | bitmap_unit bitmap[CLUSTER_BITMAP_SIZE]; 23 | unsigned char ptr[]; 24 | }; 25 | 26 | const size_t elem_size; // size of each element in the cluster 27 | cluster_t * head; // pointer to first node of cluster list 28 | cluster_t * freecluster; // pointer to first potentially free cluster 29 | 30 | cluster_t * newcluster(long id); 31 | 32 | public: 33 | ClusterAllocator(const size_t elem_size); 34 | ~ClusterAllocator(); 35 | void * alloc(); 36 | void free(void * ptr); 37 | }; 38 | -------------------------------------------------------------------------------- /src/peripheral/debug_adapter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/debug_adapter.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the VS Code debug adapter. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_DEBUG_ADAPTER_HPP 12 | #define PERIPHERAL_DEBUG_ADAPTER_HPP 13 | #include "debugger.hpp" 14 | #include 15 | #include 16 | 17 | class debug_adapter: public debugger { 18 | friend class DAPConnection; 19 | Poco::Net::TCPServer server; 20 | Poco::Net::StreamSocket * socket = NULL; 21 | public: 22 | std::stringstream data; 23 | bool running = true; 24 | static peripheral * _init(lua_State *L, const char * side) {return new debug_adapter(L, side);} 25 | static void deinit(peripheral * p) {delete (debug_adapter*)p;} 26 | virtual destructor getDestructor() const override {return deinit;} 27 | debug_adapter(lua_State *L, const char * side); 28 | ~debug_adapter(); 29 | void sendData(const std::string& data); 30 | }; 31 | 32 | #endif -------------------------------------------------------------------------------- /resources/android-project/.idea/modules/craftos2-android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/terminal/HardwareSDLTerminal.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * terminal/HardwareSDLTerminal.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the HardwareSDLTerminal class. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef TERMINAL_HARDWARESDLTERMINAL_HPP 12 | #define TERMINAL_HARDWARESDLTERMINAL_HPP 13 | #include "SDLTerminal.hpp" 14 | 15 | class HardwareSDLTerminal : public SDLTerminal { 16 | friend class debug_adapter; 17 | public: 18 | static void init(); 19 | static void quit(); 20 | static bool pollEvents(); 21 | HardwareSDLTerminal(std::string title); 22 | ~HardwareSDLTerminal() override; 23 | bool drawChar(unsigned char c, int x, int y, Color fg, Color bg, bool transparent = false) override; 24 | void render() override; 25 | bool resize(unsigned w, unsigned h) override; 26 | private: 27 | SDL_Renderer *ren = NULL; 28 | SDL_Texture *font = NULL; 29 | SDL_Texture *pixtex = NULL; 30 | static SDL_Renderer *singleRen; 31 | static SDL_Texture *singleFont; 32 | static SDL_Texture *singlePixtex; 33 | }; 34 | #endif -------------------------------------------------------------------------------- /resources/android-project/.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /src/peripheral/computer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/computer.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the computer peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_COMPUTER_HPP 12 | #define PERIPHERAL_COMPUTER_HPP 13 | #include 14 | 15 | class computer: public peripheral { 16 | friend struct Computer; 17 | Computer * comp; 18 | Computer * thiscomp; 19 | int turnOn(lua_State *L); 20 | int shutdown(lua_State *L); 21 | int reboot(lua_State *L); 22 | int getID(lua_State *L); 23 | int isOn(lua_State *L); 24 | int getLabel(lua_State *L); 25 | public: 26 | static library_t methods; 27 | static peripheral * init(lua_State *L, const char * side) {return new computer(L, side);} 28 | static void deinit(peripheral * p) {delete (computer*)p;} 29 | destructor getDestructor() const override {return deinit;} 30 | library_t getMethods() const override {return methods;} 31 | computer(lua_State *L, const char * side); 32 | ~computer(); 33 | int call(lua_State *L, const char * method) override; 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | 13 | 14 | **Describe the bug** 15 | A clear and concise description of what the bug is. 16 | 17 | **To Reproduce** 18 | Steps to reproduce the behavior: 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | **Expected behavior** 25 | A clear and concise description of what you expected to happen. 26 | 27 | **Screenshots** 28 | If applicable, add screenshots or recordings to help explain your problem. You can capture these using F2, F3, or F12. If CraftOS-PC has crashed, paste the stack trace here (wrapped in \`\`\` characters please!). 29 | 30 | **Environment (please complete the following information):** 31 | - OS: [e.g. Windows 10] 32 | - OS Version: [e.g. 2004] (this can be found in Settings -> System -> About) 33 | - CraftOS-PC Version: [e.g. v2.2] 34 | - Compiled from source? [Yes] [No] (if in doubt, choose No) 35 | 36 | **Additional context** 37 | Add any other context about the problem here. 38 | -------------------------------------------------------------------------------- /resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LSMinimumSystemVersion 6 | 10.15.0 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleAllowMixedLocalizations 10 | 11 | CFBundleExecutable 12 | craftos 13 | CFBundleIconFile 14 | CraftOS-PC.icns 15 | CFBundleIdentifier 16 | cc.craftos-pc.CraftOS-PC 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | CraftOS-PC 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 2.8.3 25 | CFBundleSignature 26 | ???? 27 | LSApplicationCategoryType 28 | Unknown 29 | CFBundleVersion 30 | 2.8.3 31 | NSHumanReadableCopyright 32 | Copyright (C) 2019-2024 JackMacWindows. 33 | NSHighResolutionCapable 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/peripheral/energy.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/energy.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the energy peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_ENERGY_HPP 12 | #define PERIPHERAL_ENERGY_HPP 13 | #include "../util.hpp" 14 | #include 15 | 16 | class energy: public energy_storage { 17 | int currentEnergy = 0; 18 | int maxEnergy = 1'000'000'000; 19 | std::vector types = {"energy", "energy_storage"}; 20 | int setEnergy(lua_State *L); 21 | protected: 22 | int getEnergy() override; 23 | int getEnergyCapacity() override; 24 | public: 25 | static library_t methods; 26 | static peripheral * init(lua_State *L, const char * side) {return new energy(L, side);} 27 | static void deinit(peripheral * p) {delete (energy*)p;} 28 | destructor getDestructor() const override {return deinit;} 29 | library_t getMethods() const override {return methods;} 30 | std::vector getTypes() const override {return types;} 31 | energy(lua_State *L, const char * side); 32 | ~energy(); 33 | int call(lua_State *L, const char * method) override; 34 | }; 35 | 36 | #endif -------------------------------------------------------------------------------- /src/platform/emscripten.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * platform/emscripten.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file implements functions specific to the Emscripten/WASM platform. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifdef __EMSCRIPTEN__ 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "../platform.hpp" 17 | 18 | void setThreadName(std::thread &t, const std::string& name) {} 19 | 20 | void setBasePath(path_t path) {} 21 | 22 | void setROMPath(path_t path) {} 23 | 24 | path_t getBasePath() { 25 | return "/user-data"; 26 | } 27 | 28 | path_t getROMPath() { 29 | return "/craftos"; 30 | } 31 | 32 | path_t getPlugInPath() { 33 | return "/user-data/plugins"; 34 | } 35 | 36 | path_t getMCSavePath() { 37 | return ""; 38 | } 39 | 40 | void updateNow(const std::string& tag_name, const Poco::JSON::Object::Ptr root) {} 41 | 42 | void migrateOldData() {} 43 | 44 | void copyImage(SDL_Surface* surf, SDL_Window* win) {} 45 | 46 | void setupCrashHandler() {} 47 | 48 | void setFloating(SDL_Window* win, bool state) {} 49 | 50 | void platformExit() {} 51 | 52 | void addSystemCertificates(Poco::Net::Context::Ptr context) {} 53 | 54 | void unblockInput() {} 55 | 56 | #endif -------------------------------------------------------------------------------- /src/main.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * main.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines variables used on the command line that may be used by 6 | * other CraftOS-PC components. 7 | * 8 | * This code is licensed under the MIT license. 9 | * Copyright (c) 2019-2024 JackMacWindows. 10 | */ 11 | 12 | #ifndef MAIN_HPP 13 | #define MAIN_HPP 14 | 15 | #include 16 | #include 17 | #include 18 | #include "platform.hpp" 19 | 20 | extern bool rawClient; 21 | extern std::string overrideHardwareDriver; 22 | extern std::map rawClientTerminals; 23 | extern std::unordered_map rawClientTerminalIDs; 24 | extern std::string script_file; 25 | extern std::string script_args; 26 | extern int returnValue; 27 | extern std::unordered_map globalPluginErrors; 28 | extern int parseArguments(const std::vector& argv); 29 | 30 | // These functions are required by main for full initialization of Lua. 31 | extern "C" { 32 | extern int db_debug(lua_State *L); 33 | extern int db_breakpoint(lua_State *L); 34 | extern int db_unsetbreakpoint(lua_State *L); 35 | extern void setcompmask_(lua_State *L, int mask); 36 | extern FILE* mounter_fopen_(lua_State *L, const char * filename, const char * mode); 37 | extern int mounter_fclose_(lua_State *L, FILE * stream); 38 | } 39 | 40 | #endif -------------------------------------------------------------------------------- /src/terminal/CLITerminal.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * terminal/CLITerminal.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the CLITerminal class. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef NO_CLI 12 | #ifndef TERMINAL_CLITERMINAL_HPP 13 | #define TERMINAL_CLITERMINAL_HPP 14 | #include 15 | #include 16 | #include 17 | #undef scroll 18 | 19 | class CLITerminal: public Terminal { 20 | friend void mainLoop(); 21 | friend void pressControl(int sig); 22 | friend void pressAlt(int sig); 23 | unsigned last_pair; 24 | static unsigned short lastPaletteChecksum; 25 | public: 26 | static void init(); 27 | static void quit(); 28 | static bool pollEvents(); 29 | static void renderNavbar(std::string title); 30 | static bool stopRender; 31 | static bool forceRender; 32 | 33 | CLITerminal(std::string title); 34 | ~CLITerminal() override; 35 | bool drawChar(char c, int x, int y, Color fg, Color bg, bool transparent = false); 36 | void render() override; 37 | bool resize(unsigned w, unsigned h) override; 38 | void getMouse(int *x, int *y); 39 | void showMessage(uint32_t flags, const char * title, const char * message) override; 40 | void setLabel(std::string label) override; 41 | void onActivate() override; 42 | }; 43 | 44 | #endif 45 | #endif -------------------------------------------------------------------------------- /src/peripheral/tank.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/tank.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the tank peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_TANK_HPP 12 | #define PERIPHERAL_TANK_HPP 13 | #include "../util.hpp" 14 | #include 15 | 16 | class tank: public fluid_storage { 17 | int tankCount = 1; 18 | int tankCapacity = 256; 19 | std::vector> fluids; 20 | std::vector types = {"tank", "fluid_storage"}; 21 | protected: 22 | int tanks(lua_State *L) override; 23 | int addFluid(const std::string& fluid, int amount) override; 24 | std::list> removeFluid(const std::string& fluid, int amount) override; 25 | public: 26 | static library_t methods; 27 | static peripheral * init(lua_State *L, const char * side) {return new tank(L, side);} 28 | static void deinit(peripheral * p) {delete (tank*)p;} 29 | destructor getDestructor() const override {return deinit;} 30 | library_t getMethods() const override {return methods;} 31 | std::vector getTypes() const override {return types;} 32 | tank(lua_State *L, const char * side); 33 | ~tank(); 34 | int call(lua_State *L, const char * method) override; 35 | }; 36 | 37 | #endif -------------------------------------------------------------------------------- /src/peripheral/chest.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/chest.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the chest peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_CHEST_HPP 12 | #define PERIPHERAL_CHEST_HPP 13 | #include "../util.hpp" 14 | #include 15 | 16 | class chest: public inventory { 17 | struct slot { 18 | std::string name; 19 | uint8_t count = 0; 20 | }; 21 | bool isDouble = false; 22 | slot items[54]; 23 | int setItem(lua_State *L); 24 | protected: 25 | int size() override; 26 | void getItemDetail(lua_State *L, int slot) override; 27 | int addItems(lua_State *L, int slot, int count) override; 28 | int removeItems(int slot, int count) override; 29 | public: 30 | static library_t methods; 31 | static std::vector types; 32 | static peripheral * init(lua_State *L, const char * side) {return new chest(L, side);} 33 | static void deinit(peripheral * p) {delete (chest*)p;} 34 | destructor getDestructor() const override {return deinit;} 35 | library_t getMethods() const override {return methods;} 36 | std::vector getTypes() const override {return types;} 37 | chest(lua_State *L, const char * side); 38 | ~chest(); 39 | int call(lua_State *L, const char * method) override; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /resources/packStandaloneROM.js: -------------------------------------------------------------------------------- 1 | // Run this script with Node in the same directory as the ROM 2 | // Generates an fs_standalone.cpp file that can be used for standalone builds 3 | const fs = require("fs"); 4 | let out = fs.openSync("fs_standalone.cpp", "w") 5 | fs.writeSync(out, '#include \n\nFileEntry standaloneROM(') 6 | function writeDir(path, level) { 7 | console.log("Reading directory " + path) 8 | fs.writeSync(out, "{\n") 9 | for (var f of fs.readdirSync(path)) { 10 | if (f == "." || f == ".." || f == ".DS_Store" || f == "desktop.ini" || f == "packStandaloneROM.js") continue; 11 | fs.writeSync(out, `${' '.repeat(level * 4)}{"${f}", `) 12 | if (fs.lstatSync(path + "/" + f).isDirectory()) writeDir(path + "/" + f, level + 1) 13 | else { 14 | console.log("Reading file " + path + "/" + f) 15 | fs.writeSync(out, JSON.stringify(fs.readFileSync(path + "/" + f, "utf8")).replace(/\\r\\n/g, "\\n").replace(/\\n/g, "\\n\"\n\"")) 16 | } 17 | fs.writeSync(out, "},\n") 18 | } 19 | fs.writeSync(out, " ".repeat((level - 1) * 4) + "}") 20 | } 21 | writeDir("rom", 1) 22 | fs.writeSync(out, ");\n\nFileEntry standaloneDebug(") 23 | writeDir("debug", 1) 24 | fs.writeSync(out, ");\n\nstd::string standaloneBIOS = ") 25 | console.log("Reading BIOS") 26 | fs.writeSync(out, JSON.stringify(fs.readFileSync("bios.lua", "utf8")).replace(/\\r\\n/g, "\\n").replace(/\\n/g, "\\n\"\n\"") + ";") 27 | fs.closeSync(out); 28 | -------------------------------------------------------------------------------- /api/generic_peripheral/energy_storage.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * generic_peripheral/energy_storage.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines a generic peripheral class for energy-storing peripherals 6 | * to inherit from. 7 | * 8 | * This code is licensed under the MIT license. 9 | * Copyright (c) 2019-2024 JackMacWindows. 10 | */ 11 | 12 | #ifndef CRAFTOS_PC_GENERIC_PERIPHERAL_ENERGY_STORAGE_HPP 13 | #define CRAFTOS_PC_GENERIC_PERIPHERAL_ENERGY_STORAGE_HPP 14 | #include "../peripheral.hpp" 15 | 16 | class energy_storage : public peripheral { 17 | protected: 18 | virtual int getEnergy() = 0; // Returns the current energy of the peripheral. 19 | virtual int getEnergyCapacity() = 0; // Returns the total energy capacity of the peripheral. 20 | public: 21 | virtual int call(lua_State *L, const char * method) override { 22 | const std::string m(method); 23 | if (m == "getEnergy") lua_pushinteger(L, getEnergy()); 24 | else if (m == "getEnergyCapacity") lua_pushinteger(L, getEnergyCapacity()); 25 | else return luaL_error(L, "No such method"); 26 | return 1; 27 | } 28 | void update() override {} 29 | library_t getMethods() const override { 30 | static luaL_Reg reg[] = { 31 | {"getEnergy", NULL}, 32 | {"getEnergyCapacity", NULL}, 33 | {NULL, NULL} 34 | }; 35 | static library_t methods = {"energy_storage", reg, nullptr, nullptr}; 36 | return methods; 37 | } 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/platform.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * platform.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines functions that have implementations that differ based on 6 | * the platform the program is built for. 7 | * 8 | * This code is licensed under the MIT license. 9 | * Copyright (c) 2019-2024 JackMacWindows. 10 | */ 11 | 12 | #ifndef PLATFORM_HPP 13 | #define PLATFORM_HPP 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using path_t = std::filesystem::path; 23 | 24 | #ifdef __IPHONEOS__ 25 | extern void iOS_SetWindowTitle(SDL_Window * win, const char * title); 26 | #define SDL_SetWindowTitle iOS_SetWindowTitle 27 | #endif 28 | 29 | extern void setThreadName(std::thread &t, const std::string& name); 30 | extern void setBasePath(path_t path); 31 | extern void setROMPath(path_t path); 32 | extern path_t getBasePath(); 33 | extern path_t getROMPath(); 34 | extern path_t getPlugInPath(); 35 | extern path_t getMCSavePath(); 36 | extern void updateNow(const std::string& tag_name, const Poco::JSON::Object::Ptr root); 37 | extern void migrateOldData(); 38 | extern void copyImage(SDL_Surface* surf, SDL_Window* win); 39 | extern void setupCrashHandler(); 40 | extern void setFloating(SDL_Window* win, bool state); 41 | extern void platformExit(); 42 | extern void addSystemCertificates(Poco::Net::Context::Ptr context); 43 | extern void unblockInput(); 44 | extern bool winFolderIsReadOnly(path_t path); 45 | #endif 46 | -------------------------------------------------------------------------------- /src/peripheral/energy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/energy.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the methods for the energy peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include "energy.hpp" 12 | 13 | int energy::getEnergy() { 14 | return currentEnergy; 15 | } 16 | 17 | int energy::getEnergyCapacity() { 18 | return maxEnergy; 19 | } 20 | 21 | int energy::setEnergy(lua_State *L) { 22 | currentEnergy = min(max((int)luaL_checkinteger(L, 1), 0), maxEnergy); 23 | return 0; 24 | } 25 | 26 | energy::energy(lua_State *L, const char * side) { 27 | maxEnergy = luaL_optinteger(L, 3, maxEnergy); 28 | if (lua_istable(L, 4)) { 29 | lua_pushinteger(L, 1); 30 | lua_gettable(L, 4); 31 | for (int i = 2; lua_isstring(L, -1); i++) { 32 | types.push_back(tostring(L, -1)); 33 | lua_pop(L, 1); 34 | lua_pushinteger(L, i); 35 | lua_gettable(L, 4); 36 | } 37 | lua_pop(L, 1); 38 | } else if (!lua_isnoneornil(L, 4)) luaL_checktype(L, 4, LUA_TTABLE); 39 | } 40 | 41 | energy::~energy() {} 42 | 43 | int energy::call(lua_State *L, const char * method) { 44 | const std::string m(method); 45 | if (m == "setEnergy") return setEnergy(L); 46 | else return energy_storage::call(L, method); 47 | } 48 | 49 | static luaL_Reg energy_reg[] = { 50 | {"getEnergy", NULL}, 51 | {"getEnergyCapacity", NULL}, 52 | {"setEnergy", NULL}, 53 | {NULL, NULL} 54 | }; 55 | 56 | library_t energy::methods = {"!!MULTITYPE", energy_reg, nullptr, nullptr}; -------------------------------------------------------------------------------- /src/apis/handles/http_handle.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * apis/handles/http_handle.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the methods for HTTP handles. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef HTTP_HANDLE_HPP 12 | #define HTTP_HANDLE_HPP 13 | extern "C" { 14 | #include 15 | } 16 | struct http_handle_t { 17 | std::string url; 18 | std::string failureReason; 19 | Poco::Net::HTTPClientSession * session; 20 | Poco::Net::HTTPResponse * handle; 21 | std::istream * stream; 22 | http_handle_t(std::istream * s) : stream(s) {} 23 | }; 24 | extern int http_handle_free(lua_State *L); 25 | extern int http_handle_close(lua_State *L); 26 | extern int http_handle_readAll(lua_State *L); 27 | extern int http_handle_readLine(lua_State *L); 28 | extern int http_handle_readChar(lua_State *L); 29 | extern int http_handle_readByte(lua_State *L); 30 | extern int http_handle_readAllByte(lua_State *L); 31 | extern int http_handle_getResponseCode(lua_State *L); 32 | extern int http_handle_getResponseHeaders(lua_State *L); 33 | extern int http_handle_seek(lua_State *L); 34 | extern int req_read(lua_State *L); 35 | extern int req_readLine(lua_State *L); 36 | extern int req_readAll(lua_State *L); 37 | extern int req_close(lua_State *L); 38 | extern int req_free(lua_State *L); 39 | extern int req_getURL(lua_State *L); 40 | extern int req_getMethod(lua_State *L); 41 | extern int req_getRequestHeaders(lua_State *L); 42 | extern int res_write(lua_State *L); 43 | extern int res_writeLine(lua_State *L); 44 | extern int res_close(lua_State *L); 45 | extern int res_setStatusCode(lua_State *L); 46 | extern int res_setResponseHeader(lua_State *L); 47 | #endif -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "(lldb) Launch", 9 | "type": "lldb", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/craftos", 12 | "args": [], 13 | "cwd": "${workspaceFolder}", 14 | "preLaunchTask": "Build" 15 | }, 16 | { 17 | "name": "(lldb) Launch (Guard Malloc)", 18 | "type": "lldb", 19 | "request": "launch", 20 | "program": "${workspaceFolder}/craftos", 21 | "args": [], 22 | "cwd": "${workspaceFolder}", 23 | "preLaunchTask": "Build", 24 | "env": {"DYLD_INSERT_LIBRARIES": "/usr/lib/libgmalloc.dylib"} 25 | }, 26 | { 27 | "name": "(gdb) Launch", 28 | "type": "cppdbg", 29 | "request": "launch", 30 | "program": "${workspaceFolder}/craftos", 31 | "args": [], 32 | "stopAtEntry": false, 33 | "cwd": "${workspaceFolder}", 34 | "environment": [], 35 | "externalConsole": false, 36 | "MIMode": "gdb", 37 | "preLaunchTask": "Build", 38 | "setupCommands": [ 39 | { 40 | "description": "Enable pretty-printing for gdb", 41 | "text": "-enable-pretty-printing", 42 | "ignoreFailures": true 43 | } 44 | ] 45 | } 46 | ] 47 | } -------------------------------------------------------------------------------- /resources/CraftOS-PC.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | Advanced ComputerCraft Emulator 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /examples/example_peripheral.cpp: -------------------------------------------------------------------------------- 1 | extern "C" { 2 | #include 3 | #include 4 | } 5 | #include 6 | 7 | class example_peripheral: public peripheral { 8 | int add(lua_State *L) { 9 | lua_pushnumber(L, luaL_checknumber(L, 1) + luaL_checknumber(L, 2)); 10 | return 1; 11 | } 12 | int subtract(lua_State *L) { 13 | lua_pushnumber(L, luaL_checknumber(L, 1) - luaL_checknumber(L, 2)); 14 | return 1; 15 | } 16 | int ping(lua_State *L) { 17 | lua_pushstring(L, "pong"); 18 | return 1; 19 | } 20 | public: 21 | static library_t methods; 22 | example_peripheral(lua_State *L, const char * side) {} 23 | ~example_peripheral(){} 24 | int call(lua_State *L, const char * method) { 25 | std::string m(method); 26 | if (m == "add") return add(L); 27 | else if (m == "subtract") return subtract(L); 28 | else if (m == "ping") return ping(L); 29 | else return luaL_error(L, "No such method"); 30 | } 31 | static peripheral * init(lua_State *L, const char * side) {return new example_peripheral(L, side);} 32 | static void deinit(peripheral * p) {delete (example_peripheral*)p;} 33 | virtual destructor getDestructor() const {return deinit;} 34 | void update(){} 35 | virtual library_t getMethods() const {return methods;} 36 | }; 37 | 38 | static luaL_Reg methods_reg[] = { 39 | {"add", NULL}, 40 | {"subtract", NULL}, 41 | {"ping", NULL}, 42 | }; 43 | static PluginInfo info; 44 | library_t example_peripheral::methods = {"example_peripheral", methods_reg, nullptr, nullptr}; 45 | 46 | extern "C" { 47 | DLLEXPORT PluginInfo * plugin_init(PluginFunctions * func, const path_t& path) { 48 | func->registerPeripheralFn("example_peripheral", &example_peripheral::init); 49 | return &info; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "craftos-pc", 3 | "version-string": "v2.8", 4 | "description": "Advanced ComputerCraft emulator", 5 | "dependencies": [ 6 | "sdl2", 7 | "openssl", 8 | { 9 | "name": "poco", 10 | "default-features": true, 11 | "features": [ "netssl" ] 12 | }, 13 | { 14 | "name": "zlib", 15 | "platform": "windows" 16 | }, 17 | { 18 | "name": "dirent", 19 | "platform": "windows" 20 | } 21 | ], 22 | "default-features": ["cli", "speaker", "pdf-printer", "png-screenshots", "webp-screenshots"], 23 | "features": { 24 | "cli": { 25 | "description": "Console interface", 26 | "dependencies": [ 27 | { 28 | "name": "pdcurses", 29 | "platform": "windows" 30 | } 31 | ] 32 | }, 33 | "speaker": { 34 | "description": "Speaker/sound support", 35 | "dependencies": [ 36 | { 37 | "name": "sdl2-mixer", 38 | "default-features": true, 39 | "features": [ "libmodplug", "opusfile", "fluidsynth", "libflac", "mpg123" ] 40 | } 41 | ] 42 | }, 43 | "pdf-printer": { 44 | "description": "Print to PDF file with printer", 45 | "dependencies": [ "libharu" ] 46 | }, 47 | "png-screenshots": { 48 | "description": "Take screenshots in PNG format", 49 | "dependencies": [ "pngpp" ] 50 | }, 51 | "webp-screenshots": { 52 | "description": "Take screenshots and recordings in WebP format", 53 | "dependencies": [ "libwebp" ] 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /examples/peripheral_base.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral_base.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file can be used as a template for new peripheral plugins. 6 | * 7 | * This code is released in the public domain. 8 | */ 9 | 10 | extern "C" { 11 | #include 12 | #include 13 | } 14 | #include 15 | 16 | // Replace myperipheral with the name of your peripheral 17 | class myperipheral: public peripheral { 18 | // Define your peripheral methods here 19 | public: 20 | static library_t methods; 21 | // Replace myperipheral with the name of your peripheral 22 | myperipheral(lua_State *L, const char * side) {} 23 | ~myperipheral(){} 24 | static peripheral * init(lua_State *L, const char * side) {return new myperipheral(L, side);} 25 | static void deinit(peripheral * p) {delete (myperipheral*)p;} 26 | destructor getDestructor() const override {return deinit;} 27 | int call(lua_State *L, const char * method) override { 28 | const std::string m(method); 29 | // Check the value of m for each method: 30 | // if (m == "a") return a(L); 31 | // etc... 32 | // else return luaL_error(L, "No such method"); 33 | } 34 | void update() override {} 35 | library_t getMethods() const override {return methods;} 36 | }; 37 | 38 | static luaL_Reg methods_reg[] = { 39 | // Insert the methods names here as {"func", NULL}... 40 | {NULL, NULL} 41 | }; 42 | static PluginInfo info; 43 | // Replace myperipheral with the name of your peripheral 44 | library_t myperipheral::methods = {"myperipheral", methods_reg, nullptr, nullptr}; 45 | 46 | extern "C" { 47 | DLLEXPORT PluginInfo * plugin_init(PluginFunctions * func, const path_t& path) { 48 | // Replace myperipheral with the name of your peripheral 49 | func->registerPeripheral("myperipheral", &myperipheral::init); 50 | return &info; 51 | } 52 | } -------------------------------------------------------------------------------- /src/peripheral/drive.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/drive.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the drive peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_DRIVE_HPP 12 | #define PERIPHERAL_DRIVE_HPP 13 | #include 14 | #include 15 | #include "../util.hpp" 16 | #ifndef NO_MIXER 17 | #include 18 | #endif 19 | 20 | enum class disk_type { 21 | DISK_TYPE_NONE, 22 | DISK_TYPE_DISK, 23 | DISK_TYPE_AUDIO, 24 | DISK_TYPE_MOUNT 25 | }; 26 | 27 | class drive: public peripheral { 28 | private: 29 | disk_type diskType = disk_type::DISK_TYPE_NONE; 30 | std::string mount_path; 31 | path_t path; 32 | #ifndef NO_MIXER 33 | Mix_Music* music = NULL; 34 | #else 35 | void* music = NULL; 36 | #endif 37 | int id = 0; 38 | std::string side; 39 | int isDiskPresent(lua_State *L); 40 | int getDiskLabel(lua_State *L); 41 | int setDiskLabel(lua_State *L); 42 | int hasData(lua_State *L); 43 | int getMountPath(lua_State *L); 44 | int hasAudio(lua_State *L); 45 | int getAudioTitle(lua_State *L); 46 | int playAudio(lua_State *L); 47 | int stopAudio(lua_State *L); 48 | int ejectDisk(lua_State *L); 49 | int getDiskID(lua_State *L); 50 | int insertDisk(lua_State *L, bool init = false); 51 | public: 52 | static library_t methods; 53 | static peripheral * init(lua_State *L, const char * side) {return new drive(L, side);} 54 | static void deinit(peripheral * p) {delete (drive*)p;} 55 | destructor getDestructor() const override {return deinit;} 56 | library_t getMethods() const override { return methods; } 57 | drive(lua_State *L, const char * side); 58 | ~drive(); 59 | int call(lua_State *L, const char * method) override; 60 | }; 61 | 62 | extern void driveInit(); 63 | extern void driveQuit(); 64 | 65 | #endif -------------------------------------------------------------------------------- /src/peripheral/modem.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/modem.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the modem peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_MODEM_HPP 12 | #define PERIPHERAL_MODEM_HPP 13 | #include 14 | #include 15 | #include 16 | 17 | class modem: public peripheral { 18 | private: 19 | friend std::string modem_message(lua_State *, void*); 20 | std::unordered_set openPorts; 21 | Computer * comp; 22 | int eventQueuePosition; 23 | lua_State * eventQueue; 24 | std::mutex eventQueueMutex; 25 | std::unordered_set idsToDelete; 26 | std::string side; 27 | int netID = 0; 28 | int isOpen(lua_State *L); 29 | int open(lua_State *L); 30 | int close(lua_State *L); 31 | int closeAll(lua_State *L); 32 | int transmit(lua_State *L); 33 | int isWireless(lua_State *L); 34 | int getNamesRemote(lua_State *L); 35 | int getTypeRemote(lua_State *L); 36 | int isPresentRemote(lua_State *L); 37 | int getMethodsRemote(lua_State *L); 38 | int callRemote(lua_State *L); 39 | int hasTypeRemote(lua_State *L); 40 | int getNameLocal(lua_State *L); 41 | void receive(lua_State *data, uint16_t port, uint16_t replyPort, modem * sender); 42 | public: 43 | static library_t methods; 44 | static std::vector types; 45 | static peripheral * init(lua_State *L, const char * side) {return new modem(L, side);} 46 | static void deinit(peripheral * p) {delete (modem*)p;} 47 | destructor getDestructor() const override {return deinit;} 48 | library_t getMethods() const override {return methods;} 49 | std::vector getTypes() const override {return types;} 50 | modem(lua_State *L, const char * side); 51 | ~modem(); 52 | int call(lua_State *L, const char * method) override; 53 | void reinitialize(lua_State *L) override; 54 | }; 55 | 56 | #endif -------------------------------------------------------------------------------- /m4/find_cxx11.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the current language's compiler 12 | # or gives an error. (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the current language's default 18 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with 19 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to 20 | # force the compiler to issue an error when a bad flag is given. 21 | # 22 | # INPUT gives an alternative input source to AC_COMPILE_IFELSE. 23 | # 24 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 25 | # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. 26 | # 27 | # LICENSE 28 | # 29 | # Copyright (c) 2008 Guido U. Draheim 30 | # Copyright (c) 2011 Maarten Bosmans 31 | # 32 | # Copying and distribution of this file, with or without modification, are 33 | # permitted in any medium without royalty provided the copyright notice 34 | # and this notice are preserved. This file is offered as-is, without any 35 | # warranty. 36 | 37 | #serial 6 38 | 39 | AC_DEFUN([AX_CHECK_COMPILE_FLAG], 40 | [AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF 41 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl 42 | AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ 43 | ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS 44 | _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" 45 | AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], 46 | [AS_VAR_SET(CACHEVAR,[yes])], 47 | [AS_VAR_SET(CACHEVAR,[no])]) 48 | _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) 49 | AS_VAR_IF(CACHEVAR,yes, 50 | [m4_default([$2], :)], 51 | [m4_default([$3], :)]) 52 | AS_VAR_POPDEF([CACHEVAR])dnl 53 | ])dnl AX_CHECK_COMPILE_FLAGS 54 | -------------------------------------------------------------------------------- /src/peripheral/speaker.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/speaker.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the speaker peripheral. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef NO_MIXER 12 | #ifndef PERIPHERAL_SPEAKER_HPP 13 | #define PERIPHERAL_SPEAKER_HPP 14 | #include 15 | #include 16 | 17 | static void audioEffect(int chan, void *stream, int len, void *udata); 18 | static Uint32 audioTimer(Uint32 interval, void* param); 19 | static Uint32 speaker_audio_empty_timer(Uint32 interval, void* param); 20 | class speaker: public peripheral { 21 | friend void speakerInit(); 22 | friend void audioEffect(int chan, void *stream, int len, void *udata); 23 | friend Uint32 audioTimer(Uint32 interval, void* param); 24 | friend Uint32 speaker_audio_empty_timer(Uint32 interval, void* param); 25 | static library_t methods; 26 | static int nextChannelGroup; 27 | static int sampleSize; 28 | std::chrono::system_clock::time_point lastTickReset = std::chrono::system_clock::now(); 29 | unsigned int noteCount = 0; 30 | int channelGroup; 31 | int audioChannel; 32 | ProtectedObject> audioQueue; 33 | std::queue volumeQueue; 34 | int audioQueueEnd = 0; 35 | uint8_t * delayedBuffer; 36 | int delayedBufferPos = 0; 37 | SDL_TimerID delayedBufferTimer = 0; 38 | Computer * comp; 39 | std::string side; 40 | int playNote(lua_State *L); 41 | int playSound(lua_State *L); 42 | int playAudio(lua_State *L); 43 | int playLocalMusic(lua_State *L); 44 | int listSounds(lua_State *L); 45 | int setSoundFont(lua_State *L); 46 | int stop(lua_State *L); 47 | int setPosition(lua_State *L); 48 | public: 49 | static peripheral * init(lua_State *L, const char * side) {return new speaker(L, side);} 50 | static void deinit(peripheral * p) {delete (speaker*)p;} 51 | speaker(lua_State *L, const char * side); 52 | ~speaker(); 53 | destructor getDestructor() const override {return deinit;} 54 | int call(lua_State *L, const char * method) override; 55 | library_t getMethods() const override {return methods;} 56 | }; 57 | 58 | extern void speakerInit(); 59 | extern void speakerQuit(); 60 | 61 | #endif 62 | #endif -------------------------------------------------------------------------------- /src/peripheral/monitor.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/monitor.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the monitor peripheral. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_MONITOR_HPP 12 | #define PERIPHERAL_MONITOR_HPP 13 | #include 14 | #include 15 | #include 16 | #ifdef scroll 17 | #undef scroll 18 | #endif 19 | 20 | class monitor : public peripheral { 21 | private: 22 | unsigned char colors = 0xF0; 23 | std::chrono::high_resolution_clock::time_point last_blink = std::chrono::high_resolution_clock::now(); 24 | int write(lua_State *L); 25 | int scroll(lua_State *L); 26 | int setCursorPos(lua_State *L); 27 | int setCursorBlink(lua_State *L); 28 | int getCursorPos(lua_State *L); 29 | int getCursorBlink(lua_State *L); 30 | int getSize(lua_State *L); 31 | int clear(lua_State *L); 32 | int clearLine(lua_State *L); 33 | int setTextColor(lua_State *L); 34 | int setBackgroundColor(lua_State *L); 35 | int isColor(lua_State *L); 36 | int getTextColor(lua_State *L); 37 | int getBackgroundColor(lua_State *L); 38 | int blit(lua_State *L); 39 | int getPaletteColor(lua_State *L); 40 | int setPaletteColor(lua_State *L); 41 | int setGraphicsMode(lua_State *L); 42 | int getGraphicsMode(lua_State *L); 43 | int setPixel(lua_State *L); 44 | int getPixel(lua_State *L); 45 | int setTextScale(lua_State *L); 46 | int getTextScale(lua_State *L); 47 | int drawPixels(lua_State *L); 48 | int getPixels(lua_State *L); 49 | int screenshot(lua_State *L); 50 | int setFrozen(lua_State *L); 51 | int getFrozen(lua_State *L); 52 | int setSize(lua_State *L); 53 | int setBlockSize(lua_State *L); 54 | public: 55 | Terminal * term; 56 | static library_t methods; 57 | static peripheral * init(lua_State *L, const char * side) {return new monitor(L, side);} 58 | static void deinit(peripheral * p) {delete (monitor*)p;} 59 | destructor getDestructor() const override {return deinit;} 60 | library_t getMethods() const override {return methods;} 61 | monitor(lua_State *L, const char * side); 62 | ~monitor(); 63 | int call(lua_State *L, const char * method) override; 64 | }; 65 | #endif 66 | -------------------------------------------------------------------------------- /api/lib.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * lib.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines some functions and constants useful for plugins. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef CRAFTOS_PC_LIB_HPP 12 | #define CRAFTOS_PC_LIB_HPP 13 | 14 | extern "C" { 15 | #include "lua.h" 16 | #include "lauxlib.h" 17 | } 18 | #include 19 | #include 20 | 21 | #ifndef CRAFTOS_PC_COMPUTER_HPP 22 | struct Computer; 23 | #endif 24 | 25 | /// The current version of plugin support. 26 | #if defined(_WIN32) && defined(_DEBUG) 27 | #define PLUGIN_VERSION 100012 28 | #else 29 | #define PLUGIN_VERSION 12 30 | #endif 31 | 32 | /// Most OS's use UTF-8/ASCII for path storage; however, Windows is contrarian and uses UTF-16. 33 | /// To abstract this difference in implementation, a path_t type is used to allow the correct 34 | /// string type to be used on each platform. Since the type only changes when the platform changes, 35 | /// this should not have a negative impact on ABI stability. 36 | /// @deprecated This is retained for ABI compatibility - the next API will use std::filesystem::path instead. 37 | #ifdef _WIN32 38 | typedef std::wstring _path_t; 39 | #define _to_path_t std::to_wstring 40 | #else 41 | typedef std::string _path_t; 42 | #define _to_path_t std::to_string 43 | #endif 44 | 45 | // The library_t structure is used to hold information about an API. 46 | struct Computer; 47 | struct library_t { 48 | const char * name; // The name of the API 49 | luaL_Reg * functions; // The list of functions used in the API 50 | std::function init; // A function to call when opening the API 51 | std::function deinit; // A function to call when closing the API 52 | }; 53 | 54 | #ifdef CRAFTOS_PC_HPP 55 | /** 56 | * Returns the associated Computer object pointer for a Lua state. 57 | * This is a bit slow, so try not to call it too much, or cache results. 58 | * (CraftOS-PC caches results internally.) 59 | * @param L The Lua state to get the computer for 60 | * @return The Computer object the state is running on 61 | */ 62 | inline Computer * get_comp(lua_State *L) { 63 | lua_pushinteger(L, 1); 64 | lua_gettable(L, LUA_REGISTRYINDEX); 65 | void * retval = lua_touserdata(L, -1); 66 | lua_pop(L, 1); 67 | return (Computer*)retval; 68 | } 69 | #endif 70 | 71 | #endif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2024 JackMacWindows 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | 24 | 25 | Default instrument sounds for the speaker peripheral have been borrowed from 26 | various sources: 27 | 28 | * The following sources were retrieved from http://wiki.laptop.org/go/Sound_samples: 29 | 30 | * banjo, bass, basedrum, bell, cow_bell, flute, guitar, hat, and pling were 31 | originally created by OpenPathMusic for use in the OLPC sound library. They 32 | have been shortened for use in CraftOS-PC. These were retrieved from 33 | https://archive.org/details/OpenPathMusic44V[x] (where [x] is any number 34 | between 1-4). The files are licensed under the Creative Commons Attribution 35 | 3.0 (CC BY 3.0) license. See https://creativecommons.org/licenses/by/3.0/legalcode 36 | for more details. 37 | 38 | * harp and digeridoo were originally created by Lisa Lim for use in the OLPC 39 | sound library. They have been shortened for use in CraftOS-PC. These were 40 | retrieved from https://archive.org/details/LisaLim. The files are licensed 41 | under the Creative Commons Attribution 3.0 (CC BY 3.0) license. See 42 | https://creativecommons.org/licenses/by/3.0/legalcode for more details. 43 | 44 | * bell, chime, iron_xylophone, snare, and xylophone were extracted from the 45 | GMGSx.sf2 soundfont that is included with SynthFont 1 (http://www.synthfont.com). 46 | They have been shortened for use in CraftOS-PC. They are distributed in the 47 | public domain. 48 | 49 | * bit was created for use in CraftOS-PC. It is distributed in the public domain. -------------------------------------------------------------------------------- /src/terminal/RawTerminal.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * terminal/RawTerminal.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the RawTerminal class. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef TERMINAL_RAWTERMINAL_HPP 12 | #define TERMINAL_RAWTERMINAL_HPP 13 | #include 14 | #include 15 | #include 16 | #include "../runtime.hpp" 17 | 18 | enum { 19 | CCPC_RAW_TERMINAL_DATA = 0, 20 | CCPC_RAW_KEY_DATA, 21 | CCPC_RAW_MOUSE_DATA, 22 | CCPC_RAW_EVENT_DATA, 23 | CCPC_RAW_TERMINAL_CHANGE, 24 | CCPC_RAW_MESSAGE_DATA, 25 | CCPC_RAW_FEATURE_FLAGS, 26 | CCPC_RAW_FILE_REQUEST, 27 | CCPC_RAW_FILE_RESPONSE, 28 | CCPC_RAW_FILE_DATA 29 | }; 30 | 31 | enum { 32 | CCPC_RAW_FILE_REQUEST_EXISTS = 0, 33 | CCPC_RAW_FILE_REQUEST_ISDIR, 34 | CCPC_RAW_FILE_REQUEST_ISREADONLY, 35 | CCPC_RAW_FILE_REQUEST_GETSIZE, 36 | CCPC_RAW_FILE_REQUEST_GETDRIVE, 37 | CCPC_RAW_FILE_REQUEST_GETCAPACITY, 38 | CCPC_RAW_FILE_REQUEST_GETFREESPACE, 39 | CCPC_RAW_FILE_REQUEST_LIST, 40 | CCPC_RAW_FILE_REQUEST_ATTRIBUTES, 41 | CCPC_RAW_FILE_REQUEST_FIND, 42 | CCPC_RAW_FILE_REQUEST_MAKEDIR, 43 | CCPC_RAW_FILE_REQUEST_DELETE, 44 | CCPC_RAW_FILE_REQUEST_COPY, 45 | CCPC_RAW_FILE_REQUEST_MOVE 46 | }; 47 | 48 | #define CCPC_RAW_FILE_REQUEST_OPEN 0x10 49 | #define CCPC_RAW_FILE_REQUEST_OPEN_WRITE 0x01 50 | #define CCPC_RAW_FILE_REQUEST_OPEN_APPEND 0x02 51 | #define CCPC_RAW_FILE_REQUEST_OPEN_BINARY 0x04 52 | 53 | #define CCPC_RAW_FEATURE_FLAG_BINARY_CHECKSUM 0x0001 54 | #define CCPC_RAW_FEATURE_FLAG_FILESYSTEM_SUPPORT 0x0002 55 | #define CCPC_RAW_FEATURE_FLAG_SEND_ALL_WINDOWS 0x0004 56 | #define CCPC_RAW_FEATURE_FLAG_HAS_EXTENDED_FEATURES 0x8000 57 | 58 | class RawTerminal: public Terminal { 59 | public: 60 | static uint16_t supportedFeatures; 61 | static uint32_t supportedExtendedFeatures; 62 | uint8_t computerID; 63 | static void init(); 64 | static void quit(); 65 | static void pollEvents() {defaultPollEvents();} 66 | static void showGlobalMessage(uint32_t flags, const char * title, const char * message); 67 | static void initClient(uint16_t flags, uint32_t extflags = 0); 68 | RawTerminal(std::string title, uint8_t computerID = 0); 69 | ~RawTerminal() override; 70 | void render() override; 71 | bool resize(unsigned w, unsigned h) override; 72 | void showMessage(uint32_t flags, const char * title, const char * message) override; 73 | void setLabel(std::string label) override; 74 | void onActivate() override {} 75 | }; 76 | 77 | extern void sendRawEvent(SDL_Event e); 78 | 79 | #endif -------------------------------------------------------------------------------- /resources/appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | cc.craftos-pc.CraftOS-PC 5 | MIT 6 | MIT 7 | CraftOS-PC 8 | Advanced ComputerCraft emulator 9 | 10 | 11 |

12 | CraftOS-PC is a fantasy terminal that allows you to write and run 13 | programs inside an '80s-style text console. 14 |

15 |

16 | CraftOS-PC emulates the popular Minecraft mod "ComputerCraft", which 17 | adds programmable computers to Minecraft using the Lua programming 18 | language. CraftOS-PC takes this experience outside Minecraft to allow 19 | you to run the same programs anywhere you go. 20 |

21 |

22 | CraftOS-PC provides a set of functions (called APIs) that make it super 23 | easy to do simple tasks such as write text to the screen, read files, 24 | and more. The simplicity of these functions makes CraftOS-PC great for 25 | new programmers, but their power makes it possible to write all sorts of 26 | complex programs with less code. 27 |

28 |

29 | If you aren't ready to write programs yet, there's already a large 30 | number of programs for ComputerCraft that will work in CraftOS-PC, 31 | ranging from simple games to whole graphical operating systems. These 32 | can be downloaded through the built-in Pastebin and GitHub Gist clients. 33 |

34 |
35 | 36 | CraftOS-PC.desktop 37 | 38 | 39 | 40 | https://www.craftos-pc.cc/images/image1.png 41 | 42 | 43 | https://www.craftos-pc.cc/images/cospc-raycaster.png 44 | 45 | 46 | https://www.craftos-pc.cc/images/peripherals.png 47 | 48 | 49 | https://www.craftos-pc.cc/images/multicomputer.png 50 | 51 | 52 | https://www.craftos-pc.cc/images/gfx.png 53 | 54 | 55 | https://www.craftos-pc.cc/images/debugger_demo.png 56 | 57 | 58 | 59 | https://www.craftos-pc.cc/ 60 | JackMacWindows 61 | 62 | 63 | craftos 64 | 65 |
-------------------------------------------------------------------------------- /resources/android-project/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /resources/android-project/app/build.gradle: -------------------------------------------------------------------------------- 1 | def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY'); 2 | def buildAsApplication = !buildAsLibrary 3 | if (buildAsApplication) { 4 | apply plugin: 'com.android.application' 5 | } 6 | else { 7 | apply plugin: 'com.android.library' 8 | } 9 | 10 | android { 11 | compileSdkVersion 30 12 | defaultConfig { 13 | if (buildAsApplication) { 14 | applicationId "cc.craftospc.CraftOSPC" 15 | } 16 | minSdkVersion 24 17 | targetSdkVersion 30 18 | versionCode 22 19 | versionName "2.6.6" 20 | externalNativeBuild { 21 | ndkBuild { 22 | arguments "APP_PLATFORM=android-26" 23 | abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64' 24 | } 25 | // cmake { 26 | // arguments "-DANDROID_APP_PLATFORM=android-16", "-DANDROID_STL=c++_static" 27 | // // abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' 28 | // abiFilters 'arm64-v8a' 29 | // } 30 | } 31 | } 32 | buildTypes { 33 | release { 34 | minifyEnabled false 35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 36 | } 37 | } 38 | if (!project.hasProperty('EXCLUDE_NATIVE_LIBS')) { 39 | /*sourceSets.main { 40 | jniLibs.srcDir "${projectDir}/jniLibs" 41 | }*/ 42 | /*externalNativeBuild { 43 | ndkBuild { 44 | path 'jni/Android.mk' 45 | } 46 | // cmake { 47 | // path 'jni/CMakeLists.txt' 48 | // } 49 | }*/ 50 | 51 | } 52 | lintOptions { 53 | abortOnError false 54 | } 55 | 56 | if (buildAsLibrary) { 57 | libraryVariants.all { variant -> 58 | variant.outputs.each { output -> 59 | def outputFile = output.outputFile 60 | if (outputFile != null && outputFile.name.endsWith(".aar")) { 61 | def fileName = "org.libsdl.app.aar"; 62 | output.outputFile = new File(outputFile.parent, fileName); 63 | } 64 | } 65 | } 66 | } 67 | 68 | compileOptions { 69 | sourceCompatibility 1.8 70 | targetCompatibility 1.8 71 | } 72 | ndkVersion '24.0.8215888' 73 | } 74 | 75 | dependencies { 76 | implementation fileTree(include: ['*.jar'], dir: 'libs') 77 | implementation 'androidx.core:core:1.1.0' 78 | implementation 'androidx.appcompat:appcompat:1.1.0' 79 | implementation 'com.google.android.material:material:1.1.0' 80 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 81 | implementation 'com.mapbox.mapboxsdk:mapbox-android-gestures:0.7.0' 82 | } 83 | -------------------------------------------------------------------------------- /src/peripheral/debugger.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/debugger.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the class for the debugger peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef PERIPHERAL_DEBUGGER_HPP 12 | #define PERIPHERAL_DEBUGGER_HPP 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define DEBUGGER_BREAK_TYPE_NONSTOP 0 22 | #define DEBUGGER_BREAK_TYPE_LINE 1 23 | #define DEBUGGER_BREAK_TYPE_RETURN 2 24 | 25 | #define DEBUGGER_BREAK_FUNC_ERROR 1 26 | #define DEBUGGER_BREAK_FUNC_LOAD 2 27 | #define DEBUGGER_BREAK_FUNC_RUN 4 28 | #define DEBUGGER_BREAK_FUNC_RESUME 8 29 | #define DEBUGGER_BREAK_FUNC_YIELD 16 30 | 31 | class debugger: public peripheral { 32 | friend int debugger_lib_getInfo(lua_State *L); 33 | friend void debuggerThread(Computer*, void*, std::string); 34 | friend void forwardInput(); 35 | friend class DAPConnection; 36 | private: 37 | bool deleteThis = false; 38 | int _break(lua_State *L); 39 | int setBreakpoint(lua_State *L); 40 | int print(lua_State *L); 41 | void init(Computer * comp); 42 | int _deinit(lua_State *L); 43 | library_t * createDebuggerLibrary(); 44 | static library_t methods; 45 | protected: 46 | std::thread * compThread = NULL; 47 | Computer * monitor = NULL; 48 | public: 49 | struct profile_entry { 50 | bool running; 51 | unsigned long count; 52 | std::chrono::high_resolution_clock::time_point start; 53 | std::chrono::high_resolution_clock::duration time; 54 | }; 55 | std::atomic_bool running; 56 | Computer * computer; 57 | int breakType = DEBUGGER_BREAK_TYPE_NONSTOP; 58 | int stepCount = 0; 59 | int breakMask = 0; 60 | std::string breakFunc; 61 | bool didBreak = false; 62 | bool confirmBreak = false; 63 | bool waitingForBreak = false; 64 | std::string breakReason; 65 | std::mutex breakMutex; 66 | std::condition_variable breakNotify; 67 | lua_State * volatile thread = NULL; 68 | std::unordered_map > profile; 69 | bool isProfiling = false; 70 | static peripheral * _init(lua_State *L, const char * side) {return new debugger(L, side);} 71 | static void deinit(peripheral * p) {delete (debugger*)p;} 72 | virtual destructor getDestructor() const override {return deinit;} 73 | debugger(lua_State *L, const char * side); 74 | virtual ~debugger(); 75 | virtual int call(lua_State *L, const char * method) override; 76 | library_t getMethods() const override {return methods;} 77 | void reinitialize(lua_State *L) override; 78 | void resetMounts(); 79 | }; 80 | 81 | #endif -------------------------------------------------------------------------------- /src/termsupport.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * termsupport.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines some functions that interact with the terminal. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef TERMSUPPORT_HPP 12 | #define TERMSUPPORT_HPP 13 | #include 14 | #include "peripheral/monitor.hpp" 15 | #include "terminal/SDLTerminal.hpp" 16 | #include "util.hpp" 17 | 18 | #ifdef __APPLE__ 19 | #define KMOD_LSYSMOD KMOD_LGUI 20 | #define KMOD_RSYSMOD KMOD_RGUI 21 | #define KMOD_SYSMOD KMOD_GUI 22 | #else 23 | #define KMOD_LSYSMOD KMOD_LCTRL 24 | #define KMOD_RSYSMOD KMOD_RCTRL 25 | #define KMOD_SYSMOD KMOD_CTRL 26 | #endif 27 | 28 | extern std::thread * renderThread; 29 | extern std::unordered_set orphanedTerminals; 30 | extern std::atomic_bool taskQueueReady; 31 | extern std::condition_variable taskQueueNotify; 32 | extern std::unordered_map keymap; 33 | extern std::unordered_map keymap_cli; 34 | extern Uint32 task_event_type; 35 | extern Uint32 render_event_type; 36 | extern bool singleWindowMode; 37 | extern std::list renderTargets; 38 | extern std::mutex renderTargetsLock; 39 | extern std::list::iterator renderTarget; 40 | extern std::set currentWindowIDs; 41 | extern std::vector terminalFactories; 42 | 43 | extern Terminal * createTerminal(const std::string& title); 44 | extern std::string termGetEvent(lua_State *L); 45 | extern int convertX(SDLTerminal *term, int x); 46 | extern int convertY(SDLTerminal *term, int y); 47 | extern void termRenderLoop(); 48 | extern void termHook(lua_State *L, lua_Debug *ar); 49 | extern int termPanic(lua_State *L); 50 | extern monitor * findMonitorFromWindowID(Computer *comp, unsigned id, std::string* sideReturn); 51 | extern void displayFailure(Terminal * term, const std::string& message, const std::string& extra = ""); 52 | 53 | inline bool checkWindowID(Computer * c, unsigned wid) { 54 | if (singleWindowMode) return c->term == *renderTarget || findMonitorFromWindowID(c, (*renderTarget)->id, NULL) != NULL; 55 | return wid == c->term->id || findMonitorFromWindowID(c, wid, NULL) != NULL; 56 | } 57 | 58 | inline std::list::iterator& nextRenderTarget() { 59 | std::lock_guard lock(renderTargetsLock); 60 | if (++renderTarget == renderTargets.end()) renderTarget = renderTargets.begin(); 61 | (*renderTarget)->changed = true; 62 | (*renderTarget)->onActivate(); 63 | return renderTarget; 64 | } 65 | 66 | inline std::list::iterator& previousRenderTarget() { 67 | std::lock_guard lock(renderTargetsLock); 68 | if (renderTarget == renderTargets.begin()) renderTarget = renderTargets.end(); 69 | --renderTarget; 70 | (*renderTarget)->changed = true; 71 | (*renderTarget)->onActivate(); 72 | return renderTarget; 73 | } 74 | 75 | #endif -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "array": "cpp", 4 | "*.tcc": "cpp", 5 | "cctype": "cpp", 6 | "chrono": "cpp", 7 | "clocale": "cpp", 8 | "cmath": "cpp", 9 | "cstdarg": "cpp", 10 | "cstdint": "cpp", 11 | "cstdio": "cpp", 12 | "cstdlib": "cpp", 13 | "ctime": "cpp", 14 | "cwchar": "cpp", 15 | "cwctype": "cpp", 16 | "deque": "cpp", 17 | "unordered_map": "cpp", 18 | "vector": "cpp", 19 | "exception": "cpp", 20 | "fstream": "cpp", 21 | "initializer_list": "cpp", 22 | "iosfwd": "cpp", 23 | "istream": "cpp", 24 | "limits": "cpp", 25 | "new": "cpp", 26 | "optional": "cpp", 27 | "ostream": "cpp", 28 | "ratio": "cpp", 29 | "sstream": "cpp", 30 | "stdexcept": "cpp", 31 | "streambuf": "cpp", 32 | "string_view": "cpp", 33 | "system_error": "cpp", 34 | "cinttypes": "cpp", 35 | "type_traits": "cpp", 36 | "tuple": "cpp", 37 | "typeinfo": "cpp", 38 | "utility": "cpp", 39 | "algorithm": "cpp", 40 | "__bit_reference": "cpp", 41 | "__debug": "cpp", 42 | "__functional_base": "cpp", 43 | "__nullptr": "cpp", 44 | "__split_buffer": "cpp", 45 | "bit": "cpp", 46 | "cstddef": "cpp", 47 | "cstring": "cpp", 48 | "queue": "cpp", 49 | "functional": "cpp", 50 | "iterator": "cpp", 51 | "memory": "cpp", 52 | "random": "cpp", 53 | "__config": "cpp", 54 | "__errc": "cpp", 55 | "__hash_table": "cpp", 56 | "__locale": "cpp", 57 | "__mutex_base": "cpp", 58 | "__node_handle": "cpp", 59 | "__string": "cpp", 60 | "__threading_support": "cpp", 61 | "__tree": "cpp", 62 | "__tuple": "cpp", 63 | "atomic": "cpp", 64 | "bitset": "cpp", 65 | "iomanip": "cpp", 66 | "ios": "cpp", 67 | "iostream": "cpp", 68 | "list": "cpp", 69 | "locale": "cpp", 70 | "map": "cpp", 71 | "mutex": "cpp", 72 | "numeric": "cpp", 73 | "set": "cpp", 74 | "stack": "cpp", 75 | "string": "cpp", 76 | "strstream": "cpp", 77 | "thread": "cpp", 78 | "typeindex": "cpp", 79 | "variant": "cpp", 80 | "codecvt": "cpp", 81 | "condition_variable": "cpp", 82 | "regex": "cpp", 83 | "csignal": "cpp", 84 | "unordered_set": "cpp", 85 | "memory_resource": "cpp", 86 | "complex": "cpp", 87 | "shared_mutex": "cpp", 88 | "cfenv": "cpp", 89 | "future": "cpp", 90 | "valarray": "cpp", 91 | "csetjmp": "cpp" 92 | }, 93 | "C_Cpp.default.cppStandard": "c++14", 94 | "C_Cpp.default.cStandard": "c11", 95 | "lldb.displayFormat": "auto", 96 | "lldb.showDisassembly": "auto", 97 | "lldb.dereferencePointers": true 98 | } -------------------------------------------------------------------------------- /src/runtime.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * runtime.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines some common methods for the CraftOS-PC runtime. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef RUNTIME_HPP 12 | #define RUNTIME_HPP 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "util.hpp" 18 | 19 | struct TaskQueueItem { 20 | std::function func; 21 | void* data = NULL; 22 | bool async = false; 23 | bool ready = false; 24 | std::mutex lock; 25 | std::condition_variable notify; 26 | std::exception_ptr exception = nullptr; 27 | }; 28 | 29 | extern ProtectedObject > computers; 30 | extern ProtectedObject > freedTimers; 31 | extern ProtectedObject > taskQueue; 32 | extern bool exiting; 33 | extern int selectedRenderer; 34 | extern std::unordered_map customDataDirs; 35 | extern std::list customPlugins; 36 | extern std::list > customMounts; 37 | extern path_t computerDir; 38 | extern std::unordered_set freedComputers; 39 | extern std::list computerThreads; 40 | extern std::thread::id mainThreadID; 41 | extern bool listenerMode; 42 | extern std::mutex listenerModeMutex; 43 | extern std::condition_variable listenerModeNotify; 44 | 45 | extern int getNextEvent(lua_State* L, const std::string& filter); 46 | extern void* queueTask(const std::function& func, void* arg, bool async = false); 47 | extern void runComputer(Computer * self, const path_t& bios_name, const std::string& bios_data = ""); 48 | extern bool Computer_getEvent(Computer * self, SDL_Event* e); 49 | extern Uint32 eventTimeoutEvent(Uint32 interval, void* param); 50 | extern void* computerThread(void* data); 51 | extern Computer* startComputer(int id); 52 | extern void queueEvent(Computer *comp, const event_provider& p, void* data); 53 | extern bool addMount(Computer *comp, const path_t& real_path, const std::string& comp_path, bool read_only); 54 | extern bool addVirtualMount(Computer * comp, const FileEntry& vfs, const std::string& comp_path); 55 | extern void registerPeripheral(const std::string& name, const peripheral_init_fn& initializer); 56 | extern void registerSDLEvent(SDL_EventType type, const sdl_event_handler& handler, void* userdata); 57 | extern void pumpTaskQueue(); 58 | extern void defaultPollEvents(); 59 | extern void mainLoop(); 60 | extern void preloadPlugins(); 61 | extern std::unordered_map initializePlugins(); 62 | extern void loadPlugins(Computer * comp); 63 | extern void deinitializePlugins(); 64 | extern void unloadPlugins(); 65 | extern void stopWebsocket(void*); 66 | extern peripheral* attachPeripheral(Computer * computer, const std::string& side, const std::string& type, std::string * errorReturn, const char * format, ...); 67 | extern bool detachPeripheral(Computer * computer, const std::string& side); 68 | extern void addEventHook(const std::string& event, Computer * computer, const event_hook& hook, void* userdata); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/peripheral/chest.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/chest.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the methods for the chest peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include "chest.hpp" 12 | 13 | int chest::size() { 14 | if (isDouble) return 54; 15 | else return 27; 16 | } 17 | 18 | void chest::getItemDetail(lua_State *L, int slot) { 19 | if (slot < 1 || slot > (isDouble ? 54 : 27)) {lua_pushnil(L); return;} 20 | if (items[slot-1].count == 0) {lua_pushnil(L); return;} 21 | lua_createtable(L, 0, 2); 22 | lua_pushlstring(L, items[slot-1].name.c_str(), items[slot-1].name.size()); 23 | lua_setfield(L, -2, "name"); 24 | lua_pushinteger(L, items[slot-1].count); 25 | lua_setfield(L, -2, "count"); 26 | } 27 | 28 | int chest::addItems(lua_State *L, int slot, int count) { 29 | lua_getfield(L, -1, "name"); 30 | if (!lua_isstring(L, -1)) { 31 | lua_pop(L, 1); 32 | return 0; 33 | } 34 | std::string name = tostring(L, -1); 35 | lua_pop(L, 1); 36 | if (slot == 0) for (slot = 1; slot <= (isDouble ? 54 : 27) && items[slot-1].count > 0 && items[slot-1].name != name; slot++); 37 | if (slot < 0 || slot > (isDouble ? 54 : 27) || (items[slot-1].name != name && !items[slot-1].name.empty())) return 0; 38 | uint8_t d = min(items[slot-1].count + count, 64) - items[slot-1].count; 39 | if (d > 0) items[slot-1].name = name; 40 | items[slot-1].count += d; 41 | return d; 42 | } 43 | 44 | int chest::removeItems(int slot, int count) { 45 | if (slot < 0 || slot > (isDouble ? 54 : 27) || count <= 0) return 0; 46 | count = min(count, (int)items[slot-1].count); 47 | items[slot-1].count -= count; 48 | if (items[slot-1].count == 0) items[slot-1].name = ""; 49 | return count; 50 | } 51 | 52 | int chest::setItem(lua_State *L) { 53 | int slot = luaL_checknumber(L, 1); 54 | luaL_checktype(L, 2, LUA_TTABLE); 55 | lua_getfield(L, 2, "name"); 56 | if (!lua_isstring(L, -1)) luaL_error(L, "bad field 'name' (expected string, got %s)", lua_typename(L, lua_type(L, -1))); 57 | lua_pop(L, 1); 58 | lua_getfield(L, 2, "count"); 59 | if (!lua_isnumber(L, -1)) luaL_error(L, "bad field 'count' (expected number, got %s)", lua_typename(L, lua_type(L, -1))); 60 | int count = lua_tointeger(L, -1); 61 | lua_settop(L, 2); 62 | lua_pushinteger(L, addItems(L, slot, count)); 63 | return 1; 64 | } 65 | 66 | chest::chest(lua_State *L, const char * side) { 67 | if (lua_toboolean(L, 3)) isDouble = true; 68 | } 69 | 70 | chest::~chest() {} 71 | 72 | int chest::call(lua_State *L, const char * method) { 73 | const std::string m(method); 74 | if (m == "setItem") return setItem(L); 75 | else return inventory::call(L, method); 76 | } 77 | 78 | static luaL_Reg chest_reg[] = { 79 | {"size", NULL}, 80 | {"list", NULL}, 81 | {"getItemDetail", NULL}, 82 | {"pushItems", NULL}, 83 | {"pullItems", NULL}, 84 | {"setItem", NULL}, 85 | {NULL, NULL} 86 | }; 87 | 88 | library_t chest::methods = {"!!MULTITYPE", chest_reg, nullptr, nullptr}; 89 | std::vector chest::types = {"minecraft:chest", "inventory", "chest"}; 90 | -------------------------------------------------------------------------------- /src/platform/CraftOS-PC 2.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #pragma code_page(65001) 4 | 5 | #include "resource.h" 6 | 7 | #define APSTUDIO_READONLY_SYMBOLS 8 | ///////////////////////////////////////////////////////////////////////////// 9 | // 10 | // Generated from the TEXTINCLUDE 2 resource. 11 | // 12 | #include "winres.h" 13 | 14 | ///////////////////////////////////////////////////////////////////////////// 15 | #undef APSTUDIO_READONLY_SYMBOLS 16 | 17 | ///////////////////////////////////////////////////////////////////////////// 18 | // English (United States) resources 19 | 20 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 21 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 22 | 23 | #ifdef APSTUDIO_INVOKED 24 | ///////////////////////////////////////////////////////////////////////////// 25 | // 26 | // TEXTINCLUDE 27 | // 28 | 29 | 1 TEXTINCLUDE 30 | BEGIN 31 | "resource.h\0" 32 | END 33 | 34 | 2 TEXTINCLUDE 35 | BEGIN 36 | "#include ""winres.h""\r\n" 37 | "\0" 38 | END 39 | 40 | 3 TEXTINCLUDE 41 | BEGIN 42 | "\r\n" 43 | "\0" 44 | END 45 | 46 | #endif // APSTUDIO_INVOKED 47 | 48 | 49 | ///////////////////////////////////////////////////////////////////////////// 50 | // 51 | // RT_MANIFEST 52 | // 53 | 54 | MANIFEST RT_MANIFEST "..\\..\\resources\\CraftOS-PC.exe.manifest" 55 | 56 | 57 | ///////////////////////////////////////////////////////////////////////////// 58 | // 59 | // Version 60 | // 61 | 62 | VS_VERSION_INFO VERSIONINFO 63 | FILEVERSION 2,8,3,0 64 | PRODUCTVERSION 2,8,3,0 65 | FILEFLAGSMASK 0x3fL 66 | #ifdef _DEBUG 67 | FILEFLAGS 0x1L 68 | #else 69 | FILEFLAGS 0x0L 70 | #endif 71 | FILEOS 0x40004L 72 | FILETYPE 0x1L 73 | FILESUBTYPE 0x0L 74 | BEGIN 75 | BLOCK "StringFileInfo" 76 | BEGIN 77 | BLOCK "040904b0" 78 | BEGIN 79 | VALUE "FileDescription", "CraftOS-PC" 80 | VALUE "FileVersion", "2.8.3.0" 81 | VALUE "InternalName", "CraftOS-PC.exe" 82 | VALUE "LegalCopyright", "Copyright (C) 2019-2024 JackMacWindows." 83 | VALUE "OriginalFilename", "CraftOS-PC.exe" 84 | VALUE "ProductName", "CraftOS-PC" 85 | VALUE "ProductVersion", "2.8.3.0" 86 | END 87 | END 88 | BLOCK "VarFileInfo" 89 | BEGIN 90 | VALUE "Translation", 0x409, 1200 91 | END 92 | END 93 | 94 | 95 | ///////////////////////////////////////////////////////////////////////////// 96 | // 97 | // Icon 98 | // 99 | 100 | // Icon with lowest ID value placed first to ensure application icon 101 | // remains consistent on all systems. 102 | IDI_ICON1 ICON "..\\..\\resources\\CraftOS-PC.ico" 103 | 104 | #endif // English (United States) resources 105 | ///////////////////////////////////////////////////////////////////////////// 106 | 107 | 108 | 109 | #ifndef APSTUDIO_INVOKED 110 | ///////////////////////////////////////////////////////////////////////////// 111 | // 112 | // Generated from the TEXTINCLUDE 3 resource. 113 | // 114 | 115 | 116 | ///////////////////////////////////////////////////////////////////////////// 117 | #endif // not APSTUDIO_INVOKED 118 | 119 | -------------------------------------------------------------------------------- /src/gif.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * gif.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines some functions from gif.cpp for external use. 6 | * 7 | * This code is licensed in the public domain. 8 | * Copyright (c) 2019-2024 JackMacWindows, Charlie Tangora. 9 | */ 10 | 11 | #ifndef gif_h 12 | #define gif_h 13 | 14 | #include 15 | #include 16 | 17 | struct GifPalette 18 | { 19 | int bitDepth; 20 | 21 | uint8_t r[256]; 22 | uint8_t g[256]; 23 | uint8_t b[256]; 24 | 25 | // k-d tree over RGB space, organized in heap fashion 26 | // i.e. left child of node i is node i*2, right child is node i*2+1 27 | // nodes 256-511 are implicitly the leaves, containing a color 28 | uint8_t treeSplitElt[255]; 29 | uint8_t treeSplit[255]; 30 | }; 31 | 32 | extern void GifGetClosestPaletteColor(GifPalette* pPal, int r, int g, int b, int& bestInd, int& bestDiff, int treeRoot = 1); 33 | extern void GifSwapPixels(uint8_t* image, int pixA, int pixB); 34 | extern int GifPartition(uint8_t* image, const int left, const int right, const int elt, int pivotIndex); 35 | extern void GifPartitionByMedian(uint8_t* image, int left, int right, int com, int neededCenter); 36 | extern void GifSplitPalette(uint8_t* image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette* pal); 37 | extern int GifPickChangedPixels( const uint8_t* lastFrame, uint8_t* frame, int numPixels ); 38 | extern void GifMakePalette( const uint8_t* lastFrame, const uint8_t* nextFrame, uint32_t width, uint32_t height, int bitDepth, bool buildForDither, GifPalette* pPal ); 39 | extern void GifDitherImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal ); 40 | extern void GifThresholdImage( const uint8_t* lastFrame, const uint8_t* nextFrame, uint8_t* outFrame, uint32_t width, uint32_t height, GifPalette* pPal ); 41 | 42 | // Simple structure to write out the LZW-compressed portion of the image 43 | // one bit at a time 44 | struct GifBitStatus 45 | { 46 | uint8_t bitIndex; // how many bits in the partial byte written so far 47 | uint8_t byte; // current partial byte 48 | 49 | uint32_t chunkIndex; 50 | uint8_t chunk[256]; // bytes are written in here until we have 256 of them, then written to the file 51 | }; 52 | 53 | extern void GifWriteBit( GifBitStatus& stat, uint32_t bit ); 54 | extern void GifWriteChunk( FILE* f, GifBitStatus& stat ); 55 | extern void GifWriteCode( FILE* f, GifBitStatus& stat, uint32_t code, uint32_t length ); 56 | 57 | // The LZW dictionary is a 256-ary tree constructed as the file is encoded, 58 | // this is one node 59 | struct GifLzwNode 60 | { 61 | uint16_t m_next[256]; 62 | }; 63 | 64 | extern void GifWritePalette( const GifPalette* pPal, FILE* f ); 65 | extern void GifWriteLzwImage(FILE* f, uint8_t* image, uint32_t left, uint32_t top, uint32_t width, uint32_t height, uint32_t delay, GifPalette* pPal); 66 | 67 | struct GifWriter 68 | { 69 | FILE* f; 70 | uint8_t* oldImage; 71 | bool firstFrame; 72 | }; 73 | 74 | extern bool GifBegin( GifWriter* writer, const char* filename, uint32_t width, uint32_t height, uint32_t delay, int32_t bitDepth = 8, bool dither = false ); 75 | extern bool GifWriteFrame( GifWriter* writer, const uint8_t* image, uint32_t width, uint32_t height, uint32_t delay, int bitDepth = 8, bool dither = false, uint32_t * palette = NULL ); 76 | extern bool GifEnd( GifWriter* writer ); 77 | 78 | #endif -------------------------------------------------------------------------------- /api/generic_peripheral/fluid_storage.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * generic_peripheral/fluid_storage.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines a generic peripheral class for tank-like peripherals 6 | * to inherit from. 7 | * 8 | * This code is licensed under the MIT license. 9 | * Copyright (c) 2019-2024 JackMacWindows. 10 | */ 11 | 12 | #ifndef CRAFTOS_PC_GENERIC_PERIPHERAL_FLUID_STORAGE_HPP 13 | #define CRAFTOS_PC_GENERIC_PERIPHERAL_FLUID_STORAGE_HPP 14 | #include "../Computer.hpp" 15 | #include "../peripheral.hpp" 16 | 17 | class fluid_storage : public peripheral { 18 | protected: 19 | virtual int tanks(lua_State *L) = 0; // Implements tanks() as a Lua function: https://tweaked.cc/generic_peripheral/fluid_storage.html#v:tanks 20 | virtual int addFluid(const std::string& fluid, int amount) = 0; // Adds the specified amount of fluid to a tank. Returns the amount actually added. 21 | virtual std::list> removeFluid(const std::string& fluid, int amount) = 0; // Removes the specified amount of fluid from a tank. If fluid is empty, remove any type of fluid; otherwise only remove that type. Returns a list of each fluid type & amount removed. (If no fluid is removed, return an empty list.) 22 | public: 23 | virtual int call(lua_State *L, const char * method) override { 24 | const std::string m(method); 25 | if (m == "tanks") return tanks(L); 26 | else if (m == "pushFluid" || m == "pullFluid") { 27 | Computer * comp = get_comp(L); 28 | const char * side = luaL_checkstring(L, 1); 29 | const int limit = luaL_optinteger(L, 2, INT_MAX); 30 | const std::string name = luaL_optstring(L, 3, ""); 31 | 32 | if (comp->peripherals.find(side) == comp->peripherals.end()) return luaL_error(L, "Target '%s' does not exist", side); 33 | fluid_storage * p = dynamic_cast(comp->peripherals[side]); 34 | if (p == NULL) return luaL_error(L, "Target '%s' is not an tank", side); // grammar mistake intentional 35 | fluid_storage *src, *dest; 36 | if (m == "pushFluid") src = this, dest = p; 37 | else src = p, dest = this; 38 | if (limit <= 0) return luaL_error(L, "Limit must be > 0"); 39 | 40 | const auto removed = src->removeFluid(name, limit); 41 | if (removed.empty()) { 42 | lua_pushinteger(L, 0); 43 | return 1; 44 | } 45 | int added = 0; 46 | std::list> returnedFluid; 47 | for (const std::pair& type : removed) { 48 | const int add = dest->addFluid(type.first, type.second); 49 | added += add; 50 | if (add < type.second) returnedFluid.push_back(std::make_pair(type.first, type.second - add)); 51 | } 52 | for (const std::pair& type : returnedFluid) src->addFluid(type.first, type.second); 53 | 54 | lua_pushinteger(L, added); 55 | return 1; 56 | } else return luaL_error(L, "No such method"); 57 | } 58 | void update() override {} 59 | library_t getMethods() const override { 60 | static luaL_Reg reg[] = { 61 | {"tanks", NULL}, 62 | {"pushFluid", NULL}, 63 | {"pullFluid", NULL}, 64 | {NULL, NULL} 65 | }; 66 | static library_t methods = {"fluid_storage", reg, nullptr, nullptr}; 67 | return methods; 68 | } 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /resources/android-project/.idea/modules/app/craftos2-android.app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /resources/android-project/app/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 23 | 26 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 55 | 60 | 61 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /resources/android-project/app/src/main/java/org/libsdl/app/SDL.java: -------------------------------------------------------------------------------- 1 | package org.libsdl.app; 2 | 3 | import android.content.Context; 4 | 5 | import java.lang.Class; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | SDL library initialization 10 | */ 11 | public class SDL { 12 | 13 | // This function should be called first and sets up the native code 14 | // so it can call into the Java classes 15 | public static void setupJNI() { 16 | SDLActivity.nativeSetupJNI(); 17 | SDLAudioManager.nativeSetupJNI(); 18 | SDLControllerManager.nativeSetupJNI(); 19 | } 20 | 21 | // This function should be called each time the activity is started 22 | public static void initialize() { 23 | setContext(null); 24 | 25 | SDLActivity.initialize(); 26 | SDLAudioManager.initialize(); 27 | SDLControllerManager.initialize(); 28 | } 29 | 30 | // This function stores the current activity (SDL or not) 31 | public static void setContext(Context context) { 32 | mContext = context; 33 | } 34 | 35 | public static Context getContext() { 36 | return mContext; 37 | } 38 | 39 | public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException { 40 | 41 | if (libraryName == null) { 42 | throw new NullPointerException("No library name provided."); 43 | } 44 | 45 | try { 46 | // Let's see if we have ReLinker available in the project. This is necessary for 47 | // some projects that have huge numbers of local libraries bundled, and thus may 48 | // trip a bug in Android's native library loader which ReLinker works around. (If 49 | // loadLibrary works properly, ReLinker will simply use the normal Android method 50 | // internally.) 51 | // 52 | // To use ReLinker, just add it as a dependency. For more information, see 53 | // https://github.com/KeepSafe/ReLinker for ReLinker's repository. 54 | // 55 | Class relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker"); 56 | Class relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener"); 57 | Class contextClass = mContext.getClassLoader().loadClass("android.content.Context"); 58 | Class stringClass = mContext.getClassLoader().loadClass("java.lang.String"); 59 | 60 | // Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if 61 | // they've changed during updates. 62 | Method forceMethod = relinkClass.getDeclaredMethod("force"); 63 | Object relinkInstance = forceMethod.invoke(null); 64 | Class relinkInstanceClass = relinkInstance.getClass(); 65 | 66 | // Actually load the library! 67 | Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass); 68 | loadMethod.invoke(relinkInstance, mContext, libraryName, null, null); 69 | } 70 | catch (final Throwable e) { 71 | // Fall back 72 | try { 73 | System.loadLibrary(libraryName); 74 | } 75 | catch (final UnsatisfiedLinkError ule) { 76 | throw ule; 77 | } 78 | catch (final SecurityException se) { 79 | throw se; 80 | } 81 | } 82 | } 83 | 84 | protected static Context mContext; 85 | } 86 | -------------------------------------------------------------------------------- /src/terminal/SDLTerminal.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * terminal/SDLTerminal.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the SDLTerminal class, which is the default renderer. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef TERMINAL_SDLTERMINAL_HPP 12 | #define TERMINAL_SDLTERMINAL_HPP 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "../platform.hpp" 21 | 22 | inline SDL_Rect * setRect(SDL_Rect * rect, int x, int y, int w, int h) { 23 | rect->x = x; 24 | rect->y = y; 25 | rect->w = w; 26 | rect->h = h; 27 | return rect; 28 | } 29 | 30 | class SDLTerminal: public Terminal { 31 | friend void mainLoop(); 32 | friend int termPanic(lua_State *L); 33 | friend int runRenderer(const std::function& read, const std::function& write); 34 | friend class HardwareSDLTerminal; 35 | protected: 36 | bool shouldScreenshot = false; 37 | bool shouldRecord = false; 38 | bool fullscreen = false; 39 | path_t screenshotPath; 40 | path_t recordingPath; 41 | int recordedFrames = 0; 42 | int frameWait = 0; 43 | void * recorderHandle = NULL; 44 | std::mutex recorderMutex; 45 | std::mutex renderlock; 46 | bool overridden = false; 47 | int realWidth = 620; 48 | int realHeight = 350; 49 | public: 50 | static unsigned fontScale; 51 | unsigned charScale = 2; 52 | unsigned dpiScale = 1; 53 | unsigned charWidth = fontWidth * charScale; 54 | unsigned charHeight = fontHeight * charScale; 55 | int lastFPS = 0; 56 | int currentFPS = 0; 57 | time_t lastSecond = time(0); 58 | std::chrono::system_clock::time_point lastScreenshotTime; 59 | unsigned char cursorColor = 0; 60 | bool useOrigFont = false; 61 | bool isOnTop = false; 62 | bool isRecordingWebP = false; 63 | std::mutex mouseMoveLock; 64 | std::vector>> fingers; 65 | int nFingers = 0; 66 | 67 | static void init(); 68 | static void quit(); 69 | static bool pollEvents(); 70 | SDLTerminal(std::string title); 71 | ~SDLTerminal() override; 72 | void setPalette(Color * p); 73 | virtual void setCharScale(int scale); 74 | virtual bool drawChar(unsigned char c, int x, int y, Color fg, Color bg, bool transparent = false); 75 | void render() override; 76 | bool resize(unsigned w, unsigned h) override; 77 | void getMouse(int *x, int *y); 78 | void screenshot(std::string path = ""); // asynchronous; captures on next render 79 | void record(std::string path = ""); // asynchronous; captures on next render 80 | void stopRecording(); 81 | void toggleRecording() { if (shouldRecord) stopRecording(); else record(); } 82 | void showMessage(uint32_t flags, const char * title, const char * message) override; 83 | void toggleFullscreen(); 84 | void setLabel(std::string label) override; 85 | void onActivate() override; 86 | virtual bool resizeWholeWindow(int w, int h); 87 | 88 | SDL_Window *win; 89 | static SDL_Window *singleWin; 90 | static std::unordered_multimap > eventHandlers; 91 | protected: 92 | friend void registerSDLEvent(SDL_EventType type, const sdl_event_handler& handler, void* userdata); 93 | friend int main(int argc, char*argv[]); 94 | SDL_Surface *surf = NULL; 95 | static SDL_Surface *bmp; 96 | static SDL_Surface *origfont; 97 | static Uint32 lastWindow; 98 | 99 | SDL_Rect getCharacterRect(unsigned char c); 100 | }; 101 | #endif 102 | -------------------------------------------------------------------------------- /src/peripheral/computer_p.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/computer.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the methods for the computer peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include 12 | #include 13 | #include "computer.hpp" 14 | #include "../runtime.hpp" 15 | 16 | int computer::turnOn(lua_State *L) {return 0;} 17 | 18 | int computer::isOn(lua_State *L) { 19 | lastCFunction = __func__; 20 | lua_pushboolean(L, freedComputers.find(comp) == freedComputers.end()); 21 | return 1; 22 | } 23 | 24 | int computer::getID(lua_State *L) { 25 | lastCFunction = __func__; 26 | if (freedComputers.find(comp) != freedComputers.end()) return 0; 27 | lua_pushinteger(L, comp->id); 28 | return 1; 29 | } 30 | 31 | int computer::shutdown(lua_State *L) { 32 | lastCFunction = __func__; 33 | if (freedComputers.find(comp) != freedComputers.end()) return 0; 34 | comp->running = 0; 35 | return 0; 36 | } 37 | 38 | int computer::reboot(lua_State *L) { 39 | lastCFunction = __func__; 40 | if (freedComputers.find(comp) != freedComputers.end()) return 0; 41 | comp->running = 2; 42 | return 0; 43 | } 44 | 45 | int computer::getLabel(lua_State *L) { 46 | lastCFunction = __func__; 47 | if (freedComputers.find(comp) != freedComputers.end()) return 0; 48 | lua_pushlstring(L, comp->config->label.c_str(), comp->config->label.length()); 49 | return 1; 50 | } 51 | 52 | computer::computer(lua_State *L, const char * side) { 53 | if (SDL_GetCurrentVideoDriver() != NULL && (std::string(SDL_GetCurrentVideoDriver()) == "KMSDRM" || std::string(SDL_GetCurrentVideoDriver()) == "KMSDRM_LEGACY")) 54 | throw std::runtime_error("Computers are not available when using the Linux framebuffer"); 55 | if (strlen(side) < 10 || std::string(side).substr(0, 9) != "computer_" || (strlen(side) > 9 && !std::all_of(side + 9, side + strlen(side), ::isdigit))) 56 | throw std::invalid_argument("\"side\" parameter must be a number (the computer's ID)"); 57 | int id = std::stoi(std::string(&side[9])); 58 | comp = NULL; 59 | { 60 | LockGuard lock(computers); 61 | for (Computer * c : *computers) if (c->id == id) comp = c; 62 | } 63 | if (comp == NULL) comp = (Computer*)queueTask([ ](void* arg)->void*{return startComputer(*(int*)arg);}, &id); 64 | if (comp == NULL) throw std::runtime_error("Failed to open computer"); 65 | thiscomp = get_comp(L); 66 | comp->referencers.push_back(thiscomp); 67 | } 68 | 69 | computer::~computer() { 70 | if (thiscomp->peripherals_mutex.try_lock()) thiscomp->peripherals_mutex.unlock(); 71 | else return; 72 | for (auto it = comp->referencers.begin(); it != comp->referencers.end(); ++it) { 73 | if (*it == thiscomp) { 74 | it = comp->referencers.erase(it); 75 | if (it == comp->referencers.end()) break; 76 | } 77 | } 78 | } 79 | 80 | int computer::call(lua_State *L, const char * method) { 81 | const std::string m(method); 82 | if (m == "turnOn") return turnOn(L); 83 | else if (m == "shutdown") return shutdown(L); 84 | else if (m == "reboot") return reboot(L); 85 | else if (m == "getID") return getID(L); 86 | else if (m == "isOn") return isOn(L); 87 | else if (m == "getLabel") return getLabel(L); 88 | else return luaL_error(L, "No such method"); 89 | } 90 | 91 | static luaL_Reg computer_reg[] = { 92 | {"turnOn", NULL}, 93 | {"shutdown", NULL}, 94 | {"reboot", NULL}, 95 | {"getID", NULL}, 96 | {"isOn", NULL}, 97 | {"getLabel", NULL}, 98 | {NULL, NULL} 99 | }; 100 | 101 | library_t computer::methods = {"computer", computer_reg, nullptr, nullptr}; -------------------------------------------------------------------------------- /resources/android-project/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 23 | 26 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 59 | 65 | 66 | 69 | 70 | 76 | 77 | 78 | 79 | 80 | 81 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /api/configuration.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * configuration.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines structures used for storing the configuration. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef CRAFTOS_PC_CONFIGURATION_HPP 12 | #define CRAFTOS_PC_CONFIGURATION_HPP 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | // Constants for mount modes 19 | #define MOUNT_MODE_NONE 0 // Disallow all mounting 20 | #define MOUNT_MODE_RO_STRICT 1 // Only allow read-only mounts 21 | #define MOUNT_MODE_RO 2 // Default to read-only mounts 22 | #define MOUNT_MODE_RW 3 // Default to read-write mounts 23 | 24 | // This structure holds all available configuration variables. See https://www.craftos-pc.cc/docs/config for information about what each of these means. 25 | struct configuration { 26 | // The following fields are available in API version 10.0 and later. No structure version check is required to use these. 27 | bool http_enable; 28 | bool debug_enable; 29 | int mount_mode; 30 | std::vector http_whitelist; 31 | std::vector http_blacklist; 32 | std::vector mounter_whitelist; 33 | std::vector mounter_blacklist; 34 | std::vector mounter_no_ask; 35 | bool disable_lua51_features; 36 | std::string default_computer_settings; 37 | bool logErrors; 38 | bool showFPS; 39 | int computerSpaceLimit; 40 | int maximumFilesOpen; 41 | int abortTimeout; 42 | int maxNotesPerTick; 43 | int clockSpeed; 44 | bool ignoreHotkeys; 45 | bool checkUpdates; 46 | bool romReadOnly; 47 | std::string customFontPath; 48 | int customFontScale; 49 | int customCharScale; 50 | std::string skipUpdate; 51 | bool configReadOnly; 52 | bool vanilla; 53 | int initialComputer; 54 | int maxRecordingTime; 55 | int recordingFPS; // should be an even divisor of clockSpeed 56 | int cliControlKeyMode; // 0: home = ctrl, s+home = home; 1: home = home, s+home = ctrl; 2: home = home, esc-c = control; 3: home = home, ctrl-c = control 57 | bool showMountPrompt; 58 | int maxOpenPorts; 59 | int mouse_move_throttle; 60 | bool monitorsUseMouseEvents; 61 | int defaultWidth; 62 | int defaultHeight; 63 | bool standardsMode; 64 | bool useHardwareRenderer; 65 | std::string preferredHardwareDriver; 66 | bool useVsync; 67 | bool jit_ffi_enable; 68 | bool serverMode; 69 | std::unordered_map pluginData; 70 | bool http_websocket_enabled; 71 | int http_max_websockets; 72 | int http_max_websocket_message; 73 | int http_max_requests; 74 | int http_max_upload; 75 | int http_max_download; 76 | int http_timeout; 77 | 78 | // The following fields are available in API version 10.1 and later. 79 | std::string http_proxy_server; 80 | int http_proxy_port; 81 | bool extendMargins; 82 | bool snapToSize; 83 | 84 | // The following fields are available in API version 10.2 and later. 85 | bool snooperEnabled; 86 | 87 | // The following fields are available in API version 10.3 and later. 88 | bool keepOpenOnShutdown; 89 | 90 | // The following fields are available in API version 10.5 and later. 91 | bool useWebP; 92 | 93 | // The following fields are available in API version 10.6 and later. 94 | bool dropFilePath; 95 | 96 | // The following fields are available in API version 10.8 and later. 97 | bool useDFPWM; 98 | }; 99 | 100 | // A smaller structure that holds the configuration for a single computer. 101 | struct computer_configuration { 102 | std::string label; 103 | bool isColor; 104 | bool loadFailure; 105 | bool startFullscreen; 106 | 107 | // The following fields are available in API version 10.3 and later. 108 | int computerWidth; 109 | int computerHeight; 110 | }; 111 | 112 | #endif -------------------------------------------------------------------------------- /api/peripheral.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file creates the base class for all peripherals to inherit. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifndef CRAFTOS_PC_PERIPHERAL_HPP 12 | #define CRAFTOS_PC_PERIPHERAL_HPP 13 | #include "lib.hpp" 14 | #include 15 | 16 | class peripheral; 17 | 18 | // This function type is used to create a new instance of a peripheral. It takes 19 | // the Lua state and side that should be passed to the constructor, and returns 20 | // a new peripheral pointer object. This function template is the one that is 21 | // passed to the registerPeripheralFn function. 22 | typedef std::function peripheral_init_fn; 23 | 24 | // This type is the same as the above, but uses standard function pointers, so 25 | // it doesn't support lambdas or bound methods. This type is used by the 26 | // registerPeripheral function (deprecated). 27 | typedef peripheral*(*peripheral_init)(lua_State*, const char *); 28 | 29 | // This class is the main interface class that is overridden when making custom 30 | // peripherals. To create a peripheral type, just inherit this class as public 31 | // and define a constructor, getDestructor, call, and getMethods. 32 | class peripheral { 33 | public: 34 | typedef void(*destructor)(peripheral*); 35 | peripheral() = default; // unused 36 | // This is the main constructor that is used to create a peripheral. 37 | // You must provide your own version of this constructor. 38 | // Additional arguments to the create call start at stack index 3. 39 | peripheral(lua_State *L, const char * side) {} 40 | // You also should define a destructor for your peripheral. 41 | virtual ~peripheral()=0; 42 | // This function should return a function that takes a peripheral pointer 43 | // and correctly frees the object with delete. This is necessary when loading 44 | // a peripheral class from a plugin. 45 | // An example of this would be to define a static void function in the class: 46 | // static void deinit(peripheral * p) {delete (myperipheral*)p;} 47 | // then return that from getDestructor: 48 | // destructor getDestructor() {return deinit;} 49 | virtual destructor getDestructor() const=0; 50 | // This is the main function that is used to call methods on peripherals. 51 | // The function should act like a normal Lua function, except that it also 52 | // gets the method name as a parameter. If you're defining the function calls 53 | // separately in the class, you just need to convert the method name string 54 | // into the proper function calls: 55 | // if (m == "a") return a(L); else if (m == "b") return b(L); ... 56 | virtual int call(lua_State *L, const char * method)=0; 57 | // This function is deprecated, and no longer works. In fact, it did not work 58 | // in any version of the API. Just leave this as-is. 59 | [[deprecated]] 60 | virtual void update() {} 61 | // This function should return a library_t containing the names of all of the 62 | // methods available to the peripheral. Only the keys, name, and size members 63 | // are accessed, so there is no need to fill in the other members. 64 | virtual library_t getMethods() const=0; 65 | // This function is called whenever the computer reboots with the peripheral 66 | // still attached from a previous boot. This can be used to fix any Lua state 67 | // references that were destroyed when the previous Lua state was closed. 68 | // The state this function is called with is the computer's global state. 69 | virtual void reinitialize(lua_State *L) {} 70 | // This function optionally provides a list of types that this peripheral 71 | // provides. It is only called if the peripheral's type in getMethods() is 72 | // exactly "!!MULTITYPE". This function is only used in API version 10.7 or later. 73 | virtual std::vector getTypes() const {return {};}; 74 | }; 75 | inline peripheral::~peripheral() {} 76 | #endif -------------------------------------------------------------------------------- /api/FileEntry.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * FileEntry.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines a FileEntry class that holds data for virtual filesystems, 6 | * including the standalone ROM. 7 | * 8 | * This code is licensed under the MIT license. 9 | * Copyright (c) 2019-2024 JackMacWindows. 10 | */ 11 | 12 | #ifndef CRAFTOS_PC_FILEENTRY_HPP 13 | #define CRAFTOS_PC_FILEENTRY_HPP 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /** 24 | * The FileEntry structure holds a virtual file or directory of files for use 25 | * with virtual mounts. A FileEntry can be constructed with either a string 26 | * value (indicating a file) or a map of strings to FileEntries (indicating a 27 | * directory). 28 | * 29 | * Here's an example of how to construct a FileEntry: 30 | * @code{.cpp} 31 | FileEntry myVFS = { 32 | {"dir1", { 33 | {"file.txt", "This is a test file.\nHello!"}, 34 | {"innerdir", { 35 | {"innerfile.txt", "This file is inside two directories."} 36 | }} 37 | }}, 38 | {"outerfile.txt", "This file is in the root."} 39 | }; 40 | * @endcode 41 | */ 42 | struct FileEntry { 43 | bool isDir; // Whether the entry is a directory 44 | bool error = false; // Whether a failure occurred 45 | std::string data; // If this entry is a file, this contains the file data 46 | std::map dir; // If this entry is a directory, this contains the inner files & directories 47 | FileEntry(std::string d): isDir(false), data(d) {} // File constructor 48 | FileEntry(const char * d): isDir(false), data(d) {} // File constructor 49 | FileEntry(std::map d): isDir(true), dir(d) {} // Directory constructor 50 | FileEntry(std::initializer_list::value_type > il): isDir(true), dir(il) {} // Directory constructor 51 | FileEntry(const FileEntry &f) {isDir = f.isDir; if (isDir) dir = f.dir; else data = f.data;} // Copy constructor 52 | ~FileEntry() = default; 53 | FileEntry& operator=(const FileEntry& rhs) {isDir = rhs.isDir; if (isDir) dir = rhs.dir; else data = rhs.data; return *this;} 54 | FileEntry& operator[](std::string key) noexcept(false) {if (!isDir) throw std::runtime_error("Attempted to index a file"); return this->dir.at(key);} 55 | const FileEntry& operator[](std::string key) const noexcept(false) {if (!isDir) throw std::runtime_error("Attempted to index a file"); return this->dir.at(key);} 56 | 57 | /** 58 | * Traverses a path string and returns the associated file entry. 59 | * @param path The path to traverse 60 | * @return The resulting file entry 61 | * @throw std::runtime_error If one of the non-final nodes is a file 62 | * @throw std::out_of_range If one of the nodes doesn't exist 63 | */ 64 | FileEntry& path(std::filesystem::path path) noexcept(false) { 65 | FileEntry * retval = this; 66 | for (const auto& item : path) if (item.string() != "." && !std::regex_match(item.native(), std::basic_regex(std::filesystem::path("\\d+:").native()))) retval = &(*retval)[item.string()]; 67 | return *retval; 68 | } 69 | FileEntry& path(std::string path) noexcept(false) { 70 | return this->path(std::filesystem::path(path)); 71 | } 72 | FileEntry& path(std::wstring path) noexcept(false) { 73 | return this->path(std::filesystem::path(path)); 74 | } 75 | const FileEntry& path(std::filesystem::path path) const noexcept(false) { 76 | const FileEntry * retval = this; 77 | for (const auto& item : path) if (item.string() != "." && !std::regex_match(item.native(), std::basic_regex(std::filesystem::path("\\d+:").native()))) retval = &(*retval)[item.string()]; 78 | return *retval; 79 | } 80 | const FileEntry& path(std::string path) const noexcept(false) { 81 | return this->path(std::filesystem::path(path)); 82 | } 83 | const FileEntry& path(std::wstring path) const noexcept(false) { 84 | return this->path(std::filesystem::path(path)); 85 | } 86 | }; 87 | 88 | #endif -------------------------------------------------------------------------------- /src/apis/peripheral.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * apis/peripheral.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the functions in the peripheral API. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include 12 | #include 13 | #include "../util.hpp" 14 | 15 | static int peripheral_isPresent(lua_State *L) { 16 | lastCFunction = __func__; 17 | luaL_checkstring(L, 1); 18 | Computer * computer = get_comp(L); 19 | std::lock_guard lock(computer->peripherals_mutex); 20 | lua_pushboolean(L, computer->peripherals.find(tostring(L, -1)) != computer->peripherals.end()); 21 | return 1; 22 | } 23 | 24 | static int peripheral_getType(lua_State *L) { 25 | lastCFunction = __func__; 26 | Computer * computer = get_comp(L); 27 | const std::string side(luaL_checkstring(L, 1)); 28 | std::lock_guard lock(computer->peripherals_mutex); 29 | if (computer->peripherals.find(side) != computer->peripherals.end()) { 30 | const char * name = computer->peripherals[side]->getMethods().name; 31 | if (strcmp(name, "!!MULTITYPE") == 0) { 32 | std::vector names = computer->peripherals[side]->getTypes(); 33 | for (const std::string& n : names) lua_pushstring(L, n.c_str()); 34 | return names.size(); 35 | } else lua_pushstring(L, name); 36 | } 37 | else return 0; 38 | return 1; 39 | } 40 | 41 | static int peripheral_getMethods(lua_State *L) { 42 | lastCFunction = __func__; 43 | Computer * computer = get_comp(L); 44 | const std::string side(luaL_checkstring(L, 1)); 45 | std::lock_guard lock(computer->peripherals_mutex); 46 | if (computer->peripherals.find(side) == computer->peripherals.end()) return 0; 47 | const library_t methods = computer->peripherals[side]->getMethods(); 48 | lua_newtable(L); 49 | for (int i = 0; methods.functions[i].name; i++) { 50 | lua_pushinteger(L, i+1); 51 | lua_pushstring(L, methods.functions[i].name); 52 | lua_settable(L, -3); 53 | } 54 | return 1; 55 | } 56 | 57 | static int peripheral_call(lua_State *L) { 58 | lastCFunction = __func__; 59 | Computer * computer = get_comp(L); 60 | const std::string side(luaL_checkstring(L, 1)); 61 | const std::string func(luaL_checkstring(L, 2)); 62 | peripheral * p; 63 | { 64 | std::lock_guard lock(computer->peripherals_mutex); 65 | if (computer->peripherals.find(side) == computer->peripherals.end()) return 0; 66 | lua_remove(L, 1); 67 | lua_remove(L, 1); 68 | p = computer->peripherals[side]; 69 | } 70 | return p->call(L, func.c_str()); 71 | } 72 | 73 | static int peripheral_hasType(lua_State *L) { 74 | lastCFunction = __func__; 75 | Computer * computer = get_comp(L); 76 | const std::string side = checkstring(L, 1); 77 | const std::string type = checkstring(L, 2); 78 | std::lock_guard lock(computer->peripherals_mutex); 79 | if (computer->peripherals.find(side) == computer->peripherals.end()) lua_pushnil(L); 80 | else { 81 | const char * name = computer->peripherals[side]->getMethods().name; 82 | if (strcmp(name, "!!MULTITYPE") == 0) { 83 | std::vector names = computer->peripherals[side]->getTypes(); 84 | bool ok = false; 85 | for (const std::string& n : names) if (n == type) ok = true; 86 | lua_pushboolean(L, ok); 87 | } else lua_pushboolean(L, name == type); 88 | } 89 | return 1; 90 | } 91 | 92 | void peripheral_update(Computer *comp) { 93 | std::lock_guard lock(comp->peripherals_mutex); 94 | for (auto p : comp->peripherals) p.second->update(); 95 | } 96 | 97 | static luaL_Reg peripheral_reg[] = { 98 | {"isPresent", peripheral_isPresent}, 99 | {"getType", peripheral_getType}, 100 | {"getMethods", peripheral_getMethods}, 101 | {"call", peripheral_call}, 102 | {"hasType", peripheral_hasType}, 103 | {NULL, NULL} 104 | }; 105 | 106 | library_t peripheral_lib = {"peripheral", peripheral_reg, nullptr, nullptr}; -------------------------------------------------------------------------------- /src/mem/cluster.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * mem/cluster.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file implements the class for the cluster allocator. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include "cluster.hpp" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #define BITMAP_UNIT_SIZE (sizeof(bitmap_unit) * 8) 18 | 19 | ClusterAllocator::ClusterAllocator(const size_t elem_size): elem_size(elem_size + sizeof(void*)) { 20 | head = newcluster(0); 21 | freecluster = head; 22 | } 23 | 24 | ClusterAllocator::~ClusterAllocator() { 25 | cluster_t * cluster = head, * next; 26 | while (cluster != NULL) { 27 | next = cluster->next; 28 | ::free(cluster); 29 | cluster = next; 30 | } 31 | } 32 | 33 | ClusterAllocator::cluster_t * ClusterAllocator::newcluster(long id) { 34 | cluster_t * cluster = (cluster_t*)malloc(sizeof(cluster_t) + CLUSTER_SIZE * elem_size); 35 | memset(cluster, 0, sizeof(cluster_t) + CLUSTER_SIZE * elem_size); 36 | cluster->next = NULL; /* ensure next pointer is NULL */ 37 | cluster->id = id; /* set cluster number */ 38 | for (int i = 0; i < CLUSTER_SIZE; i++) 39 | *(cluster_t**)(cluster->ptr + i * elem_size) = cluster; 40 | return cluster; 41 | } 42 | 43 | void * ClusterAllocator::alloc() { 44 | void *ptr = NULL; 45 | cluster_t *cluster, *next; 46 | int i, j; 47 | for (cluster = freecluster; ptr == NULL; cluster = cluster->next) { 48 | /* search for unused entry in cluster */ 49 | for (i = 0; i < CLUSTER_BITMAP_SIZE; i++) { 50 | if (cluster->bitmap[i] != (bitmap_unit)~(bitmap_unit)0) { /* empty space found? */ 51 | // magic (https://graphics.stanford.edu/%7Eseander/bithacks.html#CountBitsSetParallel) 52 | // please don't use this on a 256-bit CPU 53 | bitmap_unit v = (cluster->bitmap[i] ^ (cluster->bitmap[i] + 1)) >> 1; 54 | v = v - ((v >> 1) & (bitmap_unit)~(bitmap_unit)0/3); // temp 55 | v = (v & (bitmap_unit)~(bitmap_unit)0/15*3) + ((v >> 2) & (bitmap_unit)~(bitmap_unit)0/15*3); // temp 56 | v = (v + (v >> 4)) & (bitmap_unit)~(bitmap_unit)0/255*15; // temp 57 | j = (bitmap_unit)(v * ((bitmap_unit)~(bitmap_unit)0/255)) >> (sizeof(bitmap_unit) - 1) * 8; // count 58 | ptr = (void*)(cluster->ptr + (i * BITMAP_UNIT_SIZE + j) * elem_size); 59 | cluster->bitmap[i] |= (1 << j); 60 | break; 61 | } 62 | } 63 | if (ptr != NULL) break; 64 | if (cluster->next == NULL) { /* need new cluster? */ 65 | next = newcluster(cluster->id + 1); 66 | cluster->next = next; /* chain next cluster in list */ 67 | } 68 | } 69 | freecluster = cluster; 70 | return (void*)((char*)ptr + sizeof(void*)); 71 | } 72 | 73 | void ClusterAllocator::free(void * ptr) { 74 | cluster_t * cluster = *(cluster_t**)((char*)ptr - sizeof(cluster_t**)); 75 | int idx = ((ptrdiff_t)ptr - (ptrdiff_t)cluster->ptr) / elem_size; 76 | cluster->bitmap[idx/BITMAP_UNIT_SIZE] &= ~(1 << (idx % BITMAP_UNIT_SIZE)); /* mark entry as freed */ 77 | if (cluster->id < freecluster->id) 78 | freecluster = cluster; 79 | 80 | int i, empty, full; 81 | empty = cluster->bitmap[0] == 0; 82 | full = cluster->bitmap[0] == ULONG_MAX; 83 | for (i = 1; i < CLUSTER_BITMAP_SIZE && (empty || full); i++) { 84 | if (cluster->bitmap[i]) { /* any entry in use? */ 85 | empty = 0; 86 | } 87 | if (cluster->bitmap[i] != ULONG_MAX) { /* any entry *not* in use? */ 88 | full = 0; 89 | } 90 | } 91 | if (empty && cluster->next != NULL) { /* entire cluster unused? */ 92 | /* unlink and free cluster */ 93 | if (head != cluster) { 94 | cluster_t * last = head; 95 | while (last->next != cluster && last->next != NULL) last = last->next; 96 | assert(last != NULL); 97 | // TODO: sweep previous empty clusters 98 | if (last != cluster) last->next = cluster->next; 99 | } else head = cluster->next; 100 | if (freecluster == cluster) 101 | freecluster = cluster->next; 102 | ::free(cluster); 103 | } else if (!full && cluster->id < freecluster->id) { 104 | freecluster = cluster; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /m4/find_cxx.m4: -------------------------------------------------------------------------------- 1 | dnl @synopsis AX_CXX_CHECK_LIB(libname, functioname, action-if, action-if-not) 2 | dnl 3 | dnl The standard AC_CHECK_LIB can not test functions in namespaces. 4 | dnl Therefore AC_CHECK_LIB(cgicc, cgicc::Cgicc::getVersion) will always 5 | dnl fail. We need to decompose the functionname into a series of namespaces 6 | dnl where it gets declared so that it can be used for a link test. 7 | dnl 8 | dnl In the first version I did allow namespace::functionname to be a 9 | dnl reference to a void-argument global functionname (just wrapped in a 10 | dnl namespace) like its C counterparts would be - but in reality such 11 | dnl thing does not exist. The only global / static functions are always 12 | dnl made const-functions which is an attribute mangled along into the 13 | dnl library function export name. 14 | dnl 15 | dnl The normal usage will ask for a test of a class-member function which 16 | dnl should be presented with a full function spec with arguments given in 17 | dnl parentheses following the function name - if the function to test for 18 | dnl does expect arguments then you should add default initial values in the 19 | dnl prototype (even if they do not exist originally, these are used only 20 | dnl locally to build a correct function call in the configure test script). 21 | dnl 22 | dnl In the current version if you do omit the parenthesis from the macro 23 | dnl argument then the macro will assume that you want to check for the 24 | dnl class name - which is really to check for default constructor being 25 | dnl exported from the given library name. 26 | dnl 27 | dnl EXAMPLE: 28 | dnl AX_CXX_CHECK_LIB(cgicc, [cgicc::HTTPCookie]) 29 | dnl AX_CXX_CHECK_LIB(cgicc, [cgicc::Cgicc::getVersion () const], 30 | dnl AX_CXX_CHECK_LIB(boost_regex, [boost::RegEx::Position (int i = 0) const]) 31 | dnl 32 | dnl Result: 33 | dnl Just as the usual AX_CXX_CHECK_LIB - defines HAVE_LIBCGICC 34 | dnl and adds the libraries to the default library path (and 35 | dnl uses internally the normal ac_check_lib cache symbol 36 | dnl like ac_cv_lib_cgicc_cgicc__Cgicc) 37 | dnl 38 | dnl Footnote: The C++ language is not good at creating stable library 39 | dnl interfaces at the binary level - a lot of functionality is usually being 40 | dnl given as inline functions plus there is hardly a chance to create opaque 41 | dnl types. Therefore most C++ library tests will only do compile tests using 42 | dnl the header files. Doing a check_lib is however good to check the link 43 | dnl dependency before hitting it as an error in the build later. 44 | dnl 45 | dnl @category C++ 46 | dnl @author Guido U. Draheim 47 | dnl @vesion 2006-12-18 48 | 49 | AC_DEFUN([AX_CXX_CHECK_LIB], 50 | [m4_ifval([$3], , [AH_CHECK_LIB([$1])])dnl 51 | AS_LITERAL_IF([$1], 52 | [AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$2])], 53 | [AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1''_$2])])dnl 54 | AC_CACHE_CHECK([for $2 in -l$1], ac_Lib, 55 | [ac_check_lib_save_LIBS=$LIBS 56 | LIBS="-l$1 $5 $LIBS" 57 | case "$2" 58 | in *::*::*\(*) 59 | AC_LINK_IFELSE([AC_LANG_PROGRAM([ 60 | namespace `echo "$2" | sed -e "s/::.*//"` 61 | { class `echo "$2" | sed -e "s/.*::\\(.*\\)::.*/\\1/" -e "s/(.*//"` 62 | { public: int `echo "$2" | sed -e "s/.*:://" -e "/(/!s/..*/&()/"`; 63 | }; 64 | } 65 | ],[`echo "$2" | sed -e "s/(.*//" -e "s/\\(.*\\)::\\(.*\\)/((\\1*)(0))->\\2/g"`()])], 66 | [AS_VAR_SET(ac_Lib, yes)], 67 | [AS_VAR_SET(ac_Lib, no)]) 68 | ;; *::*::*) 69 | AC_LINK_IFELSE([AC_LANG_PROGRAM([ 70 | namespace `echo "$2" | sed -e "s/::.*//"` 71 | { namespace `echo "$2" | sed -e "s/.*::\\(.*\\)::.*/\\1/"` 72 | { class `echo "$2" | sed -e "s/.*:://"` 73 | { public: `echo "$2" | sed -e "s/.*:://"` (); 74 | }; 75 | } 76 | } 77 | ],[new $2()])], 78 | [AS_VAR_SET(ac_Lib, yes)], 79 | [AS_VAR_SET(ac_Lib, no)]) 80 | ;; *::*\(*) 81 | AC_LINK_IFELSE([AC_LANG_PROGRAM([ 82 | class `echo "$2" | sed -e "s/\\(.*\\)::.*/\\1/" -e "s/(.*//"` 83 | { public: int `echo "$2" | sed -e "s/.*:://" -e "/(/!s/..*/&()/"`; 84 | }; 85 | ],[`echo "$2" | sed -e "s/(.*//" -e "s/\\(.*\\)::\\(.*\\)/((\\1*)(0))->\\2/g"`()])], 86 | [AS_VAR_SET(ac_Lib, yes)], 87 | [AS_VAR_SET(ac_Lib, no)]) 88 | ;; *::*) 89 | AC_LINK_IFELSE([AC_LANG_PROGRAM([ 90 | namespace `echo "$2" | sed -e "s/::.*//"` 91 | { class `echo "$2" | sed -e "s/.*:://"` 92 | { public: `echo "$2" | sed -e "s/.*:://"` (); 93 | }; 94 | } 95 | ],[new $2()])], 96 | [AS_VAR_SET(ac_Lib, yes)], 97 | [AS_VAR_SET(ac_Lib, no)]) 98 | ;; *) 99 | AC_LINK_IFELSE([AC_LANG_CALL([], [$2])], 100 | [AS_VAR_SET(ac_Lib, yes)], 101 | [AS_VAR_SET(ac_Lib, no)]) 102 | ;; esac 103 | LIBS=$ac_check_lib_save_LIBS]) 104 | AS_IF([test AS_VAR_GET(ac_Lib) = yes], 105 | [m4_default([$3], [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1)) 106 | LIBS="-l$1 $LIBS" 107 | ])], 108 | [$4])dnl 109 | AS_VAR_POPDEF([ac_Lib])dnl 110 | ])# AC_CHECK_LIB 111 | -------------------------------------------------------------------------------- /api/generic_peripheral/inventory.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * generic_peripheral/inventory.hpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines a generic peripheral class for inventory-type peripherals 6 | * to inherit from. 7 | * 8 | * This code is licensed under the MIT license. 9 | * Copyright (c) 2019-2024 JackMacWindows. 10 | */ 11 | 12 | #ifndef CRAFTOS_PC_GENERIC_PERIPHERAL_INVENTORY_HPP 13 | #define CRAFTOS_PC_GENERIC_PERIPHERAL_INVENTORY_HPP 14 | #include "../Computer.hpp" 15 | #include "../peripheral.hpp" 16 | 17 | class inventory : public peripheral { 18 | protected: 19 | virtual int size() = 0; // Returns the number of slots available in the inventory. 20 | virtual int getItemSpace(int slot) {return 64;} // Returns the maximum number of items in a slot (defaults to 64 for all). 21 | virtual void getItemDetail(lua_State *L, int slot) = 0; // Pushes a single Lua value to the stack with details about an item in a slot. If the slot is empty or invalid, pushes nil. (Slots are in the range 1-size().) 22 | virtual int addItems(lua_State *L, int slot, int count) = 0; // Adds the item described at the top of the Lua stack to the slot selected. Only adds up to count items. If slot is 0, determine the best slot available. Returns the number of items added. 23 | virtual int removeItems(int slot, int count) = 0; // Removes up to a number of items from the selected slot. Returns the number of items removed. 24 | public: 25 | virtual int call(lua_State *L, const char * method) override { 26 | const std::string m(method); 27 | if (m == "size") { 28 | lua_pushinteger(L, size()); 29 | return 1; 30 | } else if (m == "list") { 31 | lua_createtable(L, size(), 0); 32 | for (int i = 1; i <= size(); i++) { 33 | lua_pushinteger(L, i); 34 | lua_createtable(L, 0, 3); 35 | getItemDetail(L, i); 36 | if (lua_istable(L, -1)) { 37 | lua_getfield(L, -1, "name"); 38 | lua_setfield(L, -3, "name"); 39 | lua_getfield(L, -1, "count"); 40 | lua_setfield(L, -3, "count"); 41 | lua_getfield(L, -1, "nbt"); 42 | lua_setfield(L, -3, "nbt"); 43 | lua_pop(L, 1); 44 | } else { 45 | lua_remove(L, -2); 46 | } 47 | lua_settable(L, -3); 48 | } 49 | return 1; 50 | } else if (m == "getItemDetail") { 51 | getItemDetail(L, luaL_checkinteger(L, 1)); 52 | return 1; 53 | } else if (m == "getItemLimit") { 54 | lua_pushinteger(L, getItemSpace(luaL_checkinteger(L, 1))); 55 | return 1; 56 | } else if (m == "pushItems" || m == "pullItems") { 57 | Computer * comp = get_comp(L); 58 | const char * side = luaL_checkstring(L, 1); 59 | const int fromSlot = luaL_checkinteger(L, 2); 60 | const int limit = luaL_optinteger(L, 3, INT_MAX); 61 | const int toSlot = luaL_optinteger(L, 4, 0); 62 | 63 | if (comp->peripherals.find(side) == comp->peripherals.end()) return luaL_error(L, "Target '%s' does not exist", side); 64 | inventory * p = dynamic_cast(comp->peripherals[side]); 65 | if (p == NULL) return luaL_error(L, "Target '%s' is not an inventory", side); 66 | inventory *src, *dest; 67 | if (m == "pushItems") src = this, dest = p; 68 | else src = p, dest = this; 69 | 70 | if (fromSlot < 1 || fromSlot > src->size()) return luaL_error(L, "From slot out of range (between 1 and %d)", src->size()); 71 | if (!lua_isnoneornil(L, 4) && (toSlot < 1 || toSlot > dest->size())) return luaL_error(L, "To slot out of range (between 1 and %d)", dest->size()); 72 | if (limit <= 0) { 73 | lua_pushinteger(L, 0); 74 | return 1; 75 | } 76 | 77 | src->getItemDetail(L, fromSlot); 78 | const int removed = src->removeItems(fromSlot, limit); 79 | if (removed == 0) { 80 | lua_pushinteger(L, 0); 81 | return 1; 82 | } 83 | const int added = dest->addItems(L, toSlot, removed); 84 | if (added < removed) src->addItems(L, fromSlot, removed - added); // hopefully this will still be OK 85 | 86 | lua_pushinteger(L, added); 87 | return 1; 88 | } else return luaL_error(L, "No such method"); 89 | } 90 | void update() override {} 91 | virtual library_t getMethods() const override { 92 | static luaL_Reg reg[] = { 93 | {"size", NULL}, 94 | {"list", NULL}, 95 | {"getItemDetail", NULL}, 96 | {"getItemLimit", NULL}, 97 | {"pushItems", NULL}, 98 | {"pullItems", NULL}, 99 | {NULL, NULL} 100 | }; 101 | static library_t methods = {"inventory", reg, nullptr, nullptr}; 102 | return methods; 103 | } 104 | }; 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /src/peripheral/debug_adapter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/debug_adapter.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file implements the Debug Adapter Protocol connection. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | static void forwardInput(); 12 | #include "debug_adapter.hpp" 13 | #include "../runtime.hpp" 14 | #include "../terminal/SDLTerminal.hpp" 15 | #include "../terminal/HardwareSDLTerminal.hpp" 16 | #include "../termsupport.hpp" 17 | #include 18 | #include 19 | #ifdef _WIN32 20 | #include 21 | #include 22 | #endif 23 | 24 | static debug_adapter * stdio_debugger = NULL; 25 | static std::mutex stdio_debugger_lock; 26 | static std::thread * inputThread = NULL; 27 | 28 | static std::string dap_input(lua_State *L, void* arg) { 29 | std::string * str = (std::string*)arg; 30 | lua_pushlstring(L, str->c_str(), str->size()); 31 | delete str; 32 | return "dap_input"; 33 | } 34 | 35 | static void forwardInput() { 36 | std::this_thread::sleep_for(std::chrono::seconds(1)); 37 | while (!exiting) { 38 | std::string data, line; 39 | do { 40 | std::getline(std::cin, line); 41 | data += line + "\n"; 42 | } while (!exiting && line != "" && line != "\r"); 43 | if (exiting) break; 44 | size_t sz = 0; 45 | bool state = false; 46 | for (int i = 0; i < data.size(); i++) { 47 | if (!state && isdigit(data[i])) {state = true; sz = data[i] - '0';} 48 | else if (isdigit(data[i])) sz = sz * 10 + (data[i] - '0'); 49 | else if (state) break; 50 | } 51 | std::cerr << sz << "\n"; 52 | for (int i = 0; i < sz; i++) data += std::cin.get(); 53 | std::lock_guard lock(stdio_debugger_lock); 54 | if (stdio_debugger != NULL) { 55 | std::string * str = new std::string(data); 56 | queueEvent(stdio_debugger->monitor, dap_input, str); 57 | } 58 | } 59 | } 60 | 61 | class DAPConnection: public Poco::Net::TCPServerConnection { 62 | debug_adapter * debug; 63 | public: 64 | DAPConnection(const Poco::Net::StreamSocket& sock, debug_adapter * d): TCPServerConnection(sock), debug(d) {} 65 | void run() override { 66 | Poco::Net::StreamSocket& socket = this->socket(); 67 | if (debug->socket != NULL) return; 68 | debug->socket = &socket; 69 | char buffer[4096]; 70 | while (true) { 71 | int size = socket.receiveBytes(buffer, 4096); 72 | if (size <= 0) break; 73 | std::string * str = new std::string(buffer, size); 74 | queueEvent(debug->monitor, dap_input, str); 75 | } 76 | debug->socket = NULL; 77 | } 78 | 79 | class Factory: public Poco::Net::TCPServerConnectionFactory { 80 | debug_adapter * debug; 81 | public: 82 | Factory(debug_adapter * d): debug(d) {} 83 | Poco::Net::TCPServerConnection * createConnection(const Poco::Net::StreamSocket & socket) override { 84 | return new DAPConnection(socket, debug); 85 | } 86 | }; 87 | }; 88 | 89 | debug_adapter::debug_adapter(lua_State *L, const char * side): debugger(L, side), server(new DAPConnection::Factory(this), 12100 + get_comp(L)->id) { 90 | if (inputThread == NULL && (selectedRenderer == 0 || selectedRenderer == 5)) inputThread = new std::thread(forwardInput); 91 | if (stdio_debugger == NULL) { 92 | stdio_debugger = this; 93 | #ifdef _WIN32 94 | // Disable CRLF -> LF conversion (DAP needs CRLF) 95 | _setmode(0, _O_BINARY); 96 | _setmode(1, _O_BINARY); 97 | #endif 98 | } 99 | server.start(); 100 | std::lock_guard lock(renderTargetsLock); 101 | if (singleWindowMode) { 102 | const auto pos = currentWindowIDs.find(monitor->term->id); 103 | if (pos != currentWindowIDs.end()) currentWindowIDs.erase(pos); 104 | } 105 | for (auto it = renderTargets.begin(); it != renderTargets.end(); ++it) { 106 | if (*it == monitor->term) 107 | it = renderTargets.erase(it); 108 | if (it == renderTargets.end()) break; 109 | } 110 | HardwareSDLTerminal * hwterm = dynamic_cast(monitor->term); 111 | SDLTerminal * term = dynamic_cast(monitor->term); 112 | if (hwterm) { 113 | SDL_DestroyTexture(hwterm->pixtex); 114 | SDL_DestroyTexture(hwterm->font); 115 | SDL_DestroyRenderer(hwterm->ren); 116 | hwterm->pixtex = hwterm->font = NULL; 117 | hwterm->ren = NULL; 118 | } 119 | if (term) { 120 | SDL_DestroyWindow(term->win); 121 | term->win = NULL; 122 | } 123 | } 124 | 125 | debug_adapter::~debug_adapter() { 126 | if (stdio_debugger == this) stdio_debugger = NULL; 127 | } 128 | 129 | void debug_adapter::sendData(const std::string& data) { 130 | if (stdio_debugger == this) { 131 | std::cout.write(data.c_str(), data.size()); 132 | std::cout << "\n"; 133 | std::cout.flush(); 134 | } 135 | if (socket != NULL) { 136 | socket->sendBytes(data.c_str(), data.size()); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/apis/mounter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * apis/mounter.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file implements the methods for the mounter API. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "../peripheral/debugger.hpp" 16 | #include "../platform.hpp" 17 | #include "../runtime.hpp" 18 | #include "../terminal/SDLTerminal.hpp" 19 | #ifdef WIN32 20 | #include 21 | #else 22 | #include 23 | #endif 24 | 25 | #ifdef STANDALONE_ROM 26 | extern FileEntry standaloneROM; 27 | extern FileEntry standaloneDebug; 28 | extern std::string standaloneBIOS; 29 | #endif 30 | 31 | static int mounter_mount(lua_State *L) { 32 | lastCFunction = __func__; 33 | if (config.mount_mode == MOUNT_MODE_NONE) luaL_error(L, "Mounting is disabled"); 34 | bool read_only = config.mount_mode != MOUNT_MODE_RW; 35 | if (lua_isboolean(L, 3) && config.mount_mode != MOUNT_MODE_RO_STRICT) read_only = lua_toboolean(L, 3); 36 | lua_pushboolean(L, addMount(get_comp(L), luaL_checkstring(L, 2), luaL_checkstring(L, 1), read_only)); 37 | return 1; 38 | } 39 | 40 | static int mounter_unmount(lua_State *L) { 41 | lastCFunction = __func__; 42 | if (config.mount_mode == MOUNT_MODE_NONE) luaL_error(L, "Mounting is disabled"); 43 | Computer * computer = get_comp(L); 44 | const char * comp_path = luaL_checkstring(L, 1); 45 | std::vector elems = split(std::string(comp_path), "/\\"); 46 | std::list pathc; 47 | for (const std::string& s : elems) { 48 | if (s == "..") { 49 | if (pathc.empty()) luaL_error(L, "Not a directory"); 50 | else pathc.pop_back(); 51 | } 52 | else if (!s.empty() && !std::all_of(s.begin(), s.end(), [](const char c)->bool{return c == '.';})) pathc.push_back(s); 53 | } 54 | if (pathc.front() == "rom" && config.romReadOnly) { 55 | lua_pushboolean(L, false); 56 | return 1; 57 | } 58 | bool found = false; 59 | for (auto it = computer->mounts.begin(); it != computer->mounts.end(); ++it) { 60 | if (pathc.size() == std::get<0>(*it).size() && std::equal(std::get<0>(*it).begin(), std::get<0>(*it).end(), pathc.begin())) { 61 | it = computer->mounts.erase(it); 62 | found = true; 63 | if (it == computer->mounts.end()) break; 64 | } 65 | } 66 | if (found && computer->debugger && !computer->isDebugger) ((debugger*)computer->debugger)->resetMounts(); 67 | lua_pushboolean(L, found); 68 | return 1; 69 | } 70 | 71 | static int mounter_list(lua_State *L) { 72 | lastCFunction = __func__; 73 | Computer * computer = get_comp(L); 74 | lua_createtable(L, 0, computer->mounts.size()); // table 75 | for (auto m : computer->mounts) { 76 | std::stringstream ss; 77 | for (const std::string& s : std::get<0>(m)) ss << (ss.tellp() == 0 ? "" : "/") << s; 78 | lua_pushstring(L, ss.str().c_str()); // table, key 79 | lua_gettable(L, -2); // table, value 80 | if (lua_isnil(L, -1)) { 81 | lua_pop(L, 1); // table 82 | lua_createtable(L, 1, 0); // table, entries 83 | } 84 | lua_pushinteger(L, lua_rawlen(L, -1) + 1); // table, entries, index 85 | if (std::regex_match(std::get<1>(m), std::basic_regex(path_t("\\d+:").native()))) lua_pushfstring(L, "(virtual mount:%s)", std::get<1>(m).substr(0, std::get<1>(m).size()-1).c_str()); 86 | else lua_pushstring(L, path_t(std::get<1>(m)).string().c_str()); // table, entries, index, value 87 | lua_settable(L, -3); // table, entries 88 | lua_pushstring(L, ss.str().c_str()); // table, entries, key 89 | lua_pushvalue(L, -2); // table, entries, key, entries 90 | lua_remove(L, -3); // table, key, entries 91 | lua_settable(L, -3); // table 92 | } 93 | return 1; 94 | } 95 | 96 | static int mounter_isReadOnly(lua_State *L) { 97 | lastCFunction = __func__; 98 | Computer * computer = get_comp(L); 99 | const char * comp_path = luaL_checkstring(L, 1); 100 | std::vector elems = split(std::string(comp_path), "/\\"); 101 | std::list pathc; 102 | for (const std::string& s : elems) { 103 | if (s == "..") { 104 | if (pathc.empty()) luaL_error(L, "Not a directory"); 105 | else pathc.pop_back(); 106 | } else if (!s.empty() && !std::all_of(s.begin(), s.end(), [](const char c)->bool{return c == '.';})) pathc.push_back(s); 107 | } 108 | for (const auto& e : computer->mounts) { 109 | if (std::get<0>(e).size() == pathc.size() && std::equal(std::get<0>(e).begin(), std::get<0>(e).end(), pathc.begin())) { 110 | lua_pushboolean(L, std::get<2>(e)); 111 | return 1; 112 | } 113 | } 114 | luaL_error(L, "%s: Not mounted", comp_path); 115 | return 0; // redundant 116 | } 117 | 118 | static luaL_Reg mounter_reg[] = { 119 | {"mount", mounter_mount}, 120 | {"unmount", mounter_unmount}, 121 | {"list", mounter_list}, 122 | {"isReadOnly", mounter_isReadOnly}, 123 | {NULL, NULL} 124 | }; 125 | 126 | library_t mounter_lib = {"mounter", mounter_reg, nullptr, nullptr}; 127 | -------------------------------------------------------------------------------- /resources/BenchmarkRenderers.lua: -------------------------------------------------------------------------------- 1 | local function runTests() 2 | local oldClockSpeed = config.get("clockSpeed") 3 | config.set("clockSpeed", 1000) 4 | -- Test characters 5 | term.redirect(term.native()) 6 | local benchmark = debug.getregistry().benchmark 7 | local w, h = term.getSize() 8 | local canBenchmark = benchmark ~= nil 9 | local count = 0 10 | local start = os.epoch "utc" 11 | if canBenchmark then benchmark() end 12 | pcall(function() 13 | while true do 14 | term.setCursorPos(math.random(1, w), math.random(1, h)) 15 | term.setBackgroundColor(2^math.random(0, 15)) 16 | term.setTextColor(2^math.random(0, 15)) 17 | term.write(string.char(math.random(0, 255))) 18 | count = count + 1 19 | end 20 | end) 21 | local frames = canBenchmark and benchmark() or 0 22 | local time = os.epoch "utc" - start 23 | term.setCursorPos(1, 1) 24 | term.setBackgroundColor(colors.black) 25 | term.setTextColor(colors.white) 26 | term.clear() 27 | if canBenchmark then print("Rendered " .. frames .. " frames in " .. time .. " ms (" .. (frames / (time / 1000)) .. " fps)") end 28 | print("Drew " .. count .. " characters (" .. (count / (time / 1000)) .. " cps)") 29 | local score = (frames / (time / 1000)) * 2 30 | 31 | os.queueEvent("nosleep") 32 | os.pullEvent() 33 | 34 | -- Test pixels 35 | term.setGraphicsMode(2) 36 | w, h = w*6-1, h*9-1 37 | for i = 0, 255 do term.setPaletteColor(i, 7 / bit32.rshift(bit32.band(i, 0xE0), 5), 7 / bit32.rshift(bit32.band(i, 0x1C), 2), 3 / bit32.band(i, 3)) end 38 | count = 0 39 | start = os.epoch "utc" 40 | if canBenchmark then benchmark() end 41 | pcall(function() 42 | while true do 43 | term.setPixel(math.random(0, w), math.random(0, h), math.random(0, 255)) 44 | count = count + 1 45 | end 46 | end) 47 | frames = canBenchmark and benchmark() or 0 48 | time = os.epoch "utc" - start 49 | term.clear() 50 | for i = 0, 15 do term.setPaletteColor(i, term.nativePaletteColor(2^i)) end 51 | term.setGraphicsMode(0) 52 | if canBenchmark then print("Rendered " .. frames .. " frames in " .. time .. " ms (" .. (frames / (time / 1000)) .. " fps)") end 53 | print("Drew " .. count .. " pixels (" .. (count / (time / 1000)) .. " pps)") 54 | config.set("clockSpeed", oldClockSpeed) 55 | return score + (frames / (time / 1000)) 56 | end 57 | 58 | if shell == nil then error("This program must be run from the shell.") end 59 | 60 | local mode = ... 61 | if mode ~= "hardware" then 62 | if config.get("useHardwareRenderer") == true or config.get("debug_enable") == false then 63 | config.set("useHardwareRenderer", false) 64 | config.set("debug_enable", true) 65 | print("Please quit and relaunch CraftOS-PC and try again.") 66 | return 67 | end 68 | term.setTextColor(colors.yellow) 69 | term.clear() 70 | term.setCursorPos(1, 1) 71 | print("This program will test which renderer is best for your system. It will take about a minute to complete, and you will need to quit and relaunch CraftOS-PC mid-way through. It is recommended you close all other applications before starting to accurately gauge the performance of your system.\n\nPress enter to continue.") 72 | read() 73 | local score = runTests() 74 | local file = fs.open(".benchmark_results", "w") 75 | file.write(score) 76 | file.close() 77 | if fs.exists("/startup.lua") then fs.move("/startup.lua", "/startup.f8CyMWNJ.lua") end 78 | file = fs.open("/startup.lua", "w") 79 | file.write("shell.run(\"" .. shell.getRunningProgram() .. " hardware\")") 80 | file.close() 81 | config.set("useHardwareRenderer", true) 82 | term.setBackgroundColor(colors.black) 83 | term.setTextColor(colors.lightBlue) 84 | term.clear() 85 | term.setCursorPos(1, 1) 86 | print("The software rendering portion of the test is complete. CraftOS-PC will now quit. Re-open CraftOS-PC to complete the test.\n\nPress enter to continie.") 87 | read() 88 | os.shutdown() 89 | else 90 | local score = runTests() 91 | local file = fs.open(".benchmark_results", "r") 92 | if file == nil then 93 | printError("Could not open results for software test, did you run them before this?") 94 | return 95 | end 96 | local swscore = tonumber(file.readLine()) 97 | file.close() 98 | fs.delete(".benchmark_results") 99 | fs.delete("/startup.lua") 100 | if fs.exists("/startup.f8CyMWNJ.lua") then fs.move("/startup.f8CyMWNJ.lua", "/startup.lua") end 101 | term.clear() 102 | term.setCursorPos(1, 1) 103 | term.setTextColor(colors.yellow) 104 | print("Results:") 105 | term.setTextColor(swscore > score and colors.green or colors.red) 106 | print("Software renderer: " .. swscore) 107 | term.setTextColor(swscore < score and colors.green or colors.red) 108 | print("Hardware renderer: " .. score) 109 | term.setTextColor(colors.lightBlue) 110 | print("It is recommended that you use the " .. (swscore > score and "software" or "hardware") .. " renderer.") 111 | term.setTextColor(colors.yellow) 112 | write("Would you like to set CraftOS-PC to use this renderer by default? (y/N) ") 113 | term.setTextColor(colors.white) 114 | local answer = read() 115 | if answer:sub(1, 1):upper() == "Y" then config.set("useHardwareRenderer", swscore < score) 116 | else config.set("useHardwareRenderer", false) end 117 | end -------------------------------------------------------------------------------- /resources/android-project/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /src/peripheral/tank.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * peripheral/tank.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file defines the methods for the tank peripheral. 6 | * 7 | * This code is licensed under the MIT License. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include "tank.hpp" 12 | 13 | int tank::tanks(lua_State *L) { 14 | lua_createtable(L, tankCount, 0); 15 | for (int i = 0; i < tankCount; i++) { 16 | lua_newtable(L); 17 | int j = 1; 18 | for (const auto& fluid : fluids[i]) { 19 | lua_createtable(L, 0, 2); 20 | lua_pushlstring(L, fluid.first.c_str(), fluid.first.size()); 21 | lua_setfield(L, -2, "name"); 22 | lua_pushinteger(L, fluid.second); 23 | lua_setfield(L, -2, "amount"); 24 | lua_rawseti(L, -2, j++); 25 | } 26 | lua_rawseti(L, -2, i+1); 27 | } 28 | return 1; 29 | } 30 | 31 | int tank::addFluid(const std::string& name, int amount) { 32 | // First try to add all the fluid in a contiguous amount if possible, 33 | // and if not then add it split across the tanks. 34 | std::vector freeSpace(tankCount, tankCapacity); 35 | for (int i = 0; i < tankCount; i++) { 36 | for (const auto& fluid : fluids[i]) freeSpace[i] -= fluid.second; 37 | if (freeSpace[i] >= amount) { 38 | for (auto& fluid : fluids[i]) { 39 | if (fluid.first == name) { 40 | fluid.second += amount; 41 | return amount; 42 | } 43 | } 44 | fluids[i][name] = amount; 45 | return amount; 46 | } 47 | } 48 | const int total = amount; 49 | for (int i = 0; i < tankCount && amount > 0; i++) { 50 | if (freeSpace[i] == 0) continue; 51 | int d = min(amount, freeSpace[i]); 52 | for (auto& fluid : fluids[i]) { 53 | if (fluid.first == name) { 54 | fluid.second += d; 55 | amount -= d; 56 | d = 0; 57 | break; 58 | } 59 | } 60 | if (d) { 61 | fluids[i][name] = d; 62 | amount -= d; 63 | } 64 | } 65 | return total - amount; 66 | } 67 | 68 | std::list> tank::removeFluid(const std::string& name, int amount) { 69 | std::list> retval; 70 | if (name == "") { 71 | for (int i = 0; i < tankCount && amount > 0; i++) { 72 | for (auto it = fluids[i].begin(); amount > 0 && it != fluids[i].end(); it = fluids[i].begin()) { 73 | if (amount >= it->second) { 74 | retval.push_back(*it); 75 | amount -= it->second; 76 | fluids[i].erase(it); 77 | } else { 78 | retval.push_back(std::make_pair(it->first, amount)); 79 | it->second -= amount; 80 | amount = 0; 81 | break; 82 | } 83 | } 84 | } 85 | } else { 86 | for (int i = 0; i < tankCount && amount > 0; i++) { 87 | for (auto& fluid : fluids[i]) { 88 | if (fluid.first == name) { 89 | if (amount >= fluid.second) { 90 | retval.push_back(fluid); 91 | amount -= fluid.second; 92 | fluids[i].erase(fluid.first); 93 | } else { 94 | retval.push_back(std::make_pair(fluid.first, amount)); 95 | fluid.second -= amount; 96 | amount = 0; 97 | } 98 | break; 99 | } 100 | } 101 | } 102 | } 103 | return retval; 104 | } 105 | 106 | tank::tank(lua_State *L, const char * side) { 107 | tankCount = luaL_optinteger(L, 3, tankCount); 108 | tankCapacity = luaL_optinteger(L, 4, tankCapacity); 109 | fluids.resize(tankCount); 110 | if (lua_istable(L, 5)) { 111 | lua_pushinteger(L, 1); 112 | lua_gettable(L, 5); 113 | for (int i = 2; lua_isstring(L, -1); i++) { 114 | types.push_back(tostring(L, -1)); 115 | lua_pop(L, 1); 116 | lua_pushinteger(L, i); 117 | lua_gettable(L, 5); 118 | } 119 | lua_pop(L, 1); 120 | } else if (!lua_isnoneornil(L, 5)) luaL_checktype(L, 5, LUA_TTABLE); 121 | } 122 | 123 | tank::~tank() {} 124 | 125 | int tank::call(lua_State *L, const char * method) { 126 | std::string m(method); 127 | if (m == "addFluid") { 128 | lua_pushinteger(L, addFluid(checkstring(L, 1), luaL_checkinteger(L, 2))); 129 | return 1; 130 | } else if (m == "removeFluid") { 131 | size_t sz = 0; 132 | const char * s = luaL_optlstring(L, 1, "", &sz); 133 | auto retval = removeFluid(std::string(s, sz), luaL_optinteger(L, 2, INT_MAX)); 134 | lua_newtable(L); 135 | int j = 1; 136 | for (const std::pair& fluid : retval) { 137 | lua_createtable(L, 0, 2); 138 | lua_pushlstring(L, fluid.first.c_str(), fluid.first.size()); 139 | lua_setfield(L, -2, "name"); 140 | lua_pushinteger(L, fluid.second); 141 | lua_setfield(L, -2, "amount"); 142 | lua_rawseti(L, -2, j++); 143 | } 144 | return 1; 145 | } else return fluid_storage::call(L, method); 146 | } 147 | 148 | static luaL_Reg tank_reg[] = { 149 | {"tanks", NULL}, 150 | {"pushFluid", NULL}, 151 | {"pullFluid", NULL}, 152 | {"addFluid", NULL}, 153 | {"removeFluid", NULL}, 154 | {NULL, NULL} 155 | }; 156 | 157 | library_t tank::methods = {"!!MULTITYPE", tank_reg, nullptr, nullptr}; 158 | -------------------------------------------------------------------------------- /resources/CCT-Tests.patch: -------------------------------------------------------------------------------- 1 | diff -ruN --strip -x .DS_Store projects/core/src/test/resources/test-rom/mcfly.lua b/projects/core/src/test/resources/test-rom/mcfly.lua 2 | --- a/projects/core/src/test/resources/test-rom/mcfly.lua 2020-06-29 02:52:34.000000000 -0400 3 | +++ b/projects/core/src/test/resources/test-rom/mcfly.lua 2020-06-27 02:49:47.000000000 -0400 4 | @@ -699,3 +699,4 @@ 5 | 6 | if cct_test then cct_test.finish(line_counts) end 7 | if howlci then howlci.log("debug", info) sleep(3) end 8 | +_G.failed_tests = actual_count - test_status.pass 9 | diff -ruN --strip -x .DS_Store projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua b/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua 10 | --- a/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua 2020-06-29 02:52:34.000000000 -0400 11 | +++ b/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua 2020-06-29 01:24:00.000000000 -0400 12 | @@ -92,7 +92,6 @@ 13 | describe("fs.list", function() 14 | it("fails on files", function() 15 | expect.error(fs.list, "rom/startup.lua"):eq("/rom/startup.lua: Not a directory") 16 | - expect.error(fs.list, "startup.lua"):eq("/startup.lua: Not a directory") 17 | end) 18 | 19 | it("fails on non-existent nodes", function() 20 | @@ -209,11 +208,6 @@ 21 | expect(fs.getDir("../foo")):eq("..") 22 | end) 23 | 24 | - it("returns '..' for parent directories", function() 25 | - expect(fs.getDir("..")):eq("../..") 26 | - expect(fs.getDir("../..")):eq("../../..") 27 | - end) 28 | - 29 | it("preserves pattern characters", function() 30 | expect(fs.getDir("foo*?/x")):eq("foo*?") 31 | end) 32 | @@ -463,7 +457,7 @@ 33 | 34 | describe("fs.makeDir", function() 35 | it("fails on files", function() 36 | - expect.error(fs.makeDir, "startup.lua"):eq("/startup.lua: File exists") 37 | + expect.error(fs.makeDir, "test-files/out.txt"):eq("/test-files/out.txt: File exists") 38 | end) 39 | 40 | it("fails on read-only mounts", function() 41 | @@ -554,7 +548,7 @@ 42 | end) 43 | 44 | it("returns the capacity on the root mount", function() 45 | - expect(fs.getCapacity("")):eq(10000000) 46 | + 47 | end) 48 | end) 49 | 50 | diff -ruN --strip -x .DS_Store projects/core/src/test/resources/test-rom/spec/apis/os_spec.lua b/projects/core/src/test/resources/test-rom/spec/apis/os_spec.lua 51 | --- a/projects/core/src/test/resources/test-rom/spec/apis/os_spec.lua 2021-06-08 23:52:34.000000000 -0400 52 | +++ b/projects/core/src/test/resources/test-rom/spec/apis/os_spec.lua 2021-04-28 03:19:00.000000000 -0400 53 | @@ -189,38 +189,3 @@ 54 | end) 55 | end) 56 | - 57 | - describe("os.queueEvent", function() 58 | - local function roundtrip(...) 59 | - local event_name = ("event_%08x"):format(math.random(1, 0x7FFFFFFF)) 60 | - os.queueEvent(event_name, ...) 61 | - return select(2, os.pullEvent(event_name)) 62 | - end 63 | - 64 | - it("preserves references in tables", function() 65 | - local tbl = {} 66 | - local xs = roundtrip({ tbl, tbl }) 67 | - expect(xs[1]):eq(xs[2]) 68 | - end) 69 | - 70 | - it("handles recursive tables", function() 71 | - local tbl = {} 72 | - tbl[1] = tbl 73 | - 74 | - local xs = roundtrip(tbl) 75 | - expect(xs):eq(xs[1]) 76 | - end) 77 | - 78 | - it("does not preserve references in separate args", function() 79 | - -- I'm not sure I like this behaviour, but it is what CC has always done. 80 | - local tbl = {} 81 | - local xs, ys = roundtrip(tbl, tbl) 82 | - expect(xs):ne(ys) 83 | - end) 84 | - 85 | - it("clones objects", function() 86 | - local tbl = {} 87 | - local xs = roundtrip(tbl) 88 | - expect(xs):ne(tbl) 89 | - end) 90 | - end) 91 | end) 92 | diff -ruN --strip -x .DS_Store projects/core/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/projects/core/src/test/resources/test-rom/spec/apis/textutils_spec.lua 93 | --- a/projects/core/src/test/resources/test-rom/spec/apis/textutils_spec.lua 2021-06-08 23:52:34.000000000 -0400 94 | +++ b/projects/core/src/test/resources/test-rom/spec/apis/textutils_spec.lua 2021-04-28 03:19:00.000000000 -0400 95 | @@ -84,7 +84,6 @@ 96 | describe("textutils.serialise", function() 97 | it("serialises basic tables", function() 98 | expect(textutils.serialise({ 1, 2, 3, a = 1, b = {} })) 99 | - :eq("{\n 1,\n 2,\n 3,\n a = 1,\n b = {},\n}") 100 | 101 | expect(textutils.serialise({ 0 / 0, 1 / 0, -1 / 0 })) 102 | :eq("{\n 0/0,\n 1/0,\n -1/0,\n}") 103 | @@ -117,7 +116,6 @@ 104 | 105 | it("can emit in a compact form", function() 106 | expect(textutils.serialise({ 1, 2, 3, a = 1, [false] = {} }, { compact = true })) 107 | - :eq("{1,2,3,a=1,[false]={},}") 108 | end) 109 | 110 | it("ignores metatables", function() 111 | diff -ruN --strip -x .DS_Store projects/core/src/test/resources/test-rom/spec/lua/timeout_spec.lua b/projects/core/src/test/resources/test-rom/spec/lua/timeout_spec.lua 112 | --- a/projects/core/src/test/resources/test-rom/spec/lua/timeout_spec.lua 2021-06-08 23:52:34.000000000 -0400 113 | +++ b/projects/core/src/test/resources/test-rom/spec/lua/timeout_spec.lua 2021-04-28 03:19:00.000000000 -0400 114 | @@ -1,17 +1,7 @@ 115 | describe("The VM terminates long running code :slow", function() 116 | it("in loops", function() 117 | expect.error(function() while true do end end) 118 | - :str_match("^.+:%d+: Too long without yielding$") 119 | + :str_match("Too long without yielding$") 120 | end) 121 | 122 | - describe("in string pattern matching", function() 123 | - local str, pat = ("a"):rep(1e4), ".-.-.-.-b$" 124 | - 125 | - it("string.find", function() 126 | - expect.error(string.find, str, pat):eq("Too long without yielding") 127 | - end) 128 | - it("string.match", function() 129 | - expect.error(string.match, str, pat):eq("Too long without yielding") 130 | - end) 131 | - end) 132 | end) 133 | -------------------------------------------------------------------------------- /src/platform/android.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * platform/android.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file implements functions specific to Android. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #ifdef __ANDROID__ // disable error checking on Windows 12 | extern "C" { 13 | #include 14 | } 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "../platform.hpp" 34 | #include "../runtime.hpp" 35 | #include "../termsupport.hpp" 36 | #include "../util.hpp" 37 | #include "../terminal/SDLTerminal.hpp" 38 | 39 | path_t base_path; 40 | path_t rom_path; 41 | 42 | void setBasePath(path_t path) { 43 | base_path = path; 44 | } 45 | 46 | void setROMPath(path_t path) { 47 | rom_path = path; 48 | } 49 | 50 | path_t getBasePath() { 51 | if (base_path.empty()) { 52 | if (SDL_AndroidGetExternalStorageState() & (SDL_ANDROID_EXTERNAL_STORAGE_READ | SDL_ANDROID_EXTERNAL_STORAGE_WRITE)) 53 | base_path = path_t(SDL_AndroidGetExternalStoragePath()); 54 | else base_path = path_t(SDL_AndroidGetInternalStoragePath()); 55 | } 56 | return base_path; 57 | } 58 | 59 | path_t getROMPath() { 60 | if (rom_path.empty()) { 61 | rom_path = path_t(SDL_AndroidGetInternalStoragePath()).parent_path() / "cache"; 62 | } 63 | return rom_path; 64 | } 65 | path_t getPlugInPath() { 66 | if (rom_path.empty()) { 67 | rom_path = path_t(SDL_AndroidGetInternalStoragePath()).parent_path() / "cache"; 68 | } 69 | return rom_path / "plugins"; 70 | } 71 | 72 | path_t getMCSavePath() { 73 | return ""; 74 | } 75 | 76 | void setThreadName(std::thread &t, const std::string& name) { 77 | pthread_setname_np(t.native_handle(), name.c_str()); 78 | } 79 | 80 | void updateNow(const std::string& tag_name, const Poco::JSON::Object::Ptr root) {} 81 | 82 | void migrateOldData() {} 83 | 84 | void copyImage(SDL_Surface* surf, SDL_Window* win) { 85 | fprintf(stderr, "Warning: Android does not support taking screenshots to the clipboard.\n"); 86 | } 87 | 88 | static std::vector certificateStore; 89 | 90 | void setupCrashHandler() { 91 | DIR *d = opendir("/system/etc/security/cacerts_google"); 92 | if (d) { 93 | struct dirent *p; 94 | while ((p=readdir(d))) { 95 | if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue; 96 | try {certificateStore.push_back(Poco::Crypto::X509Certificate("/system/etc/security/cacerts_google/" + std::string(p->d_name)));} 97 | catch (...) {} 98 | } 99 | closedir(d); 100 | } 101 | d = opendir("/system/etc/security/cacerts"); 102 | if (d) { 103 | struct dirent *p; 104 | while ((p=readdir(d))) { 105 | if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue; 106 | try {certificateStore.push_back(Poco::Crypto::X509Certificate("/system/etc/security/cacerts/" + std::string(p->d_name)));} 107 | catch (...) {} 108 | } 109 | closedir(d); 110 | } 111 | // TODO: add user certs 112 | } 113 | 114 | void setFloating(SDL_Window* win, bool state) {} 115 | 116 | void platformExit() {} 117 | 118 | void addSystemCertificates(Poco::Net::Context::Ptr context) { 119 | for (Poco::Crypto::X509Certificate& cert : certificateStore) context->addCertificateAuthority(cert); 120 | } 121 | 122 | void unblockInput() {} 123 | 124 | void mobileResetModifiers() { 125 | JNIEnv * env = (JNIEnv*)SDL_AndroidGetJNIEnv(); 126 | jobject activity = (jobject)SDL_AndroidGetActivity(); 127 | jclass activity_class = env->GetObjectClass(activity); 128 | jmethodID resetModifiers = env->GetMethodID(activity_class, "resetModifiers", "()V"); 129 | env->CallVoidMethod(activity, resetModifiers); 130 | } 131 | 132 | #ifdef __INTELLISENSE__ 133 | #region Mobile API 134 | #endif 135 | 136 | std::string mobile_keyboard_open(lua_State *L, void* ud) { 137 | SDLTerminal * sdlterm = (SDLTerminal*)get_comp(L)->term; 138 | if (sdlterm == NULL || (sdlterm->charHeight*sdlterm->dpiScale) == 0) return ""; 139 | int size = ((int)(ptrdiff_t)ud - 4*sdlterm->charScale*sdlterm->dpiScale) / (sdlterm->charHeight*sdlterm->dpiScale); 140 | if (size >= sdlterm->height) return "_CCPC_mobile_keyboard_close"; 141 | lua_pushinteger(L, size); 142 | return "_CCPC_mobile_keyboard_open"; 143 | } 144 | 145 | extern "C" { 146 | JNIEXPORT void JNICALL Java_cc_craftospc_CraftOSPC_MainActivity_sendKeyboardUpdate(JNIEnv *env, jclass klass, int size) { 147 | LockGuard lock(computers); 148 | if (!computers->empty()) queueEvent(computers->front(), mobile_keyboard_open, (void*)(ptrdiff_t)size); 149 | } 150 | 151 | JNIEXPORT void JNICALL Java_cc_craftospc_CraftOSPC_MainActivity_sendCloseEvent(JNIEnv *env, jclass klass) { 152 | if (renderTargets.size() < 2) return; 153 | SDL_Event e; 154 | e.type = SDL_WINDOWEVENT; 155 | e.window.timestamp = time(0); 156 | e.window.windowID = SDL_GetWindowID(((SDLTerminal*)computers->front()->term)->win); 157 | e.window.event = SDL_WINDOWEVENT_CLOSE; 158 | e.window.data1 = 0; 159 | e.window.data2 = 0; 160 | SDL_PushEvent(&e); 161 | } 162 | } 163 | 164 | static int mobile_openKeyboard(lua_State *L) { 165 | if (lua_isnone(L, 1) || lua_toboolean(L, 1)) SDL_StartTextInput(); 166 | else SDL_StopTextInput(); 167 | return 0; 168 | } 169 | 170 | static int mobile_isKeyboardOpen(lua_State *L) { 171 | lua_pushboolean(L, SDL_IsTextInputActive()); 172 | return 1; 173 | } 174 | 175 | static luaL_Reg mobile_reg[] = { 176 | {"openKeyboard", mobile_openKeyboard}, 177 | {"isKeyboardOpen", mobile_isKeyboardOpen}, 178 | {NULL, NULL} 179 | }; 180 | 181 | static luaL_Reg android_reg[] = { 182 | {NULL, NULL} 183 | }; 184 | 185 | int mobile_luaopen(lua_State *L) { 186 | luaL_register(L, "mobile", mobile_reg); 187 | /*lua_pushstring(L, "android"); 188 | lua_newtable(L); 189 | for (luaL_Reg* r = android_reg; r->name && r->func; r++) { 190 | lua_pushstring(L, r->name); 191 | lua_pushcfunction(L, r->func); 192 | lua_settable(L, -3); 193 | } 194 | lua_settable(L, -3);*/ 195 | return 1; 196 | } 197 | 198 | #ifdef __INTELLISENSE__ 199 | #endregion 200 | #endif 201 | 202 | #endif // __INTELLISENSE__ 203 | -------------------------------------------------------------------------------- /src/apis/periphemu.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * apis/periphemu.cpp 3 | * CraftOS-PC 2 4 | * 5 | * This file implements the methods for the periphemu API. 6 | * 7 | * This code is licensed under the MIT license. 8 | * Copyright (c) 2019-2024 JackMacWindows. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "../peripheral/chest.hpp" 15 | #include "../peripheral/computer.hpp" 16 | #include "../peripheral/debugger.hpp" 17 | #include "../peripheral/debug_adapter.hpp" 18 | #include "../peripheral/drive.hpp" 19 | #include "../peripheral/energy.hpp" 20 | #include "../peripheral/modem.hpp" 21 | #include "../peripheral/monitor.hpp" 22 | #include "../peripheral/printer.hpp" 23 | #include "../peripheral/speaker.hpp" 24 | #include "../peripheral/tank.hpp" 25 | #include "../runtime.hpp" 26 | #include "../util.hpp" 27 | 28 | static std::unordered_map initializers = { 29 | {"monitor", peripheral_init_fn(monitor::init)}, 30 | {"computer", peripheral_init_fn(computer::init)}, 31 | {"debugger", peripheral_init_fn(debugger::_init)}, 32 | {"debug_adapter", peripheral_init_fn(debug_adapter::_init)}, 33 | {"printer", peripheral_init_fn(printer::init)}, 34 | {"modem", peripheral_init_fn(modem::init)}, 35 | {"drive", peripheral_init_fn(drive::init)}, 36 | {"chest", peripheral_init_fn(chest::init)}, 37 | {"minecraft:chest", peripheral_init_fn(chest::init)}, 38 | {"energy", peripheral_init_fn(energy::init)}, 39 | {"tank", peripheral_init_fn(tank::init)}, 40 | #ifndef NO_MIXER 41 | {"speaker", peripheral_init_fn(speaker::init)} 42 | #endif 43 | }; 44 | 45 | void registerPeripheral(const std::string& name, const peripheral_init_fn& initializer) { 46 | initializers[name] = initializer; 47 | } 48 | 49 | void clearPeripherals() { 50 | initializers.clear(); 51 | } 52 | 53 | static std::string peripheral_attach(lua_State *L, void* arg) { 54 | std::string * side = (std::string*)arg; 55 | lua_pushstring(L, side->c_str()); 56 | delete side; 57 | return "peripheral"; 58 | } 59 | 60 | static std::string peripheral_detach(lua_State *L, void* arg) { 61 | std::string * side = (std::string*)arg; 62 | lua_pushstring(L, side->c_str()); 63 | delete side; 64 | return "peripheral_detach"; 65 | } 66 | 67 | peripheral* attachPeripheral(Computer * computer, const std::string& side, const std::string& type, std::string * errorReturn, const char * format, ...) { 68 | if (config.serverMode && type == "speaker") { 69 | if (errorReturn != NULL) *errorReturn = "No peripheral named speaker"; 70 | return NULL; 71 | } 72 | { 73 | std::lock_guard lock(computer->peripherals_mutex); 74 | if (computer->peripherals.find(side) != computer->peripherals.end()) { 75 | if (errorReturn != NULL) *errorReturn = "Peripheral already attached on side " + side; 76 | return NULL; 77 | } 78 | } 79 | lua_State *L; 80 | int idx = -1; 81 | va_list arg; 82 | va_start(arg, format); 83 | if (*format == 'L') { 84 | L = va_arg(arg, lua_State*); 85 | } else { 86 | L = lua_newthread(computer->L); 87 | idx = lua_gettop(computer->L); 88 | lua_pushstring(L, side.c_str()); 89 | lua_pushstring(L, type.c_str()); 90 | while (*format) { 91 | switch (*format) { 92 | case 'i': lua_pushinteger(L, va_arg(arg, lua_Integer)); break; 93 | case 'n': lua_pushnumber(L, va_arg(arg, lua_Number)); break; 94 | case 's': lua_pushstring(L, va_arg(arg, const char *)); break; 95 | case 'b': lua_pushboolean(L, va_arg(arg, int)); break; 96 | case 'N': lua_pushnil(L); va_arg(arg, void*); break; 97 | default: throw std::invalid_argument(std::string("Invalid format specifier ") + *format); 98 | } 99 | } 100 | } 101 | peripheral * p; 102 | if (initializers.find(type) != initializers.end()) p = initializers[type](L, side.c_str()); 103 | else { 104 | //fprintf(stderr, "not found: %s\n", type.c_str()); 105 | if (errorReturn != NULL) *errorReturn = "No peripheral named " + type; 106 | return NULL; 107 | } 108 | computer->peripherals_mutex.lock(); 109 | try { computer->peripherals[side] = p; } catch (...) {} 110 | computer->peripherals_mutex.unlock(); 111 | if (idx != -1) { 112 | if (lua_gettop(computer->L) == idx) lua_pop(computer->L, 1); 113 | else lua_remove(computer->L, idx); 114 | } 115 | std::string * sidearg = new std::string(side); 116 | queueEvent(computer, peripheral_attach, sidearg); 117 | va_end(arg); 118 | return p; 119 | } 120 | 121 | bool detachPeripheral(Computer * computer, const std::string& side) { 122 | peripheral * p; 123 | { 124 | std::lock_guard lock(computer->peripherals_mutex); 125 | if (computer->peripherals.find(side) == computer->peripherals.end()) return false; 126 | if (std::string(computer->peripherals[side]->getMethods().name) == "drive") 127 | computer->peripherals[side]->call(computer->L, "ejectDisk"); 128 | else if (std::string(computer->peripherals[side]->getMethods().name) == "debugger") 129 | computer->peripherals[side]->call(NULL, "deinit"); 130 | p = computer->peripherals[side]; 131 | computer->peripherals.erase(side); 132 | } 133 | queueTask([ ](void* p)->void*{((peripheral*)p)->getDestructor()((peripheral*)p); return NULL;}, p); 134 | std::string * sidearg = new std::string(side); 135 | queueEvent(computer, peripheral_detach, sidearg); 136 | return true; 137 | } 138 | 139 | static int periphemu_create(lua_State* L) { 140 | lastCFunction = __func__; 141 | if (!lua_isstring(L, 1) && !lua_isnumber(L, 1)) return luaL_error(L, "bad argument #1 (expected string or number, got %s)", lua_typename(L, lua_type(L, 1))); 142 | Computer * computer = get_comp(L); 143 | const std::string type = luaL_checkstring(L, 2); 144 | std::string side = lua_isnumber(L, 1) ? type + "_" + std::to_string(lua_tointeger(L, 1)) : lua_tostring(L, 1); 145 | if (std::all_of(side.begin(), side.end(), ::isdigit)) side = type + "_" + side; 146 | peripheral * p; 147 | std::string err; 148 | try { 149 | p = attachPeripheral(computer, side, type, &err, "L", L); 150 | } catch (std::exception &e) { 151 | return luaL_error(L, "Error while creating peripheral: %s", e.what()); 152 | } 153 | if (p == NULL) { 154 | lua_pushboolean(L, false); 155 | lua_pushstring(L, err.c_str()); 156 | return 2; 157 | } 158 | lua_pushboolean(L, true); 159 | return 1; 160 | } 161 | 162 | static int periphemu_remove(lua_State* L) { 163 | lastCFunction = __func__; 164 | Computer * computer = get_comp(L); 165 | const std::string side = luaL_checkstring(L, 1); 166 | lua_pushboolean(L, detachPeripheral(computer, side)); 167 | return 1; 168 | } 169 | 170 | static int periphemu_names(lua_State *L) { 171 | lastCFunction = __func__; 172 | lua_createtable(L, initializers.size() + 1, 0); 173 | int i = 1; 174 | for (const auto& entry : initializers) { 175 | lua_pushinteger(L, i++); 176 | lua_pushstring(L, entry.first.c_str()); 177 | lua_settable(L, -3); 178 | } 179 | return 1; 180 | } 181 | 182 | static luaL_Reg periphemu_reg[] = { 183 | {"create", periphemu_create}, 184 | {"remove", periphemu_remove}, 185 | {"names", periphemu_names}, 186 | {NULL, NULL} 187 | }; 188 | 189 | library_t periphemu_lib = { "periphemu", periphemu_reg, nullptr, nullptr }; 190 | --------------------------------------------------------------------------------