kitgit

tirbofish/dropbear · diff

534cf03 · tk

Merge pull request #49 from 4tkbytes/kotlin

Unverified

diff --git a/.github/workflows/swift_doc.yaml b/.github/workflows/swift_doc.yaml
deleted file mode 100644
index b071763..0000000
--- a/.github/workflows/swift_doc.yaml
+++ /dev/null
@@ -1,166 +0,0 @@
-name: Generate Swift Documentation
-
-on:
-  push:
-    branches: [ main ]
-    paths:
-      - '**/*.swift'
-      - '.github/workflows/swift-docs.yaml'
-  pull_request:
-    branches: [ main ]
-    paths:
-      - '**/*.swift'
-  workflow_dispatch:
-
-permissions:
-  contents: read
-  pages: write
-  id-token: write
-
-concurrency:
-  group: "pages"
-  cancel-in-progress: false
-
-jobs:
-  generate-docs:
-    runs-on: ubuntu-latest
-    
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v4
-      with:
-        submodules: recursive
-    
-    - name: Setup Swift
-      uses: swift-actions/setup-swift@v2
-    
-    - name: Install Swift-DocC Plugin
-      run: |
-        # Install Swift-DocC plugin for documentation generation
-        swift package plugin --allow-writing-to-directory docs \
-          generate-documentation --target dropbear --disable-indexing \
-          --transform-for-static-hosting --hosting-base-path dropbear \
-          --output-directory docs || true
-        
-        # Alternative: Use swift-doc if DocC doesn't work
-        if [ ! -d "docs" ] || [ -z "$(ls -A docs)" ]; then
-          echo "DocC failed, trying swift-doc..."
-          
-          # Install swift-doc
-          git clone https://github.com/SwiftDocOrg/swift-doc.git
-          cd swift-doc
-          swift build -c release
-          sudo cp .build/release/swift-doc /usr/local/bin/
-          cd ..
-          
-          # Generate documentation with swift-doc
-          mkdir -p docs
-          find . -name "*.swift" -not -path "./swift-doc/*" | head -20 | while read file; do
-            echo "Processing: $file"
-            swift-doc generate "$file" --module-name "$(basename $(dirname $file))" --output docs/ --format html || true
-          done
-        fi
-    
-    - name: Create index.html if missing
-      run: |
-        if [ ! -f "docs/index.html" ]; then
-          cat > docs/index.html << 'EOF'
-        <!DOCTYPE html>
-        <html lang="en">
-        <head>
-            <meta charset="UTF-8">
-            <meta name="viewport" content="width=device-width, initial-scale=1.0">
-            <title>Dropbear Swift Documentation</title>
-            <style>
-                body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; margin: 40px; }
-                h1 { color: #333; }
-                .module { margin: 20px 0; padding: 20px; border: 1px solid #ddd; border-radius: 8px; }
-                a { color: #007AFF; text-decoration: none; }
-                a:hover { text-decoration: underline; }
-            </style>
-        </head>
-        <body>
-            <h1>🐨 Dropbear Swift Documentation</h1>
-            <p>Documentation for Swift scripting in the Dropbear game engine.</p>
-            
-            <div class="module">
-                <h2>Available Documentation</h2>
-                <p>Swift documentation files will be listed here once generated.</p>
-            </div>
-            
-            <div class="module">
-                <h3>About Dropbear</h3>
-                <p>Dropbear is a game engine made in Rust and scripted with Swift. Visit the main repository for more information.</p>
-                <a href="https://github.com/4tkbytes/dropbear">GitHub Repository</a>
-            </div>
-        </body>
-        </html>
-        EOF
-        fi
-        
-        # List generated files
-        echo "Generated documentation files:"
-        find docs -name "*.html" -type f || echo "No HTML files found"
-    
-    - name: Setup Pages
-      if: github.ref == 'refs/heads/main'
-      uses: actions/configure-pages@v4
-      
-    - name: Upload artifact
-      if: github.ref == 'refs/heads/main'
-      uses: actions/upload-pages-artifact@v3
-      with:
-        path: ./docs
-        
-    - name: Deploy to GitHub Pages
-      if: github.ref == 'refs/heads/main'
-      id: deployment
-      uses: actions/deploy-pages@v4
-
-  # Fallback job for manual Swift file documentation
-  backup-docs:
-    runs-on: ubuntu-latest
-    if: failure()
-    
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v4
-      
-    - name: Find and document Swift files
-      run: |
-        mkdir -p docs
-        
-        # Create a simple documentation index
-        cat > docs/index.html << 'EOF'
-        <!DOCTYPE html>
-        <html>
-        <head>
-            <title>Dropbear Swift Code</title>
-            <style>
-                body { font-family: monospace; margin: 40px; }
-                .file { margin: 20px 0; padding: 20px; background: #f5f5f5; }
-                pre { background: #fff; padding: 15px; overflow-x: auto; }
-            </style>
-        </head>
-        <body>
-            <h1>Dropbear Swift Code Documentation</h1>
-        EOF
-        
-        # Find all Swift files and add them to documentation
-        find . -name "*.swift" -not -path "./.git/*" | while read file; do
-          echo "<div class='file'>" >> docs/index.html
-          echo "<h2>$(basename $file)</h2>" >> docs/index.html
-          echo "<p>Path: $file</p>" >> docs/index.html
-          echo "<pre>" >> docs/index.html
-          head -50 "$file" | sed 's/</\&lt;/g; s/>/\&gt;/g' >> docs/index.html
-          echo "</pre>" >> docs/index.html
-          echo "</div>" >> docs/index.html
-        done
-        
-        echo "</body></html>" >> docs/index.html
-        
-    - name: Upload backup docs
-      if: github.ref == 'refs/heads/main'
-      uses: actions/upload-pages-artifact@v3
-      with:
-        path: ./docs
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index ec61ccd..1f67367 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,31 +1,54 @@
-# Generated by Cargo
-# will have compiled files and executables
-debug
-target
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
 
-# These are backup files generated by rustfmt
-**/*.rs.bk
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
 
-# MSVC Windows builds of rustc generate these, which store debugging information
-*.pdb
+### Kotlin ###
+.kotlin
 
-# Generated by cargo mutants
-# Contains mutation testing data
-**/mutants.out*/
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
 
-# RustRover
-#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
-#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
-#  and can be added to the global gitignore or merged into this file.  For a more nuclear
-#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
-.idea/
-Cargo.lock
-dropbear-engine/src/resources/textures/Autism.png
-.vscode
-docs
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
 
-dropbear_future-queue/test.log
+debug/
+target/
+
+Cargo.lock
+**/*.rs.bk
+*.pdb
 
-*/.build/*
-.build/*
-*.resolved
\ No newline at end of file
+.idea/
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..7bc07ec
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Environment-dependent path to Maven home directory
+/mavenHomeManager.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.run/build.run.xml b/.run/build.run.xml
new file mode 100644
index 0000000..87e14e1
--- /dev/null
+++ b/.run/build.run.xml
@@ -0,0 +1,24 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="build" type="GradleRunConfiguration" factoryName="Gradle">
+    <ExternalSystemSettings>
+      <option name="executionName" />
+      <option name="externalProjectPath" value="$PROJECT_DIR$" />
+      <option name="externalSystemIdString" value="GRADLE" />
+      <option name="scriptParameters" value="" />
+      <option name="taskDescriptions">
+        <list />
+      </option>
+      <option name="taskNames">
+        <list>
+          <option value="build" />
+        </list>
+      </option>
+      <option name="vmOptions" />
+    </ExternalSystemSettings>
+    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
+    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
+    <DebugAllEnabled>false</DebugAllEnabled>
+    <RunAsTest>false</RunAsTest>
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/.run/generateJniHeaders.run.xml b/.run/generateJniHeaders.run.xml
new file mode 100644
index 0000000..acc9512
--- /dev/null
+++ b/.run/generateJniHeaders.run.xml
@@ -0,0 +1,24 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="generateJniHeaders" type="GradleRunConfiguration" factoryName="Gradle">
+    <ExternalSystemSettings>
+      <option name="executionName" />
+      <option name="externalProjectPath" value="$PROJECT_DIR$" />
+      <option name="externalSystemIdString" value="GRADLE" />
+      <option name="scriptParameters" value="" />
+      <option name="taskDescriptions">
+        <list />
+      </option>
+      <option name="taskNames">
+        <list>
+          <option value="generateJniHeaders" />
+        </list>
+      </option>
+      <option name="vmOptions" />
+    </ExternalSystemSettings>
+    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
+    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
+    <DebugAllEnabled>false</DebugAllEnabled>
+    <RunAsTest>false</RunAsTest>
+    <method v="2" />
+  </configuration>
+</component>
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 089e30f..3a523da 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -60,7 +60,7 @@ backtrace = "0.3"
 gltf = "1"
 os_info = "3.12"
 rustc_version_runtime = "0.3"
-libloading = "0.8"
+jni = { version = "0.21", features = ["invocation"] }
 
 [workspace.dependencies.image]
 version = "0.25"
diff --git a/Package.swift b/Package.swift
deleted file mode 100644
index ae52bc3..0000000
--- a/Package.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-// swift-tools-version: 6.2
-
-import PackageDescription
-import CompilerPluginSupport
-
-let package = Package(
-    name: "dropbear",
-    products: [
-        .library(
-            name: "dropbear",
-            type: .dynamic,
-            targets: ["dropbear"],
-        ),
-    ],
-    dependencies: [
-        .package(url: "https://github.com/swiftlang/swift-syntax", from: "602.0.0")
-    ],
-    targets: [
-        .macro(
-            name: "dropbear_macro",
-            dependencies: [
-                .product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
-                .product(name: "SwiftCompilerPlugin", package: "swift-syntax")
-            ]
-        ),
-        .target(
-            name: "dropbear",
-            dependencies: ["dropbear_macro"]
-        ),
-        .testTarget(
-            name: "dropbearTests",
-            dependencies: ["dropbear"]
-        ),
-    ]
-)
diff --git a/README.md b/README.md
index cbf7fe5..90af976 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # dropbear
 
-dropbear is a game engine used to create games, made in Rust and scripted with the Swift Language.
+dropbear is a game engine used to create games, made in Rust and scripted with the Kotlin Language.
 
 It's name is a double entendre, with it being the nickname of koalas but also fits in nicely with the theme of rust utilising memory management with "drops".
 
@@ -26,7 +26,7 @@ With Unix systems (macOS not tested), you will have to download a couple depende
 
 <!-- If you have a macOS system, please create a PR and add your own implementation. I know you need to use brew, but I don't know what dependencies to install.  -->
 
-#### Dependencies
+### Dependencies
 
 ```bash
 # ubuntu
@@ -37,26 +37,22 @@ sudo pacman -Syu base-devel systemd pkgconf openssl clang cmake meson assimp
 
 ```
 
-#### Swift
-
-If you are using the Eucalyptus editor and are planning on scripting, you will have to download the Swift language. Don't fret, the Swift language is available to all major operating systems _(not only macOS to contrary belief)_, and can be easily downloaded here: [https://www.swift.org/install](https://www.swift.org/install)
-
-After downloading the requirements, you are free to build it using cargo.
-
-#### Engine Build
+### Engine Build
 
 ```bash
 git clone git@github.com:4tkbytes/dropbear
 cd dropbear
 
-# ensure submodules are checked-out
-git submodule init
-git submodule update
-
-# this will build all the projects in the workspace, including eucalyptus and redback.
+# this will build all the projects in the workspace
 cargo build
 ```
 
+[//]: # (# ensure submodules are checked-out)
+
+[//]: # (git submodule init)
+
+[//]: # (git submodule update)
+
 ### Prebuilt
 
 If you do not want to build it locally, you are able to download the latest action build (if no releases have been made).
@@ -65,7 +61,10 @@ If you do not want to build it locally, you are able to download the latest acti
 
 ## Usage
 
-Despite the dropbear-engine (and other components) being made in Rust, the editor has chosen the scripting language of choice to be `Swift`.
+Despite the dropbear-engine (and other components) being made in Rust, the editor has chosen the scripting language of choice to be `Kotlin`
+because of previous experience and that Kotlin is more multiplatform than Swift. 
+
+Java is possible (as the JVM runs the script), however it is not officially supported and Kotlin is recommended. . 
 
 API documentation and articles are available at (todo)
 
diff --git a/Sources/dropbear/dropbear.swift b/Sources/dropbear/dropbear.swift
deleted file mode 100644
index eb8426c..0000000
--- a/Sources/dropbear/dropbear.swift
+++ /dev/null
@@ -1,136 +0,0 @@
-/// A class that all scripts inherit, which define simple functions which are ran
-/// in the dropbear rust engine. 
-public protocol RunnableScript: AnyObject {
-    /// The init function. This is the constructor for the class to initialise. 
-    /// 
-    /// You can setup whatever variables and states, however it is recommended to use
-    /// the `onLoad` function instead as that is actually ran during the runtime
-    /// compared to `init`, which is initialised when the library is loaded. 
-    init()
-
-    /// Loads the content/variables/states into the entity/scene. 
-    /// 
-    /// This is ran only once and is loaded during runtime. 
-    func onLoad()
-
-    /// Updates the engine context with the content inside the function
-    /// 
-    /// This is ran every frame and is loaded during the runtime. 
-    /// - Parameter dt: Deltatime/the time it takes for the previous frame to render as a `Float`
-    func onUpdate(dt: Float)
-
-    /// Run the script (called by engine)
-    func run()
-}
-
-/// Registry for managing script classes and their metadata. 
-@MainActor
-public class ScriptRegistry {
-    private static var scriptClasses: [String: RunnableScript.Type] = [:]
-    private static var entityScripts: [String: String] = [:]  // entity -> fileName mapping
-    
-    /// Register a script class with its file name
-    public static func registerScript<T: RunnableScript>(_ type: T.Type, fileName: String) {
-        scriptClasses[fileName] = type
-    }
-    
-    /// Register a script for a specific entity
-    public static func registerEntityScript(_ fileName: String, entity: String) {
-        entityScripts[entity] = fileName
-    }
-    
-    /// Get script class by file name
-    public static func getScript(fileName: String) -> RunnableScript.Type? {
-        return scriptClasses[fileName]
-    }
-    
-    /// Get script file name for specific entity
-    public static func getScriptForEntity(_ entity: String) -> String? {
-        return entityScripts[entity]
-    }
-    
-    /// Create script instance by file name
-    public static func createScript(fileName: String) -> RunnableScript? {
-        return getScript(fileName: fileName)?.init()
-    }
-    
-    /// Create script instance for entity (checks entity-specific first, then falls back to fileName)
-    public static func createScriptForEntity(_ entity: String, fallbackFileName: String) -> RunnableScript? {
-        if let specificFileName = getScriptForEntity(entity) {
-            return createScript(fileName: specificFileName)
-        }
-        return createScript(fileName: fallbackFileName)
-    }
-}
-
-/// Base implementation of RunnableScript with default run() behavior
-open class BaseScript: RunnableScript {
-    public required init() {}
-    
-    open func onLoad() {
-        // Override in subclasses
-    }
-    
-    open func onUpdate(dt: Float) {
-        // Override in subclasses
-    }
-    
-    public func run() {
-        onLoad()
-        // Engine will call onUpdate in its loop
-    }
-}
-
-
-// todo
-public func getCurrentScene() -> Scene! {
-    if true /* check if script is attached to scene */ {
-        Scene()
-    } else {
-        nil
-    }
-}
-
-// todo
-public func getAttachedEntity() -> Entity {
-    Entity()
-}
-
-// todo
-public func getScene() -> Scene {
-    Scene()
-}
-
-/// A macro for a class of a script that can be used with any entity (when added).  
-/// 
-/// Let's say that you have an entity of a player. You want to get movement for
-/// that Player. The Eucalyptus Editor only allows for one `Swift` file per entity. 
-/// To combat that, there is a macro called `@ScriptEntry`, which allows for that class
-/// to be ran (in no particular order) in tandem with the Player.
-/// 
-/// In the case that you want a script to be locked to **only** a specific entity,
-/// you can use the `@Script(name: /*Entity Label*/)` to lock that class to run only on
-/// that entity, improving production as you won't have to constantly rewrite scripts. 
-@attached(member, names: named(init))
-public macro ScriptEntry() = #externalMacro(module: "dropbear_macro", type: "ScriptEntryMacro")
-
-/// A macro for a class of a script that can be used by a **specific** entity. 
-/// 
-/// Imagine you have an enemy. You have a class that deals with movement, a class that deals with 
-/// health, but you want an Enemy specific class for its own system. This macro helps with dealing with 
-/// such an issue, allowing you to attach this script to other entities as well. 
-/// 
-/// This macro also gives the class a higher priority compared to the `@ScriptEntry` classes, allowing this
-/// script to run earlier than any ScriptEntry derived classes. 
-/// 
-/// FYI: This macro does not update if you change the label. If the label in editor is 
-/// different than what is provided, this class will not run for that entity. 
-/// 
-/// # Parameters
-/// - name: A String to the label of the entity set by you.  
-@attached(member, names: named(init))
-public macro Script(entity: String) = #externalMacro(module: "dropbear_macro", type: "ScriptMacro")
-
-public func getInput() -> Input {
-    
-}
\ No newline at end of file
diff --git a/Sources/dropbear/entity.swift b/Sources/dropbear/entity.swift
deleted file mode 100644
index dadaa9f..0000000
--- a/Sources/dropbear/entity.swift
+++ /dev/null
@@ -1,7 +0,0 @@
-public class Entity {
-    let id: Int
-
-    init() {
-        self.id = 0
-    }
-}
\ No newline at end of file
diff --git a/Sources/dropbear/example.swift b/Sources/dropbear/example.swift
deleted file mode 100644
index 69a8887..0000000
--- a/Sources/dropbear/example.swift
+++ /dev/null
@@ -1,14 +0,0 @@
-// example testing module, do not use in production
-
-@ScriptEntry
-class Player: BaseScript {
-    override func onLoad() {
-        let input = dropbear.getInput();
-
-
-    }
-
-    override func onUpdate(dt: Float) {
-        print("Player is running: \(dt)")
-    }
-}
\ No newline at end of file
diff --git a/Sources/dropbear/ffi.swift b/Sources/dropbear/ffi.swift
deleted file mode 100644
index 5458bd7..0000000
--- a/Sources/dropbear/ffi.swift
+++ /dev/null
@@ -1,26 +0,0 @@
-private class InternalFFIData {
-    static let shared = InternalFFIData()
-    let input_data: RawInputData
-
-    private init() {
-
-    }
-}
-
-struct FFIInputState: Codable {
-    var keysPressed: [UInt32]
-    var mousePosition: (Float, Float)
-    var mouseDelta: (Float, Float)
-    var mouseButtons: [UInt32]
-
-    init(keysPressed: [UInt32] = [],
-        mousePosition: (Float, Float) = (0, 0),
-        mouseDelta: (Float, Float) = (0, 0),
-        mouseButtons: [UInt32] = [])
-    {
-        self.keysPressed = keysPressed
-        self.mousePosition = mousePosition
-        self.mouseDelta = mouseDelta
-        self.mouseButtons = mouseButtons
-    }
-}
\ No newline at end of file
diff --git a/Sources/dropbear/input.swift b/Sources/dropbear/input.swift
deleted file mode 100644
index 11b8b2a..0000000
--- a/Sources/dropbear/input.swift
+++ /dev/null
@@ -1,16 +0,0 @@
-public class Input {
-    
-
-    public func isKeyPressed(_ key: Key) -> Bool {
-        // add checking here
-        return false;
-    }
-}
-
-public enum Key {
-    case W
-    case A
-    case S
-    case D
-    // add more here
-}
\ No newline at end of file
diff --git a/Sources/dropbear/math.swift b/Sources/dropbear/math.swift
deleted file mode 100644
index 53aa8df..0000000
--- a/Sources/dropbear/math.swift
+++ /dev/null
@@ -1,31 +0,0 @@
-/// A class containing an `x`, `y` and `z` value of type `T`.
-///
-/// The type `T` must conform as
-/// an `ExpressibleByIntegerLiteral` (no strings or other stuff).
-class Vector3<T>
-where T: ExpressibleByIntegerLiteral {
-    /// The first value in a `Vector3`
-    var x: T
-    /// The second value in a `Vector3`
-    var y: T
-    /// The third value in a `Vector3`
-    var z: T
-
-    /// Initialises a new Vector3
-    ///
-    /// # Parameters:
-    ///   - x: A value of type T
-    ///   - y: A value of type T
-    ///   - z: A value of type T
-    init(x: T, y: T, z: T) {
-        self.x = x
-        self.y = y
-        self.z = z
-    }
-
-    /// Creates a new Vector3 of type `T` with all values set to zero.
-    /// - Returns: Vector3 of type `T`
-    static func zero() -> Vector3<T> {
-        return Vector3(x: 0, y: 0, z: 0)
-    }
-}
\ No newline at end of file
diff --git a/Sources/dropbear/scene.swift b/Sources/dropbear/scene.swift
deleted file mode 100644
index 643d93d..0000000
--- a/Sources/dropbear/scene.swift
+++ /dev/null
@@ -1,7 +0,0 @@
-public class Scene {
-    // create more info on this scene
-
-    public func getEntity(_ label: String) -> Entity! {
-        return nil
-    }
-}
\ No newline at end of file
diff --git a/Sources/dropbear_macro/macros.swift b/Sources/dropbear_macro/macros.swift
deleted file mode 100644
index 627d952..0000000
--- a/Sources/dropbear_macro/macros.swift
+++ /dev/null
@@ -1,130 +0,0 @@
-import SwiftCompilerPlugin
-import SwiftSyntax
-import SwiftSyntaxBuilder
-import SwiftSyntaxMacros
-import Foundation
-
-/// Already defined in `dropbear/@ScriptEntry`.
-/// A macro for a class of a script that can be used with any entity (when added).  
-/// 
-/// Let's say that you have an entity of a player. You want to get movement for
-/// that Player. The Eucalyptus Editor only allows for one `Swift` file per entity. 
-/// To combat that, there is a macro called `@ScriptEntry`, which allows for that class
-/// to be ran (in no particular order) in tandem with the Player.
-/// 
-/// In the case that you want a script to be locked to **only** a specific entity,
-/// you can use the `@Script(name: /*Entity Label*/)` to lock that class to run only on
-/// that entity, improving production as you won't have to constantly rewrite scripts. 
-public struct ScriptEntryMacro: MemberMacro {
-    public static func expansion(
-        of node: AttributeSyntax,
-        providingMembersOf declaration: some DeclGroupSyntax,
-        conformingTo protocols: [TypeSyntax],
-        in context: some MacroExpansionContext
-    ) throws -> [DeclSyntax] {
-        guard declaration.is(ClassDeclSyntax.self) else {
-            throw MacroError.notAClass
-        }
-        
-        let fileName = extractFileName(from: context, node: node)
-        
-        return [
-            """
-            required init() {
-                super.init()
-                Task { @MainActor in
-                    ScriptRegistry.registerScript(Self.self, fileName: \(literal: fileName))
-                }
-            }
-            """
-        ]
-    }
-}
-
-/// Already defined in `dropbear/@Script(name: /*Entity Label*/)`.
-/// A macro for a class of a script that can be used by a **specific** entity. 
-/// 
-/// Imagine you have an enemy. You have a class that deals with movement, a class that deals with 
-/// health, but you want an Enemy specific class for its own system. This macro helps with dealing with 
-/// such an issue, allowing you to attach this script to other entities as well. 
-/// 
-/// This macro also gives the class a higher priority compared to the `@ScriptEntry` classes, allowing this
-/// script to run earlier than any ScriptEntry derived classes. 
-/// 
-/// FYI: This macro does not update if you change the label. If the label in editor is 
-/// different than what is provided, this class will not run for that entity. 
-/// 
-/// # Parameters
-/// - name: A String to the label of the entity set by you.  
-public struct ScriptMacro: MemberMacro {
-    public static func expansion(
-        of node: AttributeSyntax,
-        providingMembersOf declaration: some DeclGroupSyntax,
-        conformingTo protocols: [TypeSyntax],
-        in context: some MacroExpansionContext
-    ) throws -> [DeclSyntax] {
-        guard declaration.is(ClassDeclSyntax.self) else {
-            throw MacroError.notAClass
-        }
-        
-        guard case let .argumentList(args) = node.arguments,
-            let firstArg = args.first,
-            let labeledExpr = firstArg.expression.as(StringLiteralExprSyntax.self) else {
-            throw MacroError.invalidEntityArgument
-        }
-        
-        let entityName = labeledExpr.segments.compactMap { segment in
-            if case let .stringSegment(content) = segment {
-                return content.content.text
-            }
-            return nil
-        }.joined()
-        
-        let fileName = extractFileName(from: context, node: node)
-        
-        return [
-            """
-            required init() {
-                super.init()
-                Task { @MainActor in
-                    ScriptRegistry.registerScript(Self.self, fileName: \(literal: fileName))
-                    ScriptRegistry.registerEntityScript(\(literal: fileName), entity: \(literal: entityName))
-                }
-            }
-            """
-        ]
-    }
-}
-
-private func extractFileName(from context: some MacroExpansionContext, node: AttributeSyntax) -> String {
-    if let location = context.location(of: node, at: .afterLeadingTrivia, filePathMode: .fileID) {
-        let fileString = location.file.description
-        let components = fileString.components(separatedBy: "/")
-        if let lastComponent = components.last {
-            return lastComponent.replacingOccurrences(of: ".swift", with: "")
-        }
-    }
-    return "unknown"
-}
-
-enum MacroError: Error, CustomStringConvertible {
-    case notAClass
-    case invalidEntityArgument
-    
-    var description: String {
-        switch self {
-        case .notAClass:
-            return "Script macros can only be applied to classes"
-        case .invalidEntityArgument:
-            return "Script macro requires a valid entity string argument"
-        }
-    }
-}
-
-@main
-struct MacroPlugin: CompilerPlugin {
-    let providingMacros: [Macro.Type] = [
-        ScriptEntryMacro.self,
-        ScriptMacro.self
-    ]
-}
\ No newline at end of file
diff --git a/Tests/dropbearTests/dropbearTests.swift b/Tests/dropbearTests/dropbearTests.swift
deleted file mode 100644
index cb7386b..0000000
--- a/Tests/dropbearTests/dropbearTests.swift
+++ /dev/null
@@ -1,6 +0,0 @@
-import Testing
-@testable import dropbear
-
-@Test func example() async throws {
-    // Write your test here and use APIs like `#expect(...)` to check expected conditions.
-}
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..cbfc7df
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,44 @@
+plugins {
+    kotlin("jvm") version "2.1.21"
+}
+
+group = "com.dropbear"
+version = "1.0-SNAPSHOT"
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    testImplementation(kotlin("test"))
+    implementation(kotlin("test"))
+}
+
+tasks.test {
+    useJUnitPlatform()
+}
+kotlin {
+    jvmToolchain(21)
+}
+
+sourceSets {
+    main {
+        java.srcDirs("src/main/kotlin", "src/main/java")
+    }
+}
+
+tasks.register<JavaCompile>("generateJniHeaders") {
+    val outputDir = layout.buildDirectory.dir("generated/jni-headers")
+    options.headerOutputDirectory.set(outputDir.get().asFile)
+
+    classpath = files(
+        tasks.named("compileKotlin"),
+        tasks.named("compileJava")
+    )
+
+    source = fileTree("src/main/java") {
+        include("**/*.java")
+    }
+
+    dependsOn("compileJava", "compileKotlin")
+}
diff --git a/eucalyptus-core/Cargo.toml b/eucalyptus-core/Cargo.toml
index ee6dc6b..c2122bd 100644
--- a/eucalyptus-core/Cargo.toml
+++ b/eucalyptus-core/Cargo.toml
@@ -25,8 +25,8 @@ serde.workspace = true
 winit.workspace = true
 tokio.workspace = true
 rayon.workspace = true
-libloading.workspace = true
-crossbeam-channel.workspace = true
+jni.workspace = true
+lazy_static = "1.5.0"
 
 [features]
 editor = []
diff --git a/eucalyptus-core/src/input.rs b/eucalyptus-core/src/input.rs
index 8da40f1..fcda409 100644
--- a/eucalyptus-core/src/input.rs
+++ b/eucalyptus-core/src/input.rs
@@ -2,7 +2,6 @@ use std::{
     collections::{HashMap, HashSet},
     time::{Duration, Instant},
 };
-use serde::{Deserialize, Serialize};
 use winit::{event::MouseButton, keyboard::KeyCode};
 
 #[derive(Clone)]
diff --git a/eucalyptus-core/src/lib.rs b/eucalyptus-core/src/lib.rs
index cf62d19..87e2061 100644
--- a/eucalyptus-core/src/lib.rs
+++ b/eucalyptus-core/src/lib.rs
@@ -5,5 +5,4 @@ pub mod logging;
 pub mod scripting;
 pub mod states;
 pub mod utils;
-pub mod spawn;
-mod swift;
+pub mod spawn;
\ No newline at end of file
diff --git a/eucalyptus-core/src/scripting.rs b/eucalyptus-core/src/scripting.rs
index 3349f31..d3907e5 100644
--- a/eucalyptus-core/src/scripting.rs
+++ b/eucalyptus-core/src/scripting.rs
@@ -1,40 +1,15 @@
+mod java;
+
 use crate::input::InputState;
 use crate::states::{EntityNode, PROJECT, SOURCE, ScriptComponent, Value};
 use dropbear_engine::entity::{AdoptedEntity, Transform};
 use hecs::{Entity, World};
 use std::path::PathBuf;
 use std::{collections::HashMap, fs};
-use std::env::current_exe;
-use glam::{Quat, Vec3};
-use libloading::{library_filename, Library};
-use once_cell::sync::Lazy;
-use parking_lot::Mutex;
-use serde::{Deserialize, Serialize};
+use crate::scripting::java::JavaContext;
 
 pub const TEMPLATE_SCRIPT: &str = include_str!("../../resources/scripting/swift/sample.swift");
 
-#[derive(Debug, Clone)]
-pub enum ScriptCommand {
-    /// Allows you to set a Transform value to a specific entity.
-    ///
-    /// # API Usage
-    /// ```swift
-    /// let player = dropbear.getAttachedEntity() // fetches entity information
-    ///
-    /// player.translate(Vector3(x: 1.0))
-    /// player.setPosition(player.getTransform().position + Vector3(x: 1.0))
-    /// player.rotateX(angle: 95.radians)
-    /// player.scale(Vector3(x: 1.4, y: 1.5, z: 0.8))
-    /// player.setTransform(Transform(position: Vector3.zero(), rotation: Quaternion.identity(), scale: Vector3.zero())
-    /// ```
-    SetTransform {
-        entity: Entity,
-        position: Option<Vec3>,
-        rotation: Option<Quat>,
-        scale: Option<Vec3>,
-    }
-}
-
 #[derive(Clone)]
 pub struct DropbearScriptingAPIContext {
     pub current_entity: Option<Entity>,
@@ -43,8 +18,6 @@ pub struct DropbearScriptingAPIContext {
     pub current_input: Option<InputState>,
     pub persistent_data: HashMap<String, Value>,
     pub frame_data: HashMap<String, Value>,
-
-    command_sender: Option<crossbeam_channel::Sender<ScriptCommand>>,
 }
 
 impl Default for DropbearScriptingAPIContext {
@@ -61,7 +34,6 @@ impl DropbearScriptingAPIContext {
             current_input: None,
             persistent_data: HashMap::new(),
             frame_data: HashMap::new(),
-            command_sender: None,
         }
     }
 
@@ -111,20 +83,19 @@ impl DropbearScriptingAPIContext {
 
 pub struct ScriptManager {
     script_context: DropbearScriptingAPIContext,
-    library: Library,
+    java: JavaContext,
 }
 
 impl ScriptManager {
     pub fn new() -> anyhow::Result<Self> {
-        let lib_path: PathBuf = Self::look_for_potential_library()?;
-        let library = unsafe { Library::new(lib_path.clone())? };
+        // let lib_path: PathBuf = Self::look_for_potential_library()?;
+        // let library = unsafe { Library::new(lib_path.clone())? };
 
         let result = Self {
-            library,
+            java: JavaContext::new()?,
             script_context: DropbearScriptingAPIContext::new(),
         };
 
-        log::info!("Loaded {} from {}", library_filename("dropbear").display(), lib_path.display());
         log::debug!("Initialised ScriptManager");
         Ok(result)
     }
@@ -151,14 +122,6 @@ impl ScriptManager {
         Ok(())
     }
 
-    fn process_commands(&mut self) {
-
-    }
-
-    fn populate(&self) {
-
-    }
-
     pub fn update_entity_script(
         &mut self,
         entity_id: hecs::Entity,
@@ -171,40 +134,6 @@ impl ScriptManager {
 
         Ok(())
     }
-
-    fn look_for_potential_library() -> anyhow::Result<PathBuf> {
-        // look for project path if editor feature is available
-        let root_path = {
-            #[cfg(feature = "editor")]
-            {
-                let _guard = PROJECT.read();
-                _guard.project_path.clone()
-            }
-
-            #[cfg(not(feature = "editor"))]
-            {
-                std::env::current_exe()?.parent().unwrap().to_path_buf()
-            }
-        };
-
-        let lib_file_name = library_filename("dropbear");
-
-        let potential_paths = vec![
-            root_path.join(lib_file_name.clone()), // when packaged for shipping
-            // cant think of any other spots
-            // root_path.parent().unwrap().parent().unwrap().join("").join(lib_file_name.clone()), // during production of editor/engine
-            current_exe()?.parent().unwrap().parent().unwrap().parent().unwrap().to_path_buf().join(".build").join("debug").join(lib_file_name.clone()),
-
-        ];
-
-        for path in potential_paths {
-            if path.exists() {
-                return Ok(path);
-            }
-        }
-
-        anyhow::bail!("Unable to locate path for the dropbear dynamic library");
-    }
 }
 
 pub fn move_script_to_src(script_path: &PathBuf) -> anyhow::Result<PathBuf> {
diff --git a/eucalyptus-core/src/scripting/java.rs b/eucalyptus-core/src/scripting/java.rs
new file mode 100644
index 0000000..0b18927
--- /dev/null
+++ b/eucalyptus-core/src/scripting/java.rs
@@ -0,0 +1,20 @@
+use jni::{InitArgsBuilder, JNIVersion, JavaVM};
+
+/// A dropbear wrapper for Java Virtual Machine (JVM) based functions
+pub(crate) struct JavaContext {
+    jvm: JavaVM,
+}
+
+impl JavaContext {
+    pub fn new() -> anyhow::Result<Self> {
+        let jvm_args = InitArgsBuilder::new()
+            .version(JNIVersion::V8)
+            .build()?;
+
+        let jvm = JavaVM::new(jvm_args)?;
+        log::info!("Initialised JVM");
+        Ok(Self {
+            jvm
+        })
+    }
+}
\ No newline at end of file
diff --git a/eucalyptus-core/src/swift/ffi.h b/eucalyptus-core/src/swift/ffi.h
deleted file mode 100644
index 7291afb..0000000
--- a/eucalyptus-core/src/swift/ffi.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// This is the header for the Swift FFI functions. This is just to be used as reference.
-//
-// I suppose you could use this for any other language other than Swift...
-
-// ----------------------------------
-// An expandable vector of uint32_t
-typedef struct {
-    const uint32_t* ptr;
-    size_t len;
-    size_t cap;
-} CArrayU32;
-
-// Creates a new empty CArrayU32
-CArrayU32 new_array_u32(void);
-
-/// Frees memory of a CArrayU32
-void free_array_u32(CArrayU32 arr);
-
-// ----------------------------------
-
-// A expandable vector of uint8_t
-typedef struct {
-    const uint8_t* ptr;
-    size_t len;
-    size_t cap;
-} CArrayU8;
-
-// Creates a new empty CArrayU8
-CArrayU8 new_array_u8(void);
-
-/// Frees memory of a CArrayU8
-void free_array_u8(CArrayU8 arr);
-
-// ----------------------------------
\ No newline at end of file
diff --git a/eucalyptus-core/src/swift/ffi.rs b/eucalyptus-core/src/swift/ffi.rs
deleted file mode 100644
index c6bb9d5..0000000
--- a/eucalyptus-core/src/swift/ffi.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-//! A module for dealing with the FFI between Swift dropbear-engine scripting API and 
-//! the game engine in Rust.
-
-use serde::{Deserialize, Serialize};
-use winit::event::MouseButton;
-use crate::input::InputState;
-use winit::platform::scancode::PhysicalKeyExtScancode;
-
-#[derive(Serialize, Deserialize)]
-pub struct FFIInputState {
-    pub keys_pressed: Vec<u32>,
-    pub mouse_position: [f32; 2],
-    pub mouse_delta: [f32; 2],
-    pub mouse_buttons: Vec<u32>,
-}
-
-impl From<InputState> for FFIInputState {
-    fn from(value: InputState) -> Self {
-
-        let keys_pressed = value.pressed_keys.iter().map(|k| {
-            k.to_scancode().unwrap()
-        }).collect::<Vec<_>>();
-
-        let mut mouse_buttons = Vec::new();
-        for m in value.mouse_button {
-            let r = match m {
-                MouseButton::Left => 1u32,
-                MouseButton::Right => 2u32,
-                MouseButton::Middle => 3u32,
-                _ => 0u32
-            };
-            mouse_buttons.push(r);
-        }
-
-        Self {
-            keys_pressed,
-            mouse_position: [value.mouse_pos.0 as f32, value.mouse_pos.1 as f32],
-            mouse_delta: [value.mouse_delta.unwrap_or_default().0 as f32, value.mouse_delta.unwrap_or_default().1 as f32],
-            mouse_buttons,
-        }
-    }
-}
-
-mod vec {
-    use std::mem::ManuallyDrop;
-
-    /// An expandable array of [`u32`], similar to a [`Vec`] but for C API's
-    #[repr(C)]
-    pub struct CArrayU32 {
-        /// Pointer/Reference to the contents
-        pub ptr: *const u32,
-        /// Number of elements in vector
-        pub len: usize,
-        /// Maximum capacity of elements in vector
-        pub cap: usize,
-    }
-
-    /// An expandable array of [`u8`], similar to a [`Vec`] but for C API's
-    #[repr(C)]
-    pub struct CArrayU8 {
-        /// Pointer/Reference to the contents
-        pub ptr: *const u8,
-        /// Number of elements in vector
-        pub len: usize,
-        /// Maximum capacity of elements in vector
-        pub cap: usize,
-    }
-
-    /// Creates a new [`CArrayU32`] from a vector (used for Rust)
-    pub fn vec_into_carray_u32(v: Vec<u32>) -> CArrayU32 {
-        let mut v = ManuallyDrop::new(v);
-        CArrayU32 { ptr: v.as_mut_ptr(), len: v.len(), cap: v.capacity() }
-    }
-
-    /// Created a nw [`CArrayU8`] from a vector (used for Rust)
-    pub fn vec_into_carray_u8(v: Vec<u8>) -> CArrayU8 {
-        let mut v = ManuallyDrop::new(v);
-        CArrayU8 { ptr: v.as_mut_ptr(), len: v.len(), cap: v.capacity() }
-    }
-
-    /// Create a new empty CArrayU32
-    #[unsafe(no_mangle)]
-    pub extern "C" fn new_array_u32() -> CArrayU32 {
-        vec_into_carray_u32(Vec::new())
-    }
-
-    /// Create a new empty CArrayU8
-    #[unsafe(no_mangle)]
-    pub extern "C" fn new_array_u8() -> CArrayU8 {
-        vec_into_carray_u8(Vec::new())
-    }
-
-    /// Frees the vector from memory.
-    ///
-    /// Since Rust is unable to manage an FFI from outside the language, this function is required.
-    ///
-    /// This function is exposed under the name of `free_array_u32`
-    #[unsafe(no_mangle)]
-    pub extern "C" fn free_array_u32(arr: CArrayU32) {
-        unsafe { Vec::from_raw_parts(arr.ptr as *mut u32, arr.len, arr.cap); }
-    }
-
-    /// Frees the vector from memory.
-    ///
-    /// Since Rust is unable to manage an FFI from outside the language, this function is required.
-    ///
-    /// This function is exposed under the name of `free_array_u8`
-    #[unsafe(no_mangle)]
-    pub extern "C" fn free_array_u8(arr: CArrayU8) {
-        unsafe { Vec::from_raw_parts(arr.ptr as *mut u8, arr.len, arr.cap); }
-    }
-}
\ No newline at end of file
diff --git a/eucalyptus-core/src/swift/mod.rs b/eucalyptus-core/src/swift/mod.rs
deleted file mode 100644
index 28f2da1..0000000
--- a/eucalyptus-core/src/swift/mod.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub mod ffi;
\ No newline at end of file
diff --git a/eucalyptus-editor/src/main.rs b/eucalyptus-editor/src/main.rs
index 88687c1..e2d5bf2 100644
--- a/eucalyptus-editor/src/main.rs
+++ b/eucalyptus-editor/src/main.rs
@@ -11,7 +11,6 @@ mod signal;
 use clap::{Arg, Command};
 use dropbear_engine::{scene, WindowConfiguration};
 use std::{fs, path::PathBuf, rc::Rc};
-use std::panic::catch_unwind;
 use std::sync::Arc;
 use parking_lot::RwLock;
 use dropbear_engine::future::FutureQueue;
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..7fc6f1f
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1 @@
+kotlin.code.style=official
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..249e583
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..3adfd49
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Sep 30 12:55:55 AEST 2025
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..1b6c787
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..2f9554a
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,4 @@
+plugins {
+    id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
+}
+rootProject.name = "com.dropbear"
\ No newline at end of file
diff --git a/src/main/kotlin/com/dropbear/DropbearEngine.kt b/src/main/kotlin/com/dropbear/DropbearEngine.kt
new file mode 100644
index 0000000..44722c3
--- /dev/null
+++ b/src/main/kotlin/com/dropbear/DropbearEngine.kt
@@ -0,0 +1,28 @@
+package com.dropbear
+
+import com.dropbear.ffi.NativeEngine
+
+class DropbearEngine {
+    var nativeEngine: NativeEngine? = null
+
+    // figure out how to create a new class
+    /**
+     * Fetches the currently active entity the script is attached to.
+     *
+     * If there is no entity this script is attached to, it will return
+     * a `null` in the form of a [Result]
+     */
+    fun getActiveEntity(): Result<EntityRef> {
+        return Result.failure(Exception("Function not implemented"))
+    }
+
+    /**
+     * Fetches an entity based on its label in the editor.
+     *
+     * If there is no entity under that label, it will return a
+     * `null` in the form of a [Result]
+     */
+    fun getEntity(label: String): EntityRef? {
+        return null
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/dropbear/EntityRef.kt b/src/main/kotlin/com/dropbear/EntityRef.kt
new file mode 100644
index 0000000..7bccd3c
--- /dev/null
+++ b/src/main/kotlin/com/dropbear/EntityRef.kt
@@ -0,0 +1,27 @@
+package com.dropbear
+
+import com.dropbear.math.Vector3D
+
+/**
+ * A class to hold a reference to an entity.
+ *
+ * The dropbear engine interface is made in Rust, which uses a
+ * borrow checker paradigm, which heavily utilises immutability
+ * unless explicitly provided with the `mut` keyword.
+ *
+ * Because of this, the primary source of the World (place to store
+ * entities) is stored in Rust, and passing an EntityRef (which contains
+ * an ID) follows Rust's ideologies of passing references instead of the entire entity,
+ * which provides immutability.
+ *
+ * To edit any values part of the entity, take a look at the functions provided
+ * by [EntityRef], which will require a reference to [DropbearEngine] to push the commands.
+ */
+class EntityRef {
+    var label: String = ""
+
+    /**
+     * Sets the position of the entity by a Vector
+     */
+    fun setPosition(position: Vector3D, engine: DropbearEngine) {}
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/dropbear/Example.kt b/src/main/kotlin/com/dropbear/Example.kt
new file mode 100644
index 0000000..e1ef013
--- /dev/null
+++ b/src/main/kotlin/com/dropbear/Example.kt
@@ -0,0 +1,12 @@
+package com.dropbear
+
+class Example(override var engine: DropbearEngine) : RunnableScript {
+    override fun load() {
+        val entity = engine.getActiveEntity()
+
+    }
+
+    override fun update() {
+        TODO("Not yet implemented")
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/dropbear/RunnableScript.kt b/src/main/kotlin/com/dropbear/RunnableScript.kt
new file mode 100644
index 0000000..d7cb338
--- /dev/null
+++ b/src/main/kotlin/com/dropbear/RunnableScript.kt
@@ -0,0 +1,21 @@
+package com.dropbear
+
+/**
+ * The basic interface that all classes implement for the class to be run.
+ */
+interface RunnableScript {
+    var engine: DropbearEngine
+    /**
+     * A function that is run once during the lifetime of the entity.
+     *
+     * It can be used to set initial properties such as health and more.
+     *
+     * ALl classes that implement RunnableScript need to implement the load function.
+     */
+    fun load()
+
+    /**
+     * A function that is run every frame during the lifetime of the entity.
+     */
+    fun update()
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/dropbear/ffi/NativeEngine.java b/src/main/kotlin/com/dropbear/ffi/NativeEngine.java
new file mode 100644
index 0000000..fbb19da
--- /dev/null
+++ b/src/main/kotlin/com/dropbear/ffi/NativeEngine.java
@@ -0,0 +1,17 @@
+package com.dropbear.ffi;
+
+import com.dropbear.math.Transform;
+
+/**
+ * A class for dealing with native functions that is required by the Kotlin scripting
+ * and the Rust game engine.
+ */
+public class NativeEngine {
+    /**
+     * Fetches the transform of the entity by its label in the editor
+     * @param label The label of the entity
+     * @return The {@link Transform} component if the entity exists, null if not.
+     */
+    public native Transform getTransformOfEntity(String label);
+    public native String getLabelOfAttachedEntity();
+}
diff --git a/src/main/kotlin/com/dropbear/math/Quaternion.kt b/src/main/kotlin/com/dropbear/math/Quaternion.kt
new file mode 100644
index 0000000..97779eb
--- /dev/null
+++ b/src/main/kotlin/com/dropbear/math/Quaternion.kt
@@ -0,0 +1,11 @@
+package com.dropbear.math
+
+typealias QuaternionD = Quaternion<Double>
+
+class Quaternion<T: Number>(var x: T, var y: T, var z: T, var w: T) {
+    companion object {
+        fun identity(): Quaternion<Double> {
+            return Quaternion(0.0, 0.0, 0.0, 1.0)
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/dropbear/math/Transform.kt b/src/main/kotlin/com/dropbear/math/Transform.kt
new file mode 100644
index 0000000..bfa039f
--- /dev/null
+++ b/src/main/kotlin/com/dropbear/math/Transform.kt
@@ -0,0 +1,9 @@
+package com.dropbear.math
+
+/**
+ * A class that keeps all the values of a Transform, which consists of a
+ * position ([Vector3D]), rotation([QuaternionD]) and a scale([Vector3D]).
+ */
+class Transform(var position: Vector3D, var rotation: QuaternionD, var scale: Vector3D) {
+
+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/dropbear/math/Vector3.kt b/src/main/kotlin/com/dropbear/math/Vector3.kt
new file mode 100644
index 0000000..822dd23
--- /dev/null
+++ b/src/main/kotlin/com/dropbear/math/Vector3.kt
@@ -0,0 +1,29 @@
+package com.dropbear.math
+
+/**
+ * A class for holding a vector of `3` values of the same type.
+ */
+class Vector3<T: Number>(var x: T, var y: T, var z: T) {
+    companion object {
+        /**
+         * Creates a new [com.dropbear.math.Vector3] of type `T` with one value.
+         */
+        fun <T: Number> uniform(value: T): Vector3<T> {
+            return Vector3(value, value, value)
+        }
+
+        /**
+         * Creates a [com.dropbear.math.Vector3] of type [Double] filled with only zeroes
+         */
+        fun zero(): Vector3<Double> {
+            return Vector3(0.0, 0.0, 0.0)
+        }
+    }
+
+    fun asDoubleVector(): Vector3<Double> {
+        return Vector3(this.x.toDouble(), this.y.toDouble(), this.z.toDouble())
+    }
+
+}
+
+typealias Vector3D = Vector3<Double>
\ No newline at end of file